mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-04-06 17:31:09 +08:00
Compare commits
72 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b549e4c060 | ||
|
6b8c51ca6b | ||
|
91ceb36f42 | ||
|
9624352b2a | ||
|
ae5378c7d1 | ||
|
deb6927d50 | ||
|
46c20d5297 | ||
|
72c3725a10 | ||
|
bb80e4f928 | ||
|
4e5898bdd3 | ||
|
c15bbd1f77 | ||
|
34dcf0a601 | ||
|
c4fd308f73 | ||
|
acdb41af74 | ||
|
c515592598 | ||
|
7c29703b3c | ||
|
b0f9bc9dc1 | ||
|
e36c119082 | ||
|
095ed3ef76 | ||
|
834a97c47e | ||
|
1289d43eea | ||
|
a49f6494a8 | ||
|
690430ac68 | ||
|
717aed5517 | ||
|
73f4fe2cf7 | ||
|
b22df10302 | ||
|
8b81761068 | ||
|
b7d2dba3e8 | ||
|
41faa51738 | ||
|
a21c60c589 | ||
|
824000b509 | ||
|
43297d58cd | ||
|
e93ba41176 | ||
|
65862e5747 | ||
|
458a8bf7f2 | ||
|
c51a420178 | ||
|
dd4fbd9bfd | ||
|
71b0bd77ea | ||
|
2c0d8f11b3 | ||
|
e7dd11e6d9 | ||
|
03d640c569 | ||
|
7953f13112 | ||
|
d207e00cae | ||
|
b9b3a1afa3 | ||
|
65bf903fef | ||
|
a26bf1c17f | ||
|
d766cd1678 | ||
|
368efc7c82 | ||
|
774ef189e1 | ||
|
0b99ed8787 | ||
|
5e51f95352 | ||
|
75d5c59a9a | ||
|
8f0d81c5a3 | ||
|
213fd7fa40 | ||
|
4c63e657ae | ||
|
fac8535b21 | ||
|
545b052dee | ||
|
09bbf45c5f | ||
|
a11651b3ab | ||
|
f438cbb816 | ||
|
2a5bd7cf07 | ||
|
ee80888e71 | ||
|
97f6382e8a | ||
|
89bea015b1 | ||
|
f1d3243f0f | ||
|
3039c281d2 | ||
|
54838b65b1 | ||
|
8208382ccd | ||
|
fc66268c64 | ||
|
22d3497ce3 | ||
|
7488b73f9b | ||
|
3d88d91bf0 |
.github/workflows
README.mdcss
index.htmljs
lang
cz.jsonde.jsonen.jsones.jsonfr.jsonit.jsonja.jsonko.jsonnl.jsonpl.jsonpt.jsonru.jsonsv.jsonuk.jsonvi.jsonzh.jsonzh_tw.json
lib
package-lock.jsonpackage.json
6
.github/workflows/webapp.yml
vendored
6
.github/workflows/webapp.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v3
|
||||
- name: Build
|
||||
@ -29,10 +29,10 @@ jobs:
|
||||
npm install
|
||||
npm run prepublish
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
# Upload entire repository
|
||||
path: '.'
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v2
|
||||
uses: actions/deploy-pages@v4
|
||||
|
@ -1,9 +1,9 @@
|
||||
# Blockbench
|
||||
|
||||
Blockbench is a free, modern model editor for low-poly and boxy models with pixel art textures.
|
||||
Blockbench is a free and open source model editor for low-poly models with pixel art textures.
|
||||
Models can be exported into standardized formats, to be shared, rendered, 3D-printed, or used in game engines. There are also multiple dedicated formats for Minecraft Java and Bedrock Edition with format-specific features.
|
||||
|
||||
Blockbench features a modern and intuitive UI, plugin support and innovative features. It is the industry standard for creating custom 3D models for the Minecraft Marketplace.
|
||||
Blockbench features a modern and beginner friendly interface, but also offers lots of customization and advanced features for experienced 3D artists. Plugins can extend the functionality of the program even further.
|
||||
|
||||
Website and download: [blockbench.net](https://www.blockbench.net)
|
||||
|
||||
@ -27,6 +27,8 @@ To launch Blockbench from source, you can clone the repository, navigate to the
|
||||
* Install [NodeJS](https://nodejs.org/en/).
|
||||
* Then install all dependencies via
|
||||
`npm install`
|
||||
* Bundle the code via
|
||||
`npm run bundle`
|
||||
* Finally, launch Blockbench using
|
||||
`npm run dev`
|
||||
|
||||
@ -34,7 +36,7 @@ To launch Blockbench from source, you can clone the repository, navigate to the
|
||||
|
||||
## Plugins
|
||||
|
||||
Blockbench supports Javascript-based plugins. Learn more about creating plugins on [https://www.blockbench.net/wiki/api/index](https://www.blockbench.net/wiki/api/index).
|
||||
Blockbench supports Javascript-based plugins. Learn more about creating plugins on [https://www.blockbench.net/wiki/docs/plugin](https://www.blockbench.net/wiki/docs/plugin).
|
||||
|
||||
|
||||
|
||||
|
@ -1218,6 +1218,10 @@
|
||||
}
|
||||
|
||||
/* Placeholders */
|
||||
ul#placeholder_buttons {
|
||||
max-height: 32%;
|
||||
overflow: auto;
|
||||
}
|
||||
#placeholder_buttons li {
|
||||
padding: 0px 8px;
|
||||
height: 30px;
|
||||
|
@ -98,6 +98,7 @@
|
||||
<script src="js/util/array_util.js"></script>
|
||||
<script src="js/util/event_system.js"></script>
|
||||
<script src="js/util/property.js"></script>
|
||||
<script src="js/util/json.js"></script>
|
||||
<script src="js/interface/menu.js"></script>
|
||||
<script src="js/interface/actions.js"></script>
|
||||
<script src="js/interface/themes.js"></script>
|
||||
|
@ -133,8 +133,8 @@ class Animation extends AnimationItem {
|
||||
copy.animators = {}
|
||||
for (var uuid in this.animators) {
|
||||
let ba = this.animators[uuid]
|
||||
var kfs = ba.keyframes
|
||||
if ((kfs && kfs.length) || ba.rotation_global) {
|
||||
let kfs = ba.keyframes
|
||||
if ((kfs && kfs.length) || ba.rotation_global || !save) {
|
||||
let ba_copy = copy.animators[uuid] = {
|
||||
name: ba.name,
|
||||
type: ba.type,
|
||||
@ -160,10 +160,10 @@ class Animation extends AnimationItem {
|
||||
|
||||
if (this.length) ani_tag.animation_length = Math.roundTo(this.length, 4);
|
||||
if (this.override) ani_tag.override_previous_animation = true;
|
||||
if (this.anim_time_update) ani_tag.anim_time_update = this.anim_time_update.replace(/\n/g, '');
|
||||
if (this.blend_weight) ani_tag.blend_weight = this.blend_weight.replace(/\n/g, '');
|
||||
if (this.start_delay) ani_tag.start_delay = this.start_delay.replace(/\n/g, '');
|
||||
if (this.loop_delay && ani_tag.loop) ani_tag.loop_delay = this.loop_delay.replace(/\n/g, '');
|
||||
if (this.anim_time_update) ani_tag.anim_time_update = exportMolang(this.anim_time_update);
|
||||
if (this.blend_weight) ani_tag.blend_weight = exportMolang(this.blend_weight);
|
||||
if (this.start_delay) ani_tag.start_delay = exportMolang(this.start_delay);
|
||||
if (this.loop_delay && ani_tag.loop) ani_tag.loop_delay = exportMolang(this.loop_delay);
|
||||
ani_tag.bones = {};
|
||||
|
||||
for (var uuid in this.animators) {
|
||||
@ -1769,12 +1769,17 @@ BARS.defineActions(function() {
|
||||
temp_animators[target_uuid] = new animator.constructor(target_uuid, animation);
|
||||
copyAnimator(temp_animators[target_uuid], target_animator);
|
||||
}
|
||||
|
||||
let tempsave_current_animator = !temp_animators[animator.uuid];
|
||||
if (tempsave_current_animator) {
|
||||
temp_animators[animator.uuid] = new animator.constructor(animator.uuid, animation);
|
||||
copyAnimator(temp_animators[animator.uuid], animator);
|
||||
}
|
||||
|
||||
copyAnimator(target_animator, temp_animators[animator.uuid] ?? animator);
|
||||
|
||||
// Reset animator
|
||||
if (!temp_animators[animator.uuid]) {
|
||||
temp_animators[animator.uuid] = new animator.constructor(animator.uuid, animation);
|
||||
copyAnimator(temp_animators[animator.uuid], animator);
|
||||
if (tempsave_current_animator) {
|
||||
resetAnimator(animator)
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ class AnimationControllerState {
|
||||
target: '',
|
||||
condition: ''
|
||||
};
|
||||
this.transitions.push(transition);
|
||||
if (typeof a == 'object' && typeof a.uuid == 'string' && a.uuid.length == 36) {
|
||||
// Internal
|
||||
Object.assign(transition, a);
|
||||
@ -90,11 +91,13 @@ class AnimationControllerState {
|
||||
setTimeout(() => {
|
||||
// Delay to after loading controller so that all states can be found
|
||||
let state_match = this.controller.states.find(state => state !== this && state.name == key);
|
||||
if (state_match) transition.target = state_match.uuid;
|
||||
if (state_match) {
|
||||
let updated_transition = this.transitions.find(t => t.uuid == transition.uuid) ?? transitions;
|
||||
updated_transition.target = state_match.uuid;
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
this.transitions.push(transition);
|
||||
})
|
||||
}
|
||||
if (data.particles instanceof Array) {
|
||||
|
@ -1470,8 +1470,8 @@ Interface.definePanels(function() {
|
||||
<ul id="placeholder_buttons">
|
||||
<li v-for="button in buttons" :key="button.id" :class="{placeholder_slider: button.type == 'slider'}" @click="button.type == 'impulse' && changeButtonValue(button, $event)" :buttontype="button.type">
|
||||
<i v-if="button.type == 'impulse'" class="material-icons">play_arrow</i>
|
||||
<input v-if="button.type == 'toggle'" type="checkbox" class="tab_target" :value="button.value == 1" @change="changeButtonValue(button, $event)" :id="'placeholder_button_'+button.id">
|
||||
<numeric-input v-if="button.type == 'slider'" class="dark_bordered tab_target" :step="button.step" :min="button.min" :max="button.max" v-model="button.value" @input="changeButtonValue(button, $event)" />
|
||||
<input v-if="button.type == 'toggle'" type="checkbox" :value="button.value == 1" @change="changeButtonValue(button, $event)" :id="'placeholder_button_'+button.id">
|
||||
<numeric-input v-if="button.type == 'slider'" :step="button.step" :min="button.min" :max="button.max" v-model="button.value" @input="changeButtonValue(button, $event)" />
|
||||
<label :for="'placeholder_button_'+button.id" @mousedown="slideButton(button, $event)" @touchstart="slideButton(button, $event)">{{ button.id }}</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -94,11 +94,8 @@ class Keyframe {
|
||||
data_point = this.data_points[data_point];
|
||||
if (!data_point || !data_point[axis]) {
|
||||
return this.transform ? 0 : '';
|
||||
} else if (!isNaN(data_point[axis])) {
|
||||
let num = parseFloat(data_point[axis]);
|
||||
return isNaN(num) ? 0 : num;
|
||||
} else {
|
||||
return data_point[axis]
|
||||
return exportMolang(data_point[axis])
|
||||
}
|
||||
}
|
||||
calc(axis, data_point = 0) {
|
||||
@ -113,6 +110,7 @@ class Keyframe {
|
||||
}
|
||||
set(axis, value, data_point = 0) {
|
||||
if (data_point) data_point = Math.clamp(data_point, 0, this.data_points.length-1);
|
||||
if (typeof value == 'number') value = Math.roundTo(value, 10).toString();
|
||||
if (this.data_points[data_point]) {
|
||||
if (this.uniform) {
|
||||
this.data_points[data_point].x = value;
|
||||
|
@ -931,7 +931,7 @@ Interface.definePanels(() => {
|
||||
|
||||
let padding = 16;
|
||||
let min_size = 2.4;
|
||||
let unit_size = Math.clamp(max-min, min_size, 1e4);
|
||||
let unit_size = Math.clamp(max-min, min_size, Timeline.graph_editor_limit);
|
||||
this.graph_size = (clientHeight - 2*padding) / unit_size;
|
||||
let blend = Math.clamp(1 - (max-min) / min_size, 0, 1)
|
||||
this.graph_offset = clientHeight - padding + (this.graph_size * (min - unit_size/2 * blend ) );
|
||||
|
@ -310,7 +310,13 @@ Object.assign(Blockbench, {
|
||||
saveAs(blob, file_name)
|
||||
|
||||
} else {
|
||||
var blob = new Blob([options.content], {type: "text/plain;charset=utf-8"});
|
||||
let type = 'text/plain;charset=utf-8';
|
||||
if (file_name.endsWith('json')) {
|
||||
type = 'application/json;charset=utf-8';
|
||||
} else if (file_name.endsWith('bbmodel')) {
|
||||
type = 'model/vnd.blockbench.bbmodel';
|
||||
}
|
||||
var blob = new Blob([options.content], {type});
|
||||
saveAs(blob, file_name, {autoBOM: true})
|
||||
}
|
||||
|
||||
|
@ -1534,17 +1534,21 @@ class Toolbar {
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Builds the toolbar from data
|
||||
* @param {object} data Data used to build the toolbar
|
||||
* @param {boolean} force If true, customization data will be ignored. Used when resetting toolbar
|
||||
*/
|
||||
build(data, force) {
|
||||
var scope = this;
|
||||
//Items
|
||||
this.children.length = 0;
|
||||
var items = data.children
|
||||
if (!force && BARS.stored[scope.id] && typeof BARS.stored[scope.id] === 'object') {
|
||||
items = BARS.stored[scope.id]
|
||||
if (!force && BARS.stored[this.id] && typeof BARS.stored[this.id] === 'object') {
|
||||
items = BARS.stored[this.id];
|
||||
if (data.children) {
|
||||
// Add new actions to existing toolbars
|
||||
// Add new actions (newly added via bb update) to existing toolbars
|
||||
data.children.forEach((key, index) => {
|
||||
if (typeof key == 'string' && key.length > 1 && !items.includes(key) && !Keybinds.stored[key] && BarItems[key]) {
|
||||
if (typeof key == 'string' && key.length > 1 && !items.includes(key) && !Keybinds.stored[key] && BARS.stored._known?.includes(key) == false && BarItems[key]) {
|
||||
// Figure out best index based on item before. Otherwise use index from original array
|
||||
let prev_index = items.indexOf(data.children[index-1]);
|
||||
if (prev_index != -1) index = prev_index+1;
|
||||
@ -1554,7 +1558,7 @@ class Toolbar {
|
||||
}
|
||||
}
|
||||
if (items && items instanceof Array) {
|
||||
var content = $(scope.node).find('div.content')
|
||||
var content = $(this.node).find('div.content')
|
||||
content.children().detach()
|
||||
for (var itemPosition = 0; itemPosition < items.length; itemPosition++) {
|
||||
let item = items[itemPosition];
|
||||
@ -1566,7 +1570,10 @@ class Toolbar {
|
||||
|
||||
continue;
|
||||
}
|
||||
if (typeof item == 'string') item = BarItems[item]
|
||||
if (typeof item == 'string') {
|
||||
BARS.stored._known?.safePush(item);
|
||||
item = BarItems[item];
|
||||
}
|
||||
|
||||
if (item) {
|
||||
item.pushToolbar(this);
|
||||
@ -1581,8 +1588,8 @@ class Toolbar {
|
||||
}
|
||||
}
|
||||
}
|
||||
$(scope.node).toggleClass('no_wrap', this.no_wrap)
|
||||
$(scope.node).toggleClass('vertical', this.vertical)
|
||||
$(this.node).toggleClass('no_wrap', this.no_wrap)
|
||||
$(this.node).toggleClass('vertical', this.vertical)
|
||||
if (data.default_place) {
|
||||
this.toPlace(this.id)
|
||||
}
|
||||
@ -1748,7 +1755,10 @@ class Toolbar {
|
||||
}
|
||||
})
|
||||
BARS.stored[this.id] = arr;
|
||||
if (arr.equals(this.default_children)) {
|
||||
let identical_to_default = this.default_children.length == arr.length && this.default_children.allAre((item, i) => {
|
||||
return arr[i] == item || (typeof arr[i] == 'string' && arr[i].startsWith(item));
|
||||
})
|
||||
if (identical_to_default) {
|
||||
delete BARS.stored[this.id];
|
||||
}
|
||||
// Temporary fix
|
||||
@ -1779,7 +1789,9 @@ Toolbar.prototype.menu = new Menu([
|
||||
])
|
||||
|
||||
const BARS = {
|
||||
stored: {},
|
||||
stored: {
|
||||
_known: []
|
||||
},
|
||||
editing_bar: undefined,
|
||||
action_definers: [],
|
||||
condition: Condition,
|
||||
@ -2145,6 +2157,9 @@ const BARS = {
|
||||
stored = JSON.parse(stored)
|
||||
if (typeof stored === 'object') {
|
||||
BARS.stored = stored;
|
||||
if (!BARS.stored._known) {
|
||||
BARS.stored._known = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2266,9 +2281,6 @@ const BARS = {
|
||||
}
|
||||
})
|
||||
}
|
||||
Blockbench.onUpdateTo('4.4.0-beta.0', () => {
|
||||
delete BARS.stored.brush;
|
||||
})
|
||||
Toolbars.brush = new Toolbar({
|
||||
id: 'brush',
|
||||
no_wrap: true,
|
||||
|
@ -535,6 +535,8 @@ window.MessageBox = class MessageBox extends Dialog {
|
||||
super(options.id, options);
|
||||
this.options = options;
|
||||
if (!options.buttons) this.buttons = ['dialog.ok'];
|
||||
this.cancelIndex = Math.min(this.buttons.length-1, this.cancelIndex);
|
||||
this.confirmIndex = Math.min(this.buttons.length-1, this.confirmIndex);
|
||||
this.callback = callback;
|
||||
}
|
||||
close(button, result, event) {
|
||||
@ -687,6 +689,7 @@ window.ToolConfig = class ToolConfig extends Dialog {
|
||||
}
|
||||
save() {
|
||||
localStorage.setItem(`tool_config.${this.id}`, JSON.stringify(this.options));
|
||||
return this;
|
||||
}
|
||||
changeOptions(options) {
|
||||
for (let key in options) {
|
||||
@ -696,6 +699,7 @@ window.ToolConfig = class ToolConfig extends Dialog {
|
||||
this.form.setValues(options);
|
||||
}
|
||||
this.save();
|
||||
return this;
|
||||
}
|
||||
close(button, event) {
|
||||
this.save();
|
||||
@ -712,6 +716,7 @@ window.ToolConfig = class ToolConfig extends Dialog {
|
||||
this.object.style.top = (anchor_position.top+anchor.offsetHeight) + 'px';
|
||||
this.object.style.left = Math.clamp(anchor_position.left - 30, 0, window.innerWidth-this.object.clientWidth - (this.title ? 0 : 30)) + 'px';
|
||||
}
|
||||
return this;
|
||||
}
|
||||
build() {
|
||||
if (this.object) this.object.remove();
|
||||
|
@ -348,8 +348,9 @@ class InputForm extends EventSystem {
|
||||
linked_ratio_toggle.addEventListener('click', event => {
|
||||
data.linked_ratio = !data.linked_ratio;
|
||||
if (data.linked_ratio) {
|
||||
updateInputs(vector_inputs[0]);
|
||||
scope.updateValues();
|
||||
initial_value = vector_inputs.map(v => v.value);
|
||||
// updateInputs(vector_inputs[0]);
|
||||
// scope.updateValues();
|
||||
}
|
||||
updateState();
|
||||
})
|
||||
|
@ -331,6 +331,7 @@ const MenuBar = {
|
||||
'adjust_curves',
|
||||
new MenuSeparator('filters'),
|
||||
'limit_to_palette',
|
||||
'split_rgb_into_layers',
|
||||
'clear_unused_texture_space',
|
||||
new MenuSeparator('transform'),
|
||||
'flip_texture_x',
|
||||
|
@ -436,7 +436,7 @@ const Settings = {
|
||||
Canvas.updateShading()
|
||||
}});
|
||||
new Setting('antialiasing', {category: 'preview', value: true, requires_restart: true});
|
||||
new Setting('antialiasing_bleed_fix', {category: 'preview', value: true, requires_restart: true});
|
||||
new Setting('antialiasing_bleed_fix', {category: 'preview', value: false, requires_restart: true});
|
||||
new Setting('fov', {category: 'preview', value: 45, type: 'number', min: 1, max: 120, onChange(val) {
|
||||
Preview.all.forEach(preview => preview.setFOV(val));
|
||||
}});
|
||||
@ -490,6 +490,7 @@ const Settings = {
|
||||
Preview.all.forEach(viewport => viewport.controls.zoomSpeed = value / 100 * 1.5)
|
||||
}});
|
||||
new Setting('editor_2d_zoom_speed', {category: 'controls', value: 100, min: 10, max: 1000, type: 'number'});
|
||||
new Setting('gamepad_controls', {category: 'controls', value: false, name: 'Gamepad Controls', description: 'Use a gamepad or 3D mouse to navigate the viewport'});
|
||||
new Setting('double_click_switch_tools',{category: 'controls', value: true});
|
||||
new Setting('canvas_unselect', {category: 'controls', value: false});
|
||||
new Setting('selection_tolerance', {category: 'controls', value: 10, type: 'number', min: 1, max: 50});
|
||||
@ -527,6 +528,7 @@ const Settings = {
|
||||
new Setting('outlines_in_paint_mode', {category: 'paint', value: true});
|
||||
new Setting('move_with_selection_tool', {category: 'paint', value: true});
|
||||
new Setting('pick_color_opacity', {category: 'paint', value: false});
|
||||
new Setting('pick_combined_color', {category: 'paint', value: false});
|
||||
new Setting('paint_through_transparency', {category: 'paint', value: true});
|
||||
new Setting('paint_side_restrict', {category: 'paint', value: true});
|
||||
new Setting('paint_with_stylus_only', {category: 'paint', value: false});
|
||||
@ -626,9 +628,8 @@ const Settings = {
|
||||
new Setting('sketchfab_token', {category: 'export', value: '', type: 'password'});
|
||||
new Setting('credit', {category: 'export', value: 'Made with Blockbench', type: 'text'});
|
||||
|
||||
Blockbench.onUpdateTo('4.7.1', () => {
|
||||
settings.brush_opacity_modifier.set('none');
|
||||
settings.brush_size_modifier.set('none');
|
||||
Blockbench.onUpdateTo('4.12.1', () => {
|
||||
settings.antialiasing_bleed_fix.set(false);
|
||||
})
|
||||
},
|
||||
setupProfiles() {
|
||||
|
@ -573,23 +573,39 @@ ModelLoader.loaders = {};
|
||||
});
|
||||
documentReady.then(() => {
|
||||
|
||||
//Twitter
|
||||
let twitter_ad;
|
||||
if (!settings.classroom_mode.value && Blockbench.startup_count < 20 && Blockbench.startup_count % 5 === 4) {
|
||||
twitter_ad = true;
|
||||
addStartScreenSection('twitter_link', {
|
||||
color: '#1da1f2',
|
||||
//Bluesky
|
||||
let bsky_ad;
|
||||
Blockbench.onUpdateTo('4.12.2', () => {
|
||||
//Bluesky
|
||||
if (!settings.classroom_mode.value) {
|
||||
bsky_ad = true;
|
||||
addStartScreenSection('bluesky_link', {
|
||||
color: 'rgb(32, 139, 254);',
|
||||
text_color: '#ffffff',
|
||||
graphic: {type: 'icon', icon: 'fab.fa-bluesky'},
|
||||
text: [
|
||||
{type: 'h3', text: 'Blockbench on Bluesky'},
|
||||
{text: 'Follow Blockbench on Bluesky for the latest news & cool models from the community! [@blockbench.net](https://bsky.app/profile/blockbench.net)'}
|
||||
],
|
||||
last: true
|
||||
})
|
||||
}
|
||||
})
|
||||
if (!settings.classroom_mode.value && !bsky_ad && Blockbench.startup_count < 20 && Blockbench.startup_count % 5 === 4) {
|
||||
bsky_ad = true;
|
||||
addStartScreenSection('bluesky_link', {
|
||||
color: 'rgb(32, 139, 254);',
|
||||
text_color: '#ffffff',
|
||||
graphic: {type: 'icon', icon: 'fab.fa-twitter'},
|
||||
graphic: {type: 'icon', icon: 'fab.fa-bluesky'},
|
||||
text: [
|
||||
{type: 'h2', text: 'Blockbench on Twitter'},
|
||||
{text: 'Follow Blockbench on Twitter for the latest news as well as cool models from the community! [twitter.com/blockbench](https://twitter.com/blockbench/)'}
|
||||
{type: 'h3', text: 'Blockbench on Bluesky'},
|
||||
{text: 'Follow Blockbench on Bluesky for the latest news & cool models from the community! [@blockbench.net](https://bsky.app/profile/blockbench.net)'}
|
||||
],
|
||||
last: true
|
||||
})
|
||||
}
|
||||
//Discord
|
||||
if (!settings.classroom_mode.value && Blockbench.startup_count < 6 && !twitter_ad) {
|
||||
if (!settings.classroom_mode.value && Blockbench.startup_count < 6 && !bsky_ad) {
|
||||
addStartScreenSection('discord_link', {
|
||||
color: '#5865F2',
|
||||
text_color: '#ffffff',
|
||||
|
@ -263,7 +263,7 @@ var codec = new Codec('project', {
|
||||
if (Animation.all.length) {
|
||||
model.animations = [];
|
||||
Animation.all.forEach(a => {
|
||||
model.animations.push(a.getUndoCopy({bone_names: true, absolute_paths: options.absolute_paths}, true))
|
||||
model.animations.push(a.getUndoCopy({absolute_paths: options.absolute_paths}, true))
|
||||
})
|
||||
}
|
||||
if (AnimationController.all.length) {
|
||||
@ -332,15 +332,11 @@ var codec = new Codec('project', {
|
||||
if (options.raw) {
|
||||
return model;
|
||||
} else if (options.compressed) {
|
||||
var json_string = JSON.stringify(model);
|
||||
var json_string = compileJSON(model, {small: true});
|
||||
var compressed = '<lz>'+LZUTF8.compress(json_string, {outputEncoding: 'StorageBinaryString'});
|
||||
return compressed;
|
||||
} else {
|
||||
if (Settings.get('minify_bbmodel') || options.minify) {
|
||||
return JSON.stringify(model);
|
||||
} else {
|
||||
return compileJSON(model);
|
||||
}
|
||||
return compileJSON(model, {small: Settings.get('minify_bbmodel') || options.minify});
|
||||
}
|
||||
},
|
||||
parse(model, path) {
|
||||
|
@ -96,7 +96,8 @@ window.BedrockEntityManager = class BedrockEntityManager {
|
||||
}
|
||||
}
|
||||
if (valid_textures_list.length == 1) {
|
||||
new Texture({keep_size: true, render_mode}).fromPath(valid_textures_list[0]).add()
|
||||
let texture = new Texture({keep_size: true, render_mode}).fromPath(valid_textures_list[0]).add()
|
||||
if (isApp) loadAdjacentTextureSet(texture);
|
||||
if (render_mode == 'layered') {
|
||||
updateLayeredTextures();
|
||||
}
|
||||
@ -169,14 +170,15 @@ window.BedrockEntityManager = class BedrockEntityManager {
|
||||
cancelIndex: 2,
|
||||
onButton(index) {
|
||||
dialog.hide();
|
||||
let textures_to_import = [];
|
||||
if (index == 1) {
|
||||
valid_textures_list.forEach(path => {
|
||||
new Texture({keep_size: true, render_mode}).fromPath(path).add()
|
||||
})
|
||||
textures_to_import = valid_textures_list;
|
||||
} else if (index == 0) {
|
||||
selected_textures.forEach(path => {
|
||||
new Texture({keep_size: true, render_mode}).fromPath(path).add()
|
||||
})
|
||||
textures_to_import = selected_textures;
|
||||
}
|
||||
for (let path of textures_to_import) {
|
||||
let texture = new Texture({keep_size: true, render_mode}).fromPath(path).add();
|
||||
if (isApp) loadAdjacentTextureSet(texture);
|
||||
}
|
||||
if (render_mode == 'layered') {
|
||||
updateLayeredTextures();
|
||||
@ -322,7 +324,8 @@ window.BedrockEntityManager = class BedrockEntityManager {
|
||||
} else {
|
||||
function tryItWith(extension) {
|
||||
if (fs.existsSync(texture_path+'.'+extension)) {
|
||||
var texture = new Texture({keep_size: true}).fromPath(texture_path+'.'+extension).add()
|
||||
var texture = new Texture({keep_size: true}).fromPath(texture_path+'.'+extension).add();
|
||||
loadAdjacentTextureSet(texture);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -454,6 +457,7 @@ window.BedrockBlockManager = class BedrockBlockManager {
|
||||
])
|
||||
if (full_texture_path) {
|
||||
let texture = new Texture({keep_size: true}).fromPath(full_texture_path).add();
|
||||
if (isApp) loadAdjacentTextureSet(texture);
|
||||
if (target == '*') {
|
||||
texture.use_as_default = true;
|
||||
|
||||
@ -1051,6 +1055,7 @@ function getFormatVersion() {
|
||||
}
|
||||
}
|
||||
for (let cube of Cube.all) {
|
||||
if (cube.box_uv) continue;
|
||||
for (let fkey in cube.faces) {
|
||||
if (cube.faces[fkey].rotation) return '1.21.0';
|
||||
}
|
||||
|
@ -24,4 +24,5 @@ new ModelFormat({
|
||||
animation_mode: true,
|
||||
animated_textures: true,
|
||||
locators: true,
|
||||
pbr: true,
|
||||
})
|
||||
|
@ -1,7 +1,7 @@
|
||||
(function() {
|
||||
|
||||
let codec = new Codec('image', {
|
||||
name: tl('format.name'),
|
||||
name: tl('format.image'),
|
||||
extension: 'png',
|
||||
remember: true,
|
||||
load_filter: {
|
||||
|
@ -453,7 +453,7 @@ var codec = new Codec('java_block', {
|
||||
open_with_textures: {text: 'message.child_model_only.open_with_textures', condition: Texture.all.length > 0}
|
||||
}
|
||||
}, (result) => {
|
||||
if (result) {
|
||||
if (typeof result == 'string') {
|
||||
let parent = model.parent.replace(/\w+:/, '');
|
||||
let path_arr = path.split(osfs);
|
||||
let index = path_arr.length - path_arr.indexOf('models');
|
||||
|
@ -254,7 +254,7 @@ var codec = new Codec('optifine_entity', {
|
||||
let texture = importTexture(b.texture, b.textureSize);
|
||||
let group = 0;
|
||||
if (!model._is_jpm) {
|
||||
let group = new Group({
|
||||
group = new Group({
|
||||
name: b.part,
|
||||
origin: b.translate,
|
||||
rotation: b.rotate,
|
||||
|
File diff suppressed because it is too large
Load Diff
147
js/io/io.js
147
js/io/io.js
@ -487,149 +487,6 @@ const Extruder = {
|
||||
Undo.finishEdit('Add extruded texture', {elements: selected, outliner: true, textures: [Texture.all[Texture.all.length-1]]})
|
||||
}
|
||||
}
|
||||
//Json
|
||||
function compileJSON(object, options = {}) {
|
||||
let indentation = options.indentation;
|
||||
if (typeof indentation !== 'string') {
|
||||
switch (settings.json_indentation.value) {
|
||||
case 'spaces_4': indentation = ' '; break;
|
||||
case 'spaces_2': indentation = ' '; break;
|
||||
case 'tabs': default: indentation = '\t'; break;
|
||||
}
|
||||
}
|
||||
function newLine(tabs) {
|
||||
if (options.small === true) {return '';}
|
||||
let s = '\n';
|
||||
for (let i = 0; i < tabs; i++) {
|
||||
s += indentation;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
function escape(string) {
|
||||
return string.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n|\r\n/g, '\\n').replace(/\t/g, '\\t')
|
||||
}
|
||||
function handleVar(o, tabs, breaks = true) {
|
||||
var out = ''
|
||||
if (typeof o === 'string') {
|
||||
//String
|
||||
out += '"' + escape(o) + '"'
|
||||
} else if (typeof o === 'boolean') {
|
||||
//Boolean
|
||||
out += (o ? 'true' : 'false')
|
||||
} else if (o === null || o === Infinity || o === -Infinity) {
|
||||
//Null
|
||||
out += 'null'
|
||||
} else if (typeof o === 'number') {
|
||||
//Number
|
||||
o = (Math.round(o*100000)/100000).toString()
|
||||
out += o
|
||||
} else if (o instanceof Array) {
|
||||
//Array
|
||||
let has_content = false
|
||||
let multiline = !!o.find(item => typeof item === 'object');
|
||||
if (!multiline) {
|
||||
let length = 0;
|
||||
o.forEach(item => {
|
||||
length += typeof item === 'string' ? (item.length+4) : 3;
|
||||
});
|
||||
if (length > 140) multiline = true;
|
||||
}
|
||||
out += '['
|
||||
for (var i = 0; i < o.length; i++) {
|
||||
var compiled = handleVar(o[i], tabs+1)
|
||||
if (compiled) {
|
||||
if (has_content) {out += ',' + ((options.small || multiline) ? '' : ' ')}
|
||||
if (multiline) {out += newLine(tabs)}
|
||||
out += compiled
|
||||
has_content = true
|
||||
}
|
||||
}
|
||||
if (multiline) {out += newLine(tabs-1)}
|
||||
out += ']'
|
||||
} else if (typeof o === 'object') {
|
||||
//Object
|
||||
breaks = breaks && o.constructor.name !== 'oneLiner';
|
||||
var has_content = false
|
||||
out += '{'
|
||||
for (var key in o) {
|
||||
if (o.hasOwnProperty(key)) {
|
||||
var compiled = handleVar(o[key], tabs+1, breaks)
|
||||
if (compiled) {
|
||||
if (has_content) {out += ',' + (breaks || options.small?'':' ')}
|
||||
if (breaks) {out += newLine(tabs)}
|
||||
out += '"' + escape(key) + '":' + (options.small === true ? '' : ' ')
|
||||
out += compiled
|
||||
has_content = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (breaks && has_content) {out += newLine(tabs-1)}
|
||||
out += '}'
|
||||
}
|
||||
return out;
|
||||
}
|
||||
let file = handleVar(object, 1);
|
||||
if ((settings.final_newline.value && options.final_newline != false) || options.final_newline == true) {
|
||||
file += '\n';
|
||||
}
|
||||
return file;
|
||||
}
|
||||
function autoParseJSON(data, feedback) {
|
||||
if (data.substr(0, 4) === '<lz>') {
|
||||
data = LZUTF8.decompress(data.substr(4), {inputEncoding: 'StorageBinaryString'})
|
||||
}
|
||||
if (data.charCodeAt(0) === 0xFEFF) {
|
||||
data = data.substr(1)
|
||||
}
|
||||
try {
|
||||
data = JSON.parse(data)
|
||||
} catch (err1) {
|
||||
data = data.replace(/\/\*[^(\*\/)]*\*\/|\/\/.*/g, '')
|
||||
try {
|
||||
data = JSON.parse(data)
|
||||
} catch (err) {
|
||||
if (feedback === false) return;
|
||||
if (data.match(/\n\r?[><]{7}/)) {
|
||||
Blockbench.showMessageBox({
|
||||
title: 'message.invalid_file.title',
|
||||
icon: 'fab.fa-git-alt',
|
||||
message: 'message.invalid_file.merge_conflict'
|
||||
})
|
||||
return;
|
||||
}
|
||||
let error_part = '';
|
||||
function logErrantPart(whole, start, length) {
|
||||
var line = whole.substr(0, start).match(/\n/gm)
|
||||
line = line ? line.length+1 : 1
|
||||
var result = '';
|
||||
var lines = whole.substr(start, length).split(/\n/gm)
|
||||
lines.forEach((s, i) => {
|
||||
result += `#${line+i} ${s}\n`
|
||||
})
|
||||
error_part = result.substr(0, result.length-1) + ' <-- HERE';
|
||||
console.log(error_part);
|
||||
}
|
||||
console.error(err)
|
||||
var length = err.toString().split('at position ')[1]
|
||||
if (length) {
|
||||
length = parseInt(length)
|
||||
var start = limitNumber(length-32, 0, Infinity)
|
||||
|
||||
logErrantPart(data, start, 1+length-start)
|
||||
} else if (err.toString().includes('Unexpected end of JSON input')) {
|
||||
|
||||
logErrantPart(data, data.length-16, 10)
|
||||
}
|
||||
Blockbench.showMessageBox({
|
||||
translateKey: 'invalid_file',
|
||||
icon: 'error',
|
||||
message: tl('message.invalid_file.message', [err]) + (error_part ? `\n\n\`\`\`\n${error_part}\n\`\`\`` : '')
|
||||
})
|
||||
return;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
BARS.defineActions(function() {
|
||||
@ -719,7 +576,9 @@ BARS.defineActions(function() {
|
||||
Codecs.project.write(Codecs.project.compile(), Project.save_path);
|
||||
}
|
||||
if (Project.export_path && export_codec?.compile) {
|
||||
export_codec.write(export_codec.compile(), Project.export_path)
|
||||
if (export_codec.id != 'image') {
|
||||
export_codec.write(export_codec.compile(), Project.export_path)
|
||||
}
|
||||
|
||||
} else if (export_codec?.export && !Project.save_path) {
|
||||
if (export_codec.id === 'project' || settings.dialog_save_codec.value == false) {
|
||||
|
@ -2208,9 +2208,9 @@ BARS.defineActions(function() {
|
||||
Mesh.selected.forEach(mesh => {
|
||||
let original_vertices = mesh.getSelectedVertices().slice();
|
||||
let selected_edges = mesh.getSelectedEdges(true);
|
||||
let selected_face_keys = mesh.getSelectedFaces();
|
||||
let new_vertices;
|
||||
let new_face_keys = [];
|
||||
let selected_face_keys = mesh.getSelectedFaces();
|
||||
if (original_vertices.length && (BarItems.selection_mode.value == 'vertex' || BarItems.selection_mode.value == 'edge')) {
|
||||
selected_face_keys.empty();
|
||||
}
|
||||
@ -2379,13 +2379,13 @@ BARS.defineActions(function() {
|
||||
if (vertices.length == 2) delete mesh.faces[selected_face_keys[face_index]];
|
||||
})
|
||||
|
||||
// Create Face between extruded edges
|
||||
// Create Faces for extruded edges
|
||||
let new_faces = [];
|
||||
selected_edges.forEach(edge => {
|
||||
let face, sorted_vertices;
|
||||
for (let fkey in mesh.faces) {
|
||||
let face2 = mesh.faces[fkey];
|
||||
let vertices = face2.getSortedVertices();
|
||||
let vertices = face2.vertices;
|
||||
if (vertices.includes(edge[0]) && vertices.includes(edge[1])) {
|
||||
face = face2;
|
||||
sorted_vertices = vertices;
|
||||
@ -2400,6 +2400,9 @@ BARS.defineActions(function() {
|
||||
let new_face = new MeshFace(mesh, face).extend({
|
||||
vertices: [a, b, c, d]
|
||||
});
|
||||
if (new_face.getAngleTo(face) > 90) {
|
||||
new_face.invert();
|
||||
}
|
||||
let [face_key] = mesh.addFaces(new_face);
|
||||
new_face_keys.push(face_key);
|
||||
new_faces.push(new_face);
|
||||
@ -2453,7 +2456,6 @@ BARS.defineActions(function() {
|
||||
}},
|
||||
even_extend: {type: 'checkbox', value: false, label: 'edit.extrude_mesh_selection.even_extend'},
|
||||
}, form => {
|
||||
console.log(form)
|
||||
runEdit(true, form.extend, form.direction_mode, form.even_extend);
|
||||
})
|
||||
}
|
||||
|
@ -284,7 +284,9 @@ const MirrorModeling = {
|
||||
} else {
|
||||
// change
|
||||
let original_vkey = pre_part_connections.vertices[vkey];
|
||||
new_face.uv[new_vkey] = original_face.uv[original_vkey].slice();
|
||||
if (original_face.uv[original_vkey]) {
|
||||
new_face.uv[new_vkey] = original_face.uv[original_vkey].slice();
|
||||
}
|
||||
}
|
||||
})
|
||||
new_face.invert();
|
||||
@ -294,8 +296,14 @@ const MirrorModeling = {
|
||||
[new_face_key] = mesh.addFaces(new_face);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
let selected_vertices = mesh.getSelectedVertices(true);
|
||||
selected_vertices.replace(selected_vertices.filter(vkey => mesh.vertices[vkey]));
|
||||
let selected_edges = mesh.getSelectedEdges(true);
|
||||
selected_edges.replace(selected_edges.filter(edge => edge.allAre(vkey => mesh.vertices[vkey])));
|
||||
let selected_faces = mesh.getSelectedFaces(true);
|
||||
selected_faces.replace(selected_faces.filter(fkey => mesh.faces[fkey]));
|
||||
|
||||
let {preview_controller} = mesh;
|
||||
preview_controller.updateGeometry(mesh);
|
||||
preview_controller.updateFaces(mesh);
|
||||
|
@ -335,9 +335,9 @@ const Vertexsnap = {
|
||||
let mode = BarItems.vertex_snap_mode.get();
|
||||
|
||||
function ignoreVectorAxes(vector) {
|
||||
if (options.ignore_x) vector.x = 0;
|
||||
if (options.ignore_y) vector.y = 0;
|
||||
if (options.ignore_z) vector.z = 0;
|
||||
if (options.ignore_axis?.x) vector.x = 0;
|
||||
if (options.ignore_axis?.y) vector.y = 0;
|
||||
if (options.ignore_axis?.z) vector.z = 0;
|
||||
}
|
||||
|
||||
if (Vertexsnap.move_origin) {
|
||||
@ -497,9 +497,7 @@ const Vertexsnap = {
|
||||
y: tl('edit.vertex_snap.align.align_axis', 'Y'),
|
||||
z: tl('edit.vertex_snap.align.align_axis', 'Z'),
|
||||
}},
|
||||
ignore_x: {type: 'checkbox', label: tl('edit.vertex_snap.ignore_axis', 'X'), value: false},
|
||||
ignore_y: {type: 'checkbox', label: tl('edit.vertex_snap.ignore_axis', 'Y'), value: false},
|
||||
ignore_z: {type: 'checkbox', label: tl('edit.vertex_snap.ignore_axis', 'Z'), value: false},
|
||||
ignore_axis: {type: 'inline_multi_select', label: tl('edit.vertex_snap.ignore_axis', ''), options: {x: 'X', y: 'Y', z: 'Z'}, value: {x: false, y: false, z: false}},
|
||||
}, form => {
|
||||
Vertexsnap.snap(data, form, true);
|
||||
})
|
||||
|
@ -1152,7 +1152,7 @@
|
||||
}
|
||||
})
|
||||
}
|
||||
_has_groups = Format.bone_rig && Group.first_selected && Group.first_selected.matchesSelection() && Toolbox.selected.transformerMode == 'translate';
|
||||
_has_groups = Format.bone_rig && Group.first_selected && Toolbox.selected.transformerMode == 'translate';
|
||||
var rotate_group = Format.bone_rig && Group.first_selected && (Toolbox.selected.transformerMode == 'rotate');
|
||||
|
||||
if (Toolbox.selected.id == 'move_tool') {
|
||||
|
@ -25,8 +25,7 @@ class Collection {
|
||||
if (Modes.animate && Animation.selected && !(event?.ctrlOrCmd || Pressing.overrides.ctrl)) {
|
||||
Timeline.animators.empty();
|
||||
}
|
||||
for (let uuid of this.children) {
|
||||
let node = OutlinerNode.uuids[uuid];
|
||||
for (let node of this.getChildren()) {
|
||||
if (Modes.animate && Animation.selected) {
|
||||
if (node.constructor.animator) {
|
||||
let animator = Animation.selected.getBoneAnimator(node);
|
||||
@ -363,7 +362,7 @@ Object.defineProperty(Collection, 'all', {
|
||||
})
|
||||
Object.defineProperty(Collection, 'selected', {
|
||||
get() {
|
||||
return Project.collections.filter(c => c.selected);
|
||||
return Project ? Project.collections.filter(c => c.selected) : [];
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -399,6 +399,7 @@ class Group extends OutlinerNode {
|
||||
obj.locked = this.locked;
|
||||
obj.visibility = this.visibility;
|
||||
obj.autouv = this.autouv;
|
||||
obj.selected = Group.multi_selected.includes(this);
|
||||
}
|
||||
|
||||
if (this.rotation.allEqual(0)) {
|
||||
@ -562,7 +563,7 @@ new Property(Group, 'string', 'bedrock_binding', {condition: {formats: ['bedrock
|
||||
new Property(Group, 'array', 'cem_animations', {condition: {formats: ['optifine_entity']}});
|
||||
new Property(Group, 'boolean', 'cem_attach', {condition: {formats: ['optifine_entity']}});
|
||||
new Property(Group, 'number', 'cem_scale', {condition: {formats: ['optifine_entity']}});
|
||||
new Property(Group, 'string', 'texture', {condition: {formats: ['optifine_entity']}});
|
||||
new Property(Group, 'string', 'texture', {condition: {features: ['per_group_texture']}});
|
||||
//new Property(Group, 'vector2', 'texture_size', {condition: {formats: ['optifine_entity']}});
|
||||
new Property(Group, 'vector', 'skin_original_origin', {condition: {formats: ['skin']}});
|
||||
new Property(Group, 'number', 'color');
|
||||
@ -738,7 +739,7 @@ BARS.defineActions(function() {
|
||||
showPresetMenu(event) {
|
||||
new Menu([
|
||||
{
|
||||
name: 'Main Hand',
|
||||
name: 'Item Slot',
|
||||
icon: 'build',
|
||||
click: () => {
|
||||
this.binding = 'q.item_slot_to_bone_name(c.item_slot)';
|
||||
|
@ -1136,6 +1136,10 @@ new NodePreviewController(Mesh, {
|
||||
|
||||
Mesh.preview_controller.updatePixelGrid(element);
|
||||
|
||||
if (Project.view_mode == 'wireframe' && this.fixWireframe) {
|
||||
this.fixWireframe(element);
|
||||
}
|
||||
|
||||
this.dispatchEvent('update_geometry', {element});
|
||||
},
|
||||
updateFaces(element) {
|
||||
@ -1447,5 +1451,20 @@ new NodePreviewController(Mesh, {
|
||||
mesh.add(box);
|
||||
|
||||
this.dispatchEvent('update_painting_grid', {element});
|
||||
},
|
||||
fixWireframe(element) {
|
||||
let geometry_orig = element.mesh.geometry;
|
||||
if (!geometry_orig) return;
|
||||
let geometry_clone = element.mesh.geometry.clone();
|
||||
element.mesh.geometry = geometry_clone;
|
||||
geometry_orig.dispose();
|
||||
}
|
||||
})
|
||||
|
||||
Blockbench.dispatchEvent('change_view_mode', ({view_mode}) => {
|
||||
if (view_mode == 'wireframe') {
|
||||
for (let mesh of Mesh.selected) {
|
||||
Mesh.preview_controller.fixWireframe(mesh);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -800,7 +800,8 @@ function parseGroups(array, import_reference, startIndex) {
|
||||
OutlinerNode.uuids[array[i].uuid].removeFromParent();
|
||||
delete OutlinerNode.uuids[array[i].uuid];
|
||||
}
|
||||
var obj = new Group(array[i], array[i].uuid)
|
||||
// todo: Update old groups instead of rebuilding all
|
||||
let obj = new Group(array[i], array[i].uuid)
|
||||
obj.parent = addGroup
|
||||
obj.isOpen = !!array[i].isOpen
|
||||
if (array[i].uuid) {
|
||||
@ -814,6 +815,9 @@ function parseGroups(array, import_reference, startIndex) {
|
||||
if (array[i].content && array[i].content.length > 0) {
|
||||
iterate(array[i].content, obj.children, obj)
|
||||
}
|
||||
if (array[i].selected) {
|
||||
obj.multiSelect();
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@ -844,20 +848,20 @@ function moveOutlinerSelectionTo(item, target, event, order) {
|
||||
iterate(target)
|
||||
if (is_parent) return;
|
||||
}
|
||||
if (item instanceof OutlinerElement && Outliner.selected.includes( item )) {
|
||||
if (item instanceof OutlinerNode && item.selected) {
|
||||
var items = [];
|
||||
// ensure elements are in displayed order
|
||||
Outliner.root.forEach(node => {
|
||||
if (node instanceof Group) {
|
||||
node.forEachChild(child => {
|
||||
if (child.selected && child instanceof Group == false) items.push(child);
|
||||
})
|
||||
if (child.selected && !child.parent.selected && (target instanceof OutlinerNode == false || !target.isChildOf?.(child))) {
|
||||
items.push(child);
|
||||
}
|
||||
}, null, true);
|
||||
} else if (node.selected) {
|
||||
items.push(node);
|
||||
}
|
||||
})
|
||||
} else if (item instanceof Group) {
|
||||
var items = Group.multi_selected.filter(g => !g.parent.selected);
|
||||
} else {
|
||||
var items = [item];
|
||||
}
|
||||
@ -882,6 +886,9 @@ function moveOutlinerSelectionTo(item, target, event, order) {
|
||||
}
|
||||
} else {
|
||||
item.preview_controller.updateTransform(item);
|
||||
if (Format.per_group_texture && item.preview_controller.updateFaces) {
|
||||
item.preview_controller.updateFaces(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1131,14 +1138,15 @@ SharedActions.add('select_all', {
|
||||
Undo.initSelection();
|
||||
let selectable_elements = Outliner.elements.filter(element => !element.locked);
|
||||
if (Outliner.selected.length < selectable_elements.length) {
|
||||
if (Outliner.root.length == 1 && !Outliner.root[0].locked) {
|
||||
Outliner.root[0].select();
|
||||
} else {
|
||||
selectable_elements.forEach(obj => {
|
||||
obj.selectLow()
|
||||
})
|
||||
TickUpdates.selection = true;
|
||||
for (let node of Outliner.root) {
|
||||
if (node instanceof Group) {
|
||||
node.multiSelect();
|
||||
}
|
||||
}
|
||||
selectable_elements.forEach(obj => {
|
||||
obj.selectLow()
|
||||
})
|
||||
TickUpdates.selection = true;
|
||||
Undo.finishSelection('Select all elements');
|
||||
} else {
|
||||
unselectAllElements()
|
||||
|
@ -1155,6 +1155,9 @@ class Preview {
|
||||
let matrix_offset = new THREE.Matrix4().makeTranslation(z_offset.x, z_offset.y, z_offset.z);
|
||||
brush_matrix.multiplyMatrices(matrix_offset, brush_matrix);
|
||||
|
||||
// Since we're setting the brush matrix, we need to multiply in its parents matrix as well in case there are any.
|
||||
if (Canvas.brush_outline.parent)
|
||||
brush_matrix.multiplyMatrices(Canvas.brush_outline.parent.matrixWorld.clone().invert(), brush_matrix);
|
||||
Canvas.brush_outline.matrix = brush_matrix;
|
||||
}
|
||||
|
||||
@ -1939,12 +1942,15 @@ class OrbitGizmo {
|
||||
window.addEventListener("gamepadconnected", function(event) {
|
||||
let is_space_mouse = event.gamepad.id.includes('SpaceMouse') || event.gamepad.id.includes('SpaceNavigator') || event.gamepad.id.includes('3Dconnexion');
|
||||
|
||||
console.log('Gamepad Connected', event);
|
||||
|
||||
let zoom_timer = 0;
|
||||
|
||||
let interval = setInterval(() => {
|
||||
let gamepad = navigator.getGamepads()[event.gamepad.index];
|
||||
let preview = Preview.selected;
|
||||
if (!document.hasFocus() || !preview || !gamepad || !gamepad.axes || gamepad.axes.allEqual(0) || gamepad.axes.find(v => isNaN(v)) != undefined) return;
|
||||
if (settings.gamepad_controls.value == false) return;
|
||||
if (!document.hasFocus() || !preview || !gamepad || !gamepad.axes || !gamepad.connected || gamepad.axes.allEqual(0) || gamepad.axes.find(v => isNaN(v)) != undefined) return;
|
||||
|
||||
if (is_space_mouse) {
|
||||
let offset = new THREE.Vector3(
|
||||
@ -2203,6 +2209,7 @@ BARS.defineActions(function() {
|
||||
material: {name: true, icon: 'pages', condition: () => ((!Toolbox.selected.allowed_view_modes || Toolbox.selected.allowed_view_modes.includes('material')) && TextureGroup.all.find(tg => tg.is_material))},
|
||||
},
|
||||
onChange() {
|
||||
let previous_view_mode = Project.view_mode;
|
||||
Project.view_mode = this.value;
|
||||
Canvas.updateViewMode();
|
||||
if (Modes.id === 'animate') {
|
||||
@ -2215,6 +2222,9 @@ BARS.defineActions(function() {
|
||||
if (icon_node) icon_node.replaceWith(icon);
|
||||
}
|
||||
})
|
||||
if (Project.view_mode != previous_view_mode) {
|
||||
Blockbench.dispatchEvent('change_view_mode', {view_mode: Project.view_mode, previous_view_mode});
|
||||
}
|
||||
//Blockbench.showQuickMessage(tl('action.view_mode') + ': ' + tl('action.view_mode.' + this.value));
|
||||
}
|
||||
})
|
||||
|
@ -349,14 +349,19 @@ class ReferenceImage {
|
||||
(e2.clientX - e1.clientX) * multiplier,
|
||||
(e2.clientY - e1.clientY) * multiplier,
|
||||
];
|
||||
this.size[0] = Math.max(original_size[0] + offset[0] * sign_x, 48);
|
||||
let zoom_level = this.getZoomLevel();
|
||||
let max_size = [
|
||||
32 / zoom_level,
|
||||
24 / zoom_level
|
||||
];
|
||||
this.size[0] = Math.max(original_size[0] + offset[0] * sign_x, max_size[0]);
|
||||
this.position[0] = original_position[0] + offset[0] / 2, 0;
|
||||
|
||||
if (!e2.ctrlOrCmd && !Pressing.overrides.ctrl) {
|
||||
offset[1] = sign_y * (this.size[0] / this.aspect_ratio - original_size[1]);
|
||||
}
|
||||
|
||||
this.size[1] = Math.max(original_size[1] + offset[1] * sign_y, 32);
|
||||
this.size[1] = Math.max(original_size[1] + offset[1] * sign_y, max_size[1]);
|
||||
this.position[1] = original_position[1] + offset[1] / 2, 0;
|
||||
|
||||
if (this.layer !== 'blueprint') {
|
||||
|
@ -643,6 +643,43 @@ BARS.defineActions(function() {
|
||||
Undo.finishEdit('Limit texture to palette')
|
||||
}
|
||||
})
|
||||
new Action('split_rgb_into_layers', {
|
||||
icon: 'stacked_bar_chart',
|
||||
category: 'textures',
|
||||
condition: {modes: ['paint'], selected: {texture: true}},
|
||||
click() {
|
||||
let texture = Texture.getDefault();
|
||||
let original_data = texture.ctx.getImageData(0, 0, texture.canvas.width, texture.canvas.height);
|
||||
|
||||
Undo.initEdit({textures: [texture], bitmap: true});
|
||||
|
||||
texture.layers_enabled = true;
|
||||
let i = 0;
|
||||
for (let color of ['red', 'green', 'blue']) {
|
||||
data_copy = new ImageData(original_data.data.slice(), original_data.width, original_data.height);
|
||||
for (let j = 0; j < data_copy.data.length; j += 4) {
|
||||
if (i != 0) data_copy.data[j+0] = 0;
|
||||
if (i != 1) data_copy.data[j+1] = 0;
|
||||
if (i != 2) data_copy.data[j+2] = 0;
|
||||
}
|
||||
let layer = new TextureLayer({
|
||||
name: color,
|
||||
blend_mode: 'add'
|
||||
}, texture);
|
||||
layer.setSize(original_data.width, original_data.height);
|
||||
layer.ctx.putImageData(data_copy, 0, 0);
|
||||
texture.layers.unshift(layer);
|
||||
if (color == 'red') {
|
||||
layer.select();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
texture.updateLayerChanges(true);
|
||||
Undo.finishEdit('Split texture into RGB layers');
|
||||
updateInterfacePanels();
|
||||
BARS.updateConditions();
|
||||
}
|
||||
})
|
||||
new Action('clear_unused_texture_space', {
|
||||
icon: 'cleaning_services',
|
||||
category: 'textures',
|
||||
|
@ -1181,7 +1181,7 @@ const Painter = {
|
||||
}, {no_undo: true, use_cache: true});
|
||||
},
|
||||
colorPicker(texture, x, y, event) {
|
||||
var ctx = Painter.getCanvas(texture).getContext('2d')
|
||||
let {ctx} = settings.pick_combined_color.value ? texture : texture.getActiveCanvas();
|
||||
let color = Painter.getPixelColor(ctx, x, y);
|
||||
if (settings.pick_color_opacity.value) {
|
||||
let opacity = Math.floor(color.getAlpha()*256);
|
||||
|
@ -348,21 +348,23 @@ const TextureGenerator = {
|
||||
});
|
||||
function faceRect(cube, face_key, tex, x, y, face_old_pos_id) {
|
||||
this.cube = cube;
|
||||
this.face = cube.faces[face_key];
|
||||
if (options.rearrange_uv) {
|
||||
this.width = Math.abs(x) * res_multiple;
|
||||
this.height = Math.abs(y) * res_multiple;
|
||||
this.mirror_x = Math.sign(this.face.uv_size[0]);
|
||||
this.mirror_y = Math.sign(this.face.uv_size[1]);
|
||||
this.width = ((this.width >= 0.01 && this.width < 1) ? 1 : Math.round(this.width)) / res_multiple;
|
||||
this.height = ((this.height >= 0.01 && this.height < 1) ? 1 : Math.round(this.height)) / res_multiple;
|
||||
} else {
|
||||
this.posx = cube.faces[face_key].uv[0], cube.faces[face_key].uv[0+2];
|
||||
this.posy = cube.faces[face_key].uv[1], cube.faces[face_key].uv[1+2];
|
||||
this.width = cube.faces[face_key].uv[0+2] - cube.faces[face_key].uv[0];
|
||||
this.height = cube.faces[face_key].uv[1+2] - cube.faces[face_key].uv[1];
|
||||
this.posx = this.face.uv[0], this.face.uv[0+2];
|
||||
this.posy = this.face.uv[1], this.face.uv[1+2];
|
||||
this.width = this.face.uv[0+2] - this.face.uv[0];
|
||||
this.height = this.face.uv[1+2] - this.face.uv[1];
|
||||
}
|
||||
this.size = this.width * this.height;
|
||||
this.face_key = face_key;
|
||||
this.texture = tex
|
||||
this.face = cube.faces[face_key];
|
||||
this.face_old_pos_id = face_old_pos_id;
|
||||
}
|
||||
function faceOldPositionIdentifier(face) {
|
||||
@ -374,7 +376,14 @@ const TextureGenerator = {
|
||||
vertex_identifiers.sort(sort_collator.compare);
|
||||
uv_id = vertex_identifiers.join(',');
|
||||
} else if (face.uv instanceof Array) {
|
||||
uv_id = face.uv.map(v => Math.roundTo(v, 4)).join(',');
|
||||
let absolute_uv = face.uv.slice();
|
||||
for (let i = 0; i < 2; i++) {
|
||||
if (absolute_uv[i] > absolute_uv[i+2]) {
|
||||
absolute_uv[i] = absolute_uv[i+2];
|
||||
absolute_uv[i+2] = face.uv[i];
|
||||
}
|
||||
}
|
||||
uv_id = absolute_uv.map(v => Math.roundTo(v, 4)).join(',');
|
||||
}
|
||||
let texture = face.getTexture();
|
||||
return uv_id + ':' + (texture ? texture.uuid : 'blank');
|
||||
@ -1408,6 +1417,15 @@ const TextureGenerator = {
|
||||
uv: flip_rotation ? [pos.y, pos.x] : [pos.x, pos.y]
|
||||
})
|
||||
target.face.uv_size = flip_rotation ? [pos.h, pos.w] : [pos.w, pos.h];
|
||||
if (source != target) {
|
||||
// Double occupancy mirroring
|
||||
if (target.mirror_x == -1) {
|
||||
[target.face.uv[2], target.face.uv[0]] = [target.face.uv[0], target.face.uv[2]];
|
||||
}
|
||||
if (target.mirror_y == -1) {
|
||||
[target.face.uv[3], target.face.uv[1]] = [target.face.uv[1], target.face.uv[3]];
|
||||
}
|
||||
}
|
||||
if (target.face_key == 'up') {
|
||||
[target.face.uv[2], target.face.uv[0]] = [target.face.uv[0], target.face.uv[2]];
|
||||
[target.face.uv[3], target.face.uv[1]] = [target.face.uv[1], target.face.uv[3]];
|
||||
|
@ -110,6 +110,8 @@ class TextureGroup {
|
||||
let normal_tex = textures.find(t => t.pbr_channel == 'normal');
|
||||
let height_tex = textures.find(t => t.pbr_channel == 'height');
|
||||
let mer_tex = textures.find(t => t.pbr_channel == 'mer');
|
||||
|
||||
// Albedo
|
||||
if (color_tex) {
|
||||
material.map = color_tex.getOwnMaterial().map;
|
||||
material.color.set('#ffffff');
|
||||
@ -120,13 +122,15 @@ class TextureGroup {
|
||||
material.color.set({r: c[0] / 255, g: c[1] / 255, b: c[2] / 255});
|
||||
material.opacity = c[4] / 255;
|
||||
}
|
||||
|
||||
// Height
|
||||
if (normal_tex) {
|
||||
material.normalMap = normal_tex.getOwnMaterial().map;
|
||||
material.bumpMap = null;
|
||||
// Use DirectX normal maps for RenderDragon. Flips the "handedness" of the normal map.
|
||||
material.normalScale = Project.format.id.includes('bedrock') ? new THREE.Vector2(1, -1) : new THREE.Vector2(1, 1);
|
||||
} else if (height_tex) {
|
||||
material.bumpMap = height_tex.getOwnMaterial().map;
|
||||
material.bumpMap = height_tex.getOwnMaterial().map.clone();
|
||||
material.bumpScale = 0.4;
|
||||
material.normalMap = null;
|
||||
// Bump map scale
|
||||
@ -139,8 +143,13 @@ class TextureGroup {
|
||||
material.bumpMap.image = canvas;
|
||||
material.bumpMap.magFilter = THREE.LinearFilter;
|
||||
material.bumpMap.needsUpdate = true;
|
||||
} else {
|
||||
material.normalMap = null;
|
||||
material.bumpMap = null;
|
||||
}
|
||||
if (mer_tex && mer_tex.img?.naturalWidth) {
|
||||
|
||||
// MER
|
||||
if (mer_tex && mer_tex.img?.naturalWidth && mer_tex.width) {
|
||||
let image_data = mer_tex.canvas.getContext('2d').getImageData(0, 0, mer_tex.width, mer_tex.height);
|
||||
|
||||
const extractEmissiveChannel = () => {
|
||||
@ -179,21 +188,21 @@ class TextureGroup {
|
||||
}
|
||||
|
||||
function generateMap(source_channel, key) {
|
||||
let canvas = material[key]?.image ?? document.createElement('canvas');
|
||||
let canvas = material[key]?.image;
|
||||
if (!canvas || key == 'emissiveMap') {
|
||||
canvas = document.createElement('canvas');
|
||||
}
|
||||
let ctx = canvas.getContext('2d');
|
||||
canvas.width = mer_tex.width;
|
||||
canvas.height = mer_tex.height;
|
||||
ctx.fillStyle = 'black';
|
||||
ctx.fillRect(0, 0, mer_tex.width, mer_tex.height);
|
||||
document.body.append(canvas);
|
||||
// document.body.append(canvas);
|
||||
|
||||
ctx.putImageData(source_channel === 1 ? extractEmissiveChannel() : extractGrayscaleValue(source_channel), 0, 0);
|
||||
|
||||
if (!material[key] || true) {
|
||||
material[key] = new THREE.Texture(canvas, THREE.UVMapping, THREE.RepeatWrapping, THREE.RepeatWrapping, THREE.NearestFilter, THREE.NearestFilter);
|
||||
material[key].needsUpdate = true;
|
||||
}
|
||||
//material.map = material[key];
|
||||
material[key] = new THREE.Texture(canvas, THREE.UVMapping, THREE.RepeatWrapping, THREE.RepeatWrapping, THREE.NearestFilter, THREE.NearestFilter);
|
||||
material[key].needsUpdate = true;
|
||||
}
|
||||
generateMap(0, 'metalnessMap');
|
||||
generateMap(1, 'emissiveMap');
|
||||
@ -318,7 +327,14 @@ class TextureGroupMaterialConfig {
|
||||
texture_set.color = this.color_value.slice();
|
||||
}
|
||||
if (mer_tex) {
|
||||
texture_set.metalness_emissive_roughness = getTextureName(mer_tex);
|
||||
let texture_name = getTextureName(mer_tex);
|
||||
if (this.subsurface_value) {
|
||||
texture_set.metalness_emissive_roughness_subsurface = texture_name;
|
||||
} else {
|
||||
texture_set.metalness_emissive_roughness = texture_name;
|
||||
}
|
||||
} else if (this.subsurface_value) {
|
||||
texture_set.metalness_emissive_roughness_subsurface = [...this.mer_value, this.subsurface_value];
|
||||
} else if (!this.mer_value.allEqual(0)) {
|
||||
texture_set.metalness_emissive_roughness = this.mer_value.slice();
|
||||
}
|
||||
@ -328,8 +344,12 @@ class TextureGroupMaterialConfig {
|
||||
texture_set.heightmap = getTextureName(height_tex);
|
||||
}
|
||||
|
||||
let format_version = "1.16.100";
|
||||
if (texture_set.metalness_emissive_roughness_subsurface) {
|
||||
format_version = "1.21.30";
|
||||
}
|
||||
let file = {
|
||||
format_version: "1.16.100",
|
||||
format_version,
|
||||
"minecraft:texture_set": texture_set
|
||||
}
|
||||
return file;
|
||||
@ -398,7 +418,7 @@ class TextureGroupMaterialConfig {
|
||||
a: this.color_value[3] / 255
|
||||
}
|
||||
},
|
||||
'mer': '_',
|
||||
'_mers': '_',
|
||||
mer: {
|
||||
type: 'select',
|
||||
label: 'dialog.material_config.mer',
|
||||
@ -412,7 +432,21 @@ class TextureGroupMaterialConfig {
|
||||
min: 0, max: 255, step: 1, force_step: true,
|
||||
value: this.mer_value.map(v => Math.clamp(v, 0, 255)),
|
||||
},
|
||||
'depth': '_',
|
||||
subsurface: {
|
||||
type: 'checkbox',
|
||||
label: 'dialog.material_config.subsurface',
|
||||
description: 'dialog.material_config.subsurface_enabled.desc',
|
||||
condition: form => isUUID(form.mer),
|
||||
value: this.subsurface_value > 0,
|
||||
},
|
||||
subsurface_value: {
|
||||
label: 'dialog.material_config.subsurface',
|
||||
condition: form => form.mer == 'uniform',
|
||||
type: 'number',
|
||||
min: 0, max: 255, step: 1, force_step: true,
|
||||
value: Math.clamp(this.subsurface_value, 0, 255),
|
||||
},
|
||||
'_depth': '_',
|
||||
depth_type: {
|
||||
type: 'inline_select',
|
||||
label: 'dialog.material_config.depth_type',
|
||||
@ -457,10 +491,12 @@ class TextureGroupMaterialConfig {
|
||||
for (let texture of textures) {
|
||||
if (texture.pbr_channel == 'mer') texture.group = '';
|
||||
}
|
||||
this.subsurface_value = result.subsurface_value;
|
||||
} else {
|
||||
this.mer_value.replace([0, 0, 0]);
|
||||
let target = textures.find(t => t.uuid == result.mer);
|
||||
if (target) target.pbr_channel = 'mer';
|
||||
this.subsurface_value = result.subsurface ? 1 : 0;
|
||||
}
|
||||
|
||||
if (result.depth_type == 'normal') {
|
||||
@ -485,6 +521,7 @@ class TextureGroupMaterialConfig {
|
||||
}
|
||||
new Property(TextureGroupMaterialConfig, 'vector4', 'color_value', {default: [255, 255, 255, 255]});
|
||||
new Property(TextureGroupMaterialConfig, 'vector', 'mer_value');
|
||||
new Property(TextureGroupMaterialConfig, 'number', 'subsurface_value');
|
||||
new Property(TextureGroupMaterialConfig, 'boolean', 'saved', {default: true});
|
||||
TextureGroupMaterialConfig.prototype.menu = new Menu('texture_group_material_config', [
|
||||
'generate_pbr_map',
|
||||
@ -532,7 +569,7 @@ function importTextureSet(file) {
|
||||
Undo.initEdit({textures: new_textures, texture_groups: new_texture_groups});
|
||||
if (file.name.endsWith('texture_set.json')) {
|
||||
let texture_group = new TextureGroup({is_material: true});
|
||||
texture_group.name = file.name.replace('.texture_set.json', '');
|
||||
texture_group.name = file.name.replace('.texture_set.json', '.png material');
|
||||
|
||||
let content = fs.readFileSync(file.path, {encoding: 'utf-8'});
|
||||
let content_json = autoParseJSON(content);
|
||||
@ -543,6 +580,7 @@ function importTextureSet(file) {
|
||||
normal: 'normal',
|
||||
heightmap: 'height',
|
||||
metalness_emissive_roughness: 'mer',
|
||||
metalness_emissive_roughness_subsurface: 'mer',
|
||||
};
|
||||
for (let key in channels) {
|
||||
let source = content_json['minecraft:texture_set'][key];
|
||||
@ -558,6 +596,9 @@ function importTextureSet(file) {
|
||||
new_textures.push(t);
|
||||
t.group = texture_group.uuid;
|
||||
})
|
||||
if (key == 'metalness_emissive_roughness_subsurface') {
|
||||
texture_group.material_config.subsurface_value = 1;
|
||||
}
|
||||
} else {
|
||||
let color_array = source;
|
||||
if (typeof source == 'string') {
|
||||
@ -572,6 +613,9 @@ function importTextureSet(file) {
|
||||
}
|
||||
} else if (key == 'metalness_emissive_roughness') {
|
||||
texture_group.material_config.mer_value.V3_set(color_array);
|
||||
} else if (key == 'metalness_emissive_roughness_subsurface') {
|
||||
texture_group.material_config.mer_value.V3_set(color_array);
|
||||
texture_group.material_config.subsurface_value = Math.clamp(color_array[3] ?? 0, 0, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -583,6 +627,14 @@ function importTextureSet(file) {
|
||||
}
|
||||
Undo.finishEdit('Import texture set');
|
||||
}
|
||||
function loadAdjacentTextureSet(texture) {
|
||||
let path = texture.path.replace(/\.png$/i, '.texture_set.json');
|
||||
if (fs.existsSync(path)) {
|
||||
Blockbench.read([path], {}, (files) => {
|
||||
importTextureSet(files[0])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
SharedActions.add('rename', {
|
||||
condition: () => Prop.active_panel == 'textures' && TextureGroup.active_menu_group,
|
||||
@ -615,6 +667,7 @@ BARS.defineActions(function() {
|
||||
new Action('create_material', {
|
||||
icon: 'lightbulb_circle',
|
||||
category: 'textures',
|
||||
condition: () => (!Texture.selected || !Texture.selected.getGroup()?.is_material) && Format.pbr,
|
||||
click() {
|
||||
let texture = Texture.selected;
|
||||
let texture_group = new TextureGroup({is_material: true});
|
||||
@ -653,7 +706,7 @@ BARS.defineActions(function() {
|
||||
let new_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
canvas.style.width = 256 + 'px';
|
||||
canvas.style.height = 256 + 'px';
|
||||
let original_image = new CanvasFrame(texture.canvas);
|
||||
let original_image = new CanvasFrame(texture.canvas, true);
|
||||
original_image.canvas.style.width = 256 + 'px';
|
||||
original_image.canvas.style.height = 256 + 'px';
|
||||
|
||||
@ -754,6 +807,17 @@ BARS.defineActions(function() {
|
||||
width: 564,
|
||||
lines: [preview],
|
||||
form: {
|
||||
channel: {
|
||||
type: 'select',
|
||||
label: 'PBR Channel',
|
||||
options: {
|
||||
//normal: 'menu.texture.pbr_channel.normal',
|
||||
height: 'menu.texture.pbr_channel.height',
|
||||
metalness: 'Metalness',
|
||||
emissive: 'Emissive',
|
||||
roughness: 'Roughness',
|
||||
}
|
||||
},
|
||||
method: {
|
||||
type: 'select',
|
||||
label: 'Source',
|
||||
@ -767,17 +831,6 @@ BARS.defineActions(function() {
|
||||
blue: 'Blue',
|
||||
}
|
||||
},
|
||||
channel: {
|
||||
type: 'select',
|
||||
label: 'PBR Channel',
|
||||
options: {
|
||||
//normal: 'menu.texture.pbr_channel.normal',
|
||||
height: 'menu.texture.pbr_channel.height',
|
||||
metalness: 'Metalness',
|
||||
emissive: 'Emissive',
|
||||
roughness: 'Roughness',
|
||||
}
|
||||
},
|
||||
in_range: {
|
||||
type: 'vector',
|
||||
label: 'Input Range',
|
||||
@ -798,15 +851,53 @@ BARS.defineActions(function() {
|
||||
onConfirm(result) {
|
||||
updateCanvas(result);
|
||||
let textures = [];
|
||||
Undo.initEdit({texture_groups: texture_group ? [texture_group] : null, textures});
|
||||
let pbr_channel = result.channel;
|
||||
let new_texture = new Texture({
|
||||
name: texture.name,
|
||||
pbr_channel,
|
||||
group: texture_group?.uuid,
|
||||
}).fromDataURL(canvas.toDataURL()).add(false);
|
||||
textures.push(new_texture);
|
||||
let pbr_channel;
|
||||
switch (result.channel) {
|
||||
case 'height': pbr_channel = result.channel; break;
|
||||
default: pbr_channel = 'mer'; break;
|
||||
}
|
||||
|
||||
let existing_channel_texture = texture_group.getTextures().find(tex => tex.pbr_channel == pbr_channel);
|
||||
|
||||
if (existing_channel_texture && pbr_channel == 'mer') {
|
||||
Undo.initEdit({textures: [existing_channel_texture], bitmap: true});
|
||||
if (!existing_channel_texture.layers_enabled) {
|
||||
existing_channel_texture.activateLayers(false);
|
||||
}
|
||||
let layer = new TextureLayer({
|
||||
name: result.channel,
|
||||
blend_mode: 'add'
|
||||
}, existing_channel_texture);
|
||||
let image_data = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
|
||||
layer.setSize(canvas.width, canvas.height);
|
||||
layer.ctx.putImageData(image_data, 0, 0);
|
||||
layer.addForEditing();
|
||||
existing_channel_texture.updateLayerChanges(true);
|
||||
|
||||
} else {
|
||||
Undo.initEdit({texture_groups: texture_group ? [texture_group] : null, textures});
|
||||
|
||||
let main_texture = texture_group?.getTextures().find(t => t.pbr_channel == 'color');
|
||||
let name = main_texture ? main_texture.name : texture.name;
|
||||
name = name.replace('.', `_${pbr_channel}.`);
|
||||
|
||||
let new_texture = new Texture({
|
||||
name,
|
||||
pbr_channel,
|
||||
group: texture_group?.uuid,
|
||||
}).fromDataURL(canvas.toDataURL()).add(false);
|
||||
textures.push(new_texture);
|
||||
|
||||
if (texture_group.material_config) {
|
||||
texture_group.material_config.saved = false;
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
texture_group.updateMaterial();
|
||||
}, 50);
|
||||
Undo.finishEdit('Create PBR map');
|
||||
updateSelection();
|
||||
},
|
||||
onOpen() {
|
||||
updateCanvas(this.getFormResult());
|
||||
|
@ -1788,6 +1788,9 @@ class Texture {
|
||||
this.source = this.canvas.toDataURL('image/png', 1);
|
||||
this.updateImageFromCanvas();
|
||||
}
|
||||
if ((this.pbr_channel == 'mer' || this.pbr_channel == 'height') && this.getGroup()?.is_material && BarItems.view_mode.value == 'material') {
|
||||
this.getGroup().updateMaterial();
|
||||
}
|
||||
this.saved = false;
|
||||
this.syncToOtherProject();
|
||||
}
|
||||
@ -1996,6 +1999,7 @@ class Texture {
|
||||
'adjust_curves',
|
||||
new MenuSeparator('filters'),
|
||||
'limit_to_palette',
|
||||
'split_rgb_into_layers',
|
||||
'clear_unused_texture_space',
|
||||
new MenuSeparator('transform'),
|
||||
'flip_texture_x',
|
||||
@ -2649,6 +2653,9 @@ Interface.definePanels(function() {
|
||||
|
||||
addEventListeners(document, 'mousemove touchmove', move, {passive: false});
|
||||
addEventListeners(document, 'mouseup touchend', off, {passive: false});
|
||||
},
|
||||
closeContextMenu() {
|
||||
if (Menu.open) Menu.open.hide();
|
||||
}
|
||||
},
|
||||
template: `
|
||||
@ -2656,7 +2663,7 @@ Interface.definePanels(function() {
|
||||
v-bind:class="{ selected: texture.selected, multi_selected: texture.multi_selected, particle: texture.particle, use_as_default: texture.use_as_default}"
|
||||
v-bind:texid="texture.uuid"
|
||||
class="texture"
|
||||
@click.stop="texture.select($event)"
|
||||
@click.stop="closeContextMenu();texture.select($event)"
|
||||
@mousedown="highlightTexture($event)"
|
||||
@mouseup="unhighlightTexture($event)"
|
||||
@dblclick="texture.openMenu($event)"
|
||||
|
@ -1277,7 +1277,6 @@ const UVEditor = {
|
||||
Undo.finishEdit('Toggle cullface')
|
||||
},
|
||||
switchTint(event) {
|
||||
var scope = this;
|
||||
var val = UVEditor.getReferenceFace().tint === -1 ? 0 : -1;
|
||||
|
||||
if (event === 0 || event === false) val = event
|
||||
@ -4204,28 +4203,42 @@ Interface.definePanels(function() {
|
||||
},
|
||||
toggleFaceTint(key, event) {
|
||||
Undo.initEdit({elements: Cube.selected, uv_only: true})
|
||||
UVEditor.switchTint(event)
|
||||
UVEditor.vue.$forceUpdate();
|
||||
let value = UVEditor.getFirstMappableElement()?.faces[key]?.tint === -1 ? 0 : -1;
|
||||
UVEditor.forCubes(cube => {
|
||||
cube.faces[key].tint = value;
|
||||
})
|
||||
this.$forceUpdate();
|
||||
Undo.finishEdit('Toggle face tint')
|
||||
},
|
||||
changeFaceTint(key, event) {
|
||||
Undo.initEdit({elements: Cube.selected, uv_only: true})
|
||||
UVEditor.setTint(event, parseInt(event.target.value));
|
||||
Undo.finishEdit('Toggle face tint');
|
||||
let value = parseInt(event.target.value);
|
||||
UVEditor.forCubes(cube => {
|
||||
cube.faces[key].tint = value;
|
||||
})
|
||||
Undo.finishEdit('Set face tint');
|
||||
},
|
||||
setCullface(key, value) {
|
||||
Undo.initEdit({elements: Cube.selected, uv_only: true})
|
||||
UVEditor.forCubes(obj => {
|
||||
UVEditor.getSelectedFaces(obj).forEach(face => {
|
||||
obj.faces[face].cullface = value;
|
||||
})
|
||||
if (obj.faces[key]) {
|
||||
obj.faces[key].cullface = value;
|
||||
}
|
||||
})
|
||||
Undo.finishEdit(value ? `Set cullface to ${value}` : 'Disable cullface');
|
||||
},
|
||||
startInputMaterialInstance(event) {
|
||||
Undo.initEdit({elements: Cube.selected, uv_only: true})
|
||||
},
|
||||
endInputMaterialInstance(event) {
|
||||
endInputMaterialInstance(event, fkey) {
|
||||
let value = this.mappable_elements[0]?.faces[fkey]?.material_name;
|
||||
if (typeof value == 'string') {
|
||||
for (let element of this.mappable_elements) {
|
||||
if (element.faces[fkey]) {
|
||||
element.faces[fkey].material_name = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Undo.finishEdit('Change material instances');
|
||||
},
|
||||
showInfoBox(title, text) {
|
||||
@ -4329,7 +4342,7 @@ Interface.definePanels(function() {
|
||||
title="${tl('uv_editor.face_properties.material_instance')}"
|
||||
v-model="mappable_elements[0].faces[key].material_name"
|
||||
@focus="startInputMaterialInstance($event)"
|
||||
@focusout="endInputMaterialInstance($event)"
|
||||
@focusout="endInputMaterialInstance($event, key)"
|
||||
>
|
||||
</template>
|
||||
</li>
|
||||
|
85
js/undo.js
85
js/undo.js
@ -15,12 +15,16 @@ class UndoSystem {
|
||||
}
|
||||
}
|
||||
initEdit(aspects, amended = false) {
|
||||
// todo: selecting all groups, moving, then undoing, unselects all multi-selected groups
|
||||
if (aspects && aspects.cubes) {
|
||||
console.warn('Aspect "cubes" is deprecated. Please use "elements" instead.');
|
||||
aspects.elements = aspects.cubes;
|
||||
}
|
||||
this.startChange(amended);
|
||||
this.current_save = new UndoSystem.save(aspects)
|
||||
this.current_save = new UndoSystem.save(aspects);
|
||||
if (aspects.selection) {
|
||||
this.current_selection_save = new UndoSystem.selectionSave(typeof aspects.selection == 'object' ? typeof aspects.selection : 0);
|
||||
}
|
||||
Blockbench.dispatchEvent('init_edit', {aspects, amended, save: this.current_save})
|
||||
return this.current_save;
|
||||
}
|
||||
@ -40,7 +44,18 @@ class UndoSystem {
|
||||
type: 'edit',
|
||||
time: Date.now()
|
||||
}
|
||||
this.current_save = entry.post
|
||||
|
||||
if (aspects.selection && this.current_selection_save) {
|
||||
let selection_aspects = typeof aspects.selection == 'object' ? aspects.selection : this.current_selection_save.aspects;
|
||||
let selection_before = this.current_selection_save;
|
||||
let selection_post = new UndoSystem.selectionSave(selection_aspects);
|
||||
if (!selection_before.matches(selection_post)) {
|
||||
entry.selection_before = selection_before;
|
||||
entry.selection_post = selection_post;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (this.history.length > this.index) {
|
||||
this.history.length = this.index;
|
||||
}
|
||||
@ -62,7 +77,7 @@ class UndoSystem {
|
||||
return entry;
|
||||
}
|
||||
initSelection(aspects) {
|
||||
if (!settings.undo_selections.value || Blockbench.hasFlag('loading_selection_save')) return;
|
||||
if (!settings.undo_selections.value || Blockbench.hasFlag('loading_selection_save') || Project.EditSession) return;
|
||||
|
||||
if (this.current_selection_save) return;
|
||||
this.current_selection_save = new UndoSystem.selectionSave(aspects);
|
||||
@ -70,7 +85,7 @@ class UndoSystem {
|
||||
return this.current_selection_save;
|
||||
}
|
||||
finishSelection(message, aspects) {
|
||||
if (!settings.undo_selections.value || Blockbench.hasFlag('loading_selection_save')) return;
|
||||
if (!settings.undo_selections.value || Blockbench.hasFlag('loading_selection_save') || Project.EditSession) return;
|
||||
|
||||
if (!this.current_selection_save) return;
|
||||
aspects = aspects || this.current_selection_save.aspects;
|
||||
@ -89,7 +104,6 @@ class UndoSystem {
|
||||
type: 'selection',
|
||||
time: Date.now()
|
||||
}
|
||||
this.current_selection_save = entry.selection_post
|
||||
if (this.history.length > this.index) {
|
||||
this.history.length = this.index;
|
||||
}
|
||||
@ -178,10 +192,14 @@ class UndoSystem {
|
||||
this.index--;
|
||||
|
||||
var entry = this.history[this.index];
|
||||
if (entry.before) entry.before.load(entry.post);
|
||||
if (entry.selection_before) entry.selection_before.load(entry.selection_post);
|
||||
if (Project.EditSession && remote !== true) {
|
||||
Project.EditSession.sendAll('command', 'undo')
|
||||
if (entry.before) {
|
||||
this.loadSave(entry.before, entry.post);
|
||||
}
|
||||
if (entry.selection_before instanceof UndoSystem.selectionSave) {
|
||||
entry.selection_before.load(entry.selection_post);
|
||||
}
|
||||
if (Project.EditSession && remote !== true && entry.type != 'selection') {
|
||||
Project.EditSession.sendAll('command', 'undo');
|
||||
}
|
||||
Blockbench.dispatchEvent('undo', {entry})
|
||||
}
|
||||
@ -195,15 +213,19 @@ class UndoSystem {
|
||||
|
||||
var entry = this.history[this.index]
|
||||
this.index++;
|
||||
if (entry.post) entry.post.load(entry.before);
|
||||
if (entry.selection_post) entry.selection_post.load(entry.selection_before);
|
||||
if (Project.EditSession && remote !== true) {
|
||||
Project.EditSession.sendAll('command', 'redo')
|
||||
if (entry.post) {
|
||||
this.loadSave(entry.post, entry.before);
|
||||
}
|
||||
if (entry.selection_post instanceof UndoSystem.selectionSave) {
|
||||
entry.selection_post.load(entry.selection_before);
|
||||
}
|
||||
if (Project.EditSession && remote !== true && entry.type != 'selection') {
|
||||
Project.EditSession.sendAll('command', 'redo');
|
||||
}
|
||||
Blockbench.dispatchEvent('redo', {entry})
|
||||
}
|
||||
remoteEdit(entry) {
|
||||
this.loadSave(entry.post, entry.before, 'session')
|
||||
this.loadSave(entry.post, entry.before, 'session');
|
||||
|
||||
if (entry.save_history !== false) {
|
||||
delete this.current_save;
|
||||
@ -228,18 +250,29 @@ class UndoSystem {
|
||||
return false;
|
||||
}
|
||||
loadSave(save, reference, mode) {
|
||||
if (save instanceof UndoSystem.save == false) {
|
||||
save = new UndoSystem.save().fromJSON(save);
|
||||
}
|
||||
save.load(reference, mode);
|
||||
}
|
||||
}
|
||||
UndoSystem.save = class {
|
||||
constructor(aspects) {
|
||||
|
||||
if (aspects) {
|
||||
this.fromState(aspects);
|
||||
}
|
||||
}
|
||||
fromJSON(data) {
|
||||
Object.assign(this, data);
|
||||
return this;
|
||||
}
|
||||
fromState(aspects) {
|
||||
var scope = this;
|
||||
this.aspects = aspects;
|
||||
|
||||
this.mode = Modes.selected.id;
|
||||
|
||||
if (aspects.selection) {
|
||||
/*if (aspects.selection) {
|
||||
this.selection = [];
|
||||
this.mesh_selection = {};
|
||||
selected.forEach(obj => {
|
||||
@ -251,8 +284,7 @@ UndoSystem.save = class {
|
||||
if (Group.multi_selected.length) {
|
||||
this.selected_groups = Group.multi_selected.map(g => g.uuid);
|
||||
}
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
if (aspects.elements) {
|
||||
this.elements = {}
|
||||
@ -367,6 +399,7 @@ UndoSystem.save = class {
|
||||
}
|
||||
|
||||
Blockbench.dispatchEvent('create_undo_save', {save: this, aspects})
|
||||
return this;
|
||||
}
|
||||
load(reference, mode) {
|
||||
let is_session = mode === 'session';
|
||||
@ -440,7 +473,7 @@ UndoSystem.save = class {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.selection && !is_session) {
|
||||
/*if (this.selection && !is_session) {
|
||||
selected.length = 0;
|
||||
Outliner.elements.forEach((obj) => {
|
||||
if (this.selection.includes(obj.uuid)) {
|
||||
@ -450,7 +483,7 @@ UndoSystem.save = class {
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}*/
|
||||
|
||||
if (this.groups) {
|
||||
for (let saved_group of this.groups) {
|
||||
@ -619,7 +652,7 @@ UndoSystem.save = class {
|
||||
if (this.animations) {
|
||||
for (var uuid in this.animations) {
|
||||
|
||||
var animation = (reference.animations && reference.animations[uuid]) ? this.getItemByUUID(Animator.animations, uuid) : null;
|
||||
var animation = (reference.animations && reference.animations[uuid]) ? Undo.getItemByUUID(Animator.animations, uuid) : null;
|
||||
if (!animation) {
|
||||
animation = new Animation()
|
||||
animation.uuid = uuid
|
||||
@ -631,7 +664,7 @@ UndoSystem.save = class {
|
||||
}
|
||||
for (var uuid in reference.animations) {
|
||||
if (!this.animations[uuid]) {
|
||||
var animation = this.getItemByUUID(Animator.animations, uuid)
|
||||
var animation = Undo.getItemByUUID(Animator.animations, uuid)
|
||||
if (animation) {
|
||||
animation.remove(false)
|
||||
}
|
||||
@ -641,7 +674,7 @@ UndoSystem.save = class {
|
||||
if (this.animation_controllers) {
|
||||
for (var uuid in this.animation_controllers) {
|
||||
|
||||
var controller = (reference.animation_controllers && reference.animation_controllers[uuid]) ? this.getItemByUUID(AnimationController.all, uuid) : null;
|
||||
var controller = (reference.animation_controllers && reference.animation_controllers[uuid]) ? Undo.getItemByUUID(AnimationController.all, uuid) : null;
|
||||
if (!controller) {
|
||||
controller = new AnimationController();
|
||||
controller.uuid = uuid;
|
||||
@ -653,7 +686,7 @@ UndoSystem.save = class {
|
||||
}
|
||||
for (var uuid in reference.animation_controllers) {
|
||||
if (!this.animation_controllers[uuid]) {
|
||||
var controller = this.getItemByUUID(AnimationController.all, uuid);
|
||||
var controller = Undo.getItemByUUID(AnimationController.all, uuid);
|
||||
if (controller) {
|
||||
controller.remove(false);
|
||||
}
|
||||
@ -790,7 +823,7 @@ UndoSystem.selectionSave = class {
|
||||
if (element instanceof Mesh) {
|
||||
this.geometry[element.uuid] = {
|
||||
faces: element.getSelectedFaces().slice(),
|
||||
edges: element.getSelectedEdges().slice(),
|
||||
edges: element.getSelectedEdges().map(edge => edge.slice()),
|
||||
vertices: element.getSelectedVertices().slice(),
|
||||
}
|
||||
} else if (element instanceof Cube && !element.box_uv) {
|
||||
@ -841,7 +874,7 @@ UndoSystem.selectionSave = class {
|
||||
|
||||
unselectAllElements();
|
||||
if (this.elements) {
|
||||
Outliner.selected.replace(this.elements.map(uuid => OutlinerNode.uuids[uuid]));
|
||||
Outliner.selected.replace(this.elements.map(uuid => OutlinerNode.uuids[uuid]).filter(element => element instanceof OutlinerElement));
|
||||
}
|
||||
if (this.groups) {
|
||||
for (let uuid of this.groups) {
|
||||
|
@ -111,6 +111,7 @@ Object.defineProperty(Array.prototype, "equals", {enumerable: false});
|
||||
//Array Vector
|
||||
Array.prototype.V3_set = function(x, y, z) {
|
||||
if (x instanceof Array) return this.V3_set(...x);
|
||||
if (x instanceof THREE.Vector3) return this.V3_set(x.x, x.y, x.z);
|
||||
if (y === undefined && z === undefined) z = y = x;
|
||||
this[0] = parseFloat(x)||0;
|
||||
this[1] = parseFloat(y)||0;
|
||||
|
156
js/util/json.js
Normal file
156
js/util/json.js
Normal file
@ -0,0 +1,156 @@
|
||||
function compileJSON(object, options = {}) {
|
||||
let indentation = options.indentation;
|
||||
if (typeof indentation !== 'string') {
|
||||
switch (settings.json_indentation.value) {
|
||||
case 'spaces_4': indentation = ' '; break;
|
||||
case 'spaces_2': indentation = ' '; break;
|
||||
case 'tabs': default: indentation = '\t'; break;
|
||||
}
|
||||
}
|
||||
function newLine(tabs) {
|
||||
if (options.small === true) {return '';}
|
||||
let s = '\n';
|
||||
for (let i = 0; i < tabs; i++) {
|
||||
s += indentation;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
function escape(string) {
|
||||
if (string.includes('\\')) {
|
||||
string = string.replace(/\\/g, '\\\\');
|
||||
}
|
||||
if (string.includes('"')) {
|
||||
string = string.replace(/"/g, '\\"');
|
||||
}
|
||||
if (string.includes('\n')) {
|
||||
string = string.replace(/\n|\r\n/g, '\\n');
|
||||
}
|
||||
if (string.includes('\t')) {
|
||||
string = string.replace(/\t/g, '\\t');
|
||||
}
|
||||
return string;
|
||||
}
|
||||
function handleVar(o, tabs, breaks = true) {
|
||||
var out = ''
|
||||
let type = typeof o;
|
||||
if (type === 'string') {
|
||||
//String
|
||||
out += '"' + escape(o) + '"'
|
||||
} else if (type === 'boolean') {
|
||||
//Boolean
|
||||
out += (o ? 'true' : 'false')
|
||||
} else if (o === null || o === Infinity || o === -Infinity) {
|
||||
//Null
|
||||
out += 'null'
|
||||
} else if (type === 'number') {
|
||||
//Number
|
||||
o = (Math.round(o*100000)/100000).toString()
|
||||
if (o == 'NaN') o = null
|
||||
out += o
|
||||
} else if (o instanceof Array) {
|
||||
//Array
|
||||
let has_content = false
|
||||
let multiline = !!o.find(item => typeof item === 'object');
|
||||
if (!multiline) {
|
||||
let length = 0;
|
||||
o.forEach(item => {
|
||||
length += typeof item === 'string' ? (item.length+4) : 3;
|
||||
});
|
||||
if (length > 140) multiline = true;
|
||||
}
|
||||
out += '['
|
||||
for (var i = 0; i < o.length; i++) {
|
||||
var compiled = handleVar(o[i], tabs+1)
|
||||
if (compiled) {
|
||||
if (has_content) {out += ',' + ((options.small || multiline) ? '' : ' ')}
|
||||
if (multiline) {out += newLine(tabs)}
|
||||
out += compiled
|
||||
has_content = true
|
||||
}
|
||||
}
|
||||
if (multiline) {out += newLine(tabs-1)}
|
||||
out += ']'
|
||||
} else if (type === 'object') {
|
||||
//Object
|
||||
breaks = breaks && o.constructor.name !== 'oneLiner';
|
||||
var has_content = false
|
||||
out += '{'
|
||||
for (var key in o) {
|
||||
if (o.hasOwnProperty(key)) {
|
||||
var compiled = handleVar(o[key], tabs+1, breaks)
|
||||
if (compiled) {
|
||||
if (has_content) {out += ',' + (breaks || options.small?'':' ')}
|
||||
if (breaks) {out += newLine(tabs)}
|
||||
out += '"' + escape(key) + '":' + (options.small === true ? '' : ' ')
|
||||
out += compiled
|
||||
has_content = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (breaks && has_content) {out += newLine(tabs-1)}
|
||||
out += '}'
|
||||
}
|
||||
return out;
|
||||
}
|
||||
let file = handleVar(object, 1);
|
||||
if ((settings.final_newline.value && options.final_newline != false) || options.final_newline == true) {
|
||||
file += '\n';
|
||||
}
|
||||
return file;
|
||||
}
|
||||
function autoParseJSON(data, feedback) {
|
||||
if (data.substr(0, 4) === '<lz>') {
|
||||
data = LZUTF8.decompress(data.substr(4), {inputEncoding: 'StorageBinaryString'})
|
||||
}
|
||||
if (data.charCodeAt(0) === 0xFEFF) {
|
||||
data = data.substr(1)
|
||||
}
|
||||
try {
|
||||
data = JSON.parse(data)
|
||||
} catch (err1) {
|
||||
data = data.replace(/\/\*[^(\*\/)]*\*\/|\/\/.*/g, '')
|
||||
try {
|
||||
data = JSON.parse(data)
|
||||
} catch (err) {
|
||||
if (feedback === false) return;
|
||||
if (data.match(/\n\r?[><]{7}/)) {
|
||||
Blockbench.showMessageBox({
|
||||
title: 'message.invalid_file.title',
|
||||
icon: 'fab.fa-git-alt',
|
||||
message: 'message.invalid_file.merge_conflict'
|
||||
})
|
||||
return;
|
||||
}
|
||||
let error_part = '';
|
||||
function logErrantPart(whole, start, length) {
|
||||
var line = whole.substr(0, start).match(/\n/gm)
|
||||
line = line ? line.length+1 : 1
|
||||
var result = '';
|
||||
var lines = whole.substr(start, length).split(/\n/gm)
|
||||
lines.forEach((s, i) => {
|
||||
result += `#${line+i} ${s}\n`
|
||||
})
|
||||
error_part = result.substr(0, result.length-1) + ' <-- HERE';
|
||||
console.log(error_part);
|
||||
}
|
||||
console.error(err)
|
||||
var length = err.toString().split('at position ')[1]
|
||||
if (length) {
|
||||
length = parseInt(length)
|
||||
var start = limitNumber(length-32, 0, Infinity)
|
||||
|
||||
logErrantPart(data, start, 1+length-start)
|
||||
} else if (err.toString().includes('Unexpected end of JSON input')) {
|
||||
|
||||
logErrantPart(data, data.length-16, 10)
|
||||
}
|
||||
Blockbench.showMessageBox({
|
||||
translateKey: 'invalid_file',
|
||||
icon: 'error',
|
||||
message: tl('message.invalid_file.message', [err]) + (error_part ? `\n\n\`\`\`\n${error_part}\n\`\`\`` : '')
|
||||
})
|
||||
return;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
@ -410,9 +410,9 @@ var Merge = {
|
||||
},
|
||||
molang(obj, source, index) {
|
||||
if (typeof source[index] == 'string') {
|
||||
obj[index] = source[index];
|
||||
obj[index] = source[index].replace(/-?\d\.\d+e-\d\d/g, '0');
|
||||
} else if (typeof source[index] == 'number') {
|
||||
obj[index] = source[index].toString();
|
||||
obj[index] = Math.roundTo(source[index], 9).toString();
|
||||
}
|
||||
},
|
||||
boolean(obj, source, index, validate) {
|
||||
@ -491,6 +491,21 @@ Object.defineProperty(String.prototype, 'hashCode', {
|
||||
return hash;
|
||||
}
|
||||
});
|
||||
function exportMolang(input) {
|
||||
if (!input) return 0;
|
||||
if (typeof input == 'string') {
|
||||
if (!isNaN(input)) {
|
||||
let num = parseFloat(input);
|
||||
return isNaN(num) ? 0 : num;
|
||||
} else {
|
||||
return input.replace(/\n/g, '');
|
||||
}
|
||||
} else if (typeof input == 'number') {
|
||||
return input;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// HTML
|
||||
function isNodeUnderCursor(node, event) {
|
||||
|
12
lang/cz.json
12
lang/cz.json
@ -2238,7 +2238,7 @@
|
||||
"settings.classroom_mode": "Classroom Mode",
|
||||
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
|
||||
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
|
||||
"settings.tone_mapping": "Tone Mapping",
|
||||
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
|
||||
"settings.audio_scrubbing": "Timline Scrubbing Audio",
|
||||
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "Longest Axis",
|
||||
"edit.vertex_snap.align.direction": "Direction from Pivot",
|
||||
"edit.vertex_snap.align.align_axis": "%0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore %0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore Axis",
|
||||
"codec.common.format": "Format",
|
||||
"codec.image.quality": "Quality",
|
||||
"panel.collections": "Collections",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Selection Tolerance",
|
||||
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
|
||||
"action.delete.keep_vertices": "Keep Edges/Vertices",
|
||||
"menu.mesh": "Mesh"
|
||||
"menu.mesh": "Mesh",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
10
lang/de.json
10
lang/de.json
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "Längste Achse",
|
||||
"edit.vertex_snap.align.direction": "Richtung vom Angelpunkt",
|
||||
"edit.vertex_snap.align.align_axis": "%0-Achse",
|
||||
"edit.vertex_snap.ignore_axis": "%0-Achse ignorieren",
|
||||
"edit.vertex_snap.ignore_axis": "Achse ignorieren",
|
||||
"codec.common.format": "Format",
|
||||
"codec.image.quality": "Qualität",
|
||||
"panel.collections": "Sammlungen",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Auswahltoleranz",
|
||||
"settings.selection_tolerance.desc": "Größe des Bereichs der zur Auswahl eines Eckpunktes oder einer Kante angeklickt werden kann",
|
||||
"action.delete.keep_vertices": "Kanten/Eckpunkte behalten",
|
||||
"menu.mesh": "Masche"
|
||||
"menu.mesh": "Masche",
|
||||
"dialog.material_config.subsurface": "Volumenstreuung",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Verwende den Transparenzkanal der MER Map für Volumenstreuung",
|
||||
"settings.pick_combined_color": "Farbkombination auswählen",
|
||||
"settings.pick_combined_color.desc": "Mit der Farbpipette die kombinierte Farbe aller Ebenen auswählen, an Stelle von der Farbe der ausgewählten Ebene",
|
||||
"action.split_rgb_into_layers": "RGB Farbkanäle in Ebenen aufteilen",
|
||||
"action.split_rgb_into_layers.desc": "Teile die Textur in eine additive Ebene pro RGB Farbkanal auf"
|
||||
}
|
10
lang/en.json
10
lang/en.json
@ -521,6 +521,8 @@
|
||||
"dialog.material_config.color_value": "Color Value",
|
||||
"dialog.material_config.mer": "Metal-Emissive-Roughness",
|
||||
"dialog.material_config.mer_value": "MER Value",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"dialog.material_config.depth_type": "Depth Type",
|
||||
|
||||
"dialog.edit_texture.preview": "Preview",
|
||||
@ -949,7 +951,7 @@
|
||||
"settings.antialiasing": "Anti-aliasing",
|
||||
"settings.antialiasing.desc": "Toggle anti-aliasing in the preview",
|
||||
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
|
||||
"settings.render_sides": "Render Sides",
|
||||
"settings.tone_mapping": "Tone Mapping",
|
||||
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
|
||||
@ -1079,6 +1081,8 @@
|
||||
"settings.color_wheel.desc": "Use the color wheel as the main color picker",
|
||||
"settings.pick_color_opacity": "Pick Color Opacity",
|
||||
"settings.pick_color_opacity.desc": "Pick the color opacity with the Color Picker and set it as brush opacity",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"settings.brush_cursor_2d": "2D Brush Cursor",
|
||||
"settings.brush_cursor_2d.desc": "Display an outline around the brush in the 2D workspace",
|
||||
"settings.brush_cursor_3d": "3D Brush Cursor",
|
||||
@ -1659,6 +1663,8 @@
|
||||
"action.adjust_curves.desc": "Adjust the brightness curves of the selected texture",
|
||||
"action.limit_to_palette": "Limit to Palette",
|
||||
"action.limit_to_palette.desc": "Limits the colors of the texture to those in the currently loaded palette",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel",
|
||||
"action.clear_unused_texture_space": "Clear Unused Texture Space",
|
||||
"action.clear_unused_texture_space.desc": "Clear parts of the texture that are not UV-mapped to any elements",
|
||||
"action.flip_texture_x": "Flip Horizontally",
|
||||
@ -2278,7 +2284,7 @@
|
||||
"edit.vertex_snap.align.longest": "Longest Axis",
|
||||
"edit.vertex_snap.align.direction": "Direction from Pivot",
|
||||
"edit.vertex_snap.align.align_axis": "%0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore %0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore Axis",
|
||||
|
||||
"web.download_app": "Download App",
|
||||
|
||||
|
160
lang/es.json
160
lang/es.json
@ -14,7 +14,7 @@
|
||||
"data.preview": "Previsualización",
|
||||
"data.toolbar": "Barra de herramientas",
|
||||
"data.image": "Imagen",
|
||||
"keys.ctrl": "Control",
|
||||
"keys.ctrl": "Ctrl",
|
||||
"keys.shift": "Shift",
|
||||
"keys.alt": "Alt",
|
||||
"keys.meta": "CMD",
|
||||
@ -62,7 +62,7 @@
|
||||
"message.unsaved_textures.title": "Texturas sin guardar",
|
||||
"message.unsaved_textures.message": "Tu modelo tiene texturas sin guardar. Asegúrate de guardarlas en la carpeta correcta del paquete de recursos",
|
||||
"message.model_clipping.title": "Módelo muy grande",
|
||||
"message.model_clipping.message": "Tu modelo contiene %0 cubos que son más grandes que el límite de 3x3x3 bloques establecido por Minecraft. Este modelo no funcionará en Minecraft.",
|
||||
"message.model_clipping.message": "Tu modelo contiene %0 cubos que son más grandes que el límite de bloques establecido por Minecraft. Este modelo no funcionará en Minecraft.",
|
||||
"message.loose_texture.title": "Importar Textura",
|
||||
"message.loose_texture.message": "La texture importada no forma parte de un Resource Pack. Minecraft sólo puede cargar texturas dentro de una carpeta de textures en un Resource Pack cargado.",
|
||||
"message.loose_texture.change": "Cambiar directorio",
|
||||
@ -81,9 +81,9 @@
|
||||
"message.image_editor.title": "Selecciona un editor de imágenes",
|
||||
"message.image_editor.file": "Seleccionar archivo...",
|
||||
"message.image_editor.exe": "Seleccionar el ejecutable de un editor de imágenes",
|
||||
"message.display_skin.title": "Mostrar Skin",
|
||||
"message.display_skin.title": "Skin de Minecraft",
|
||||
"message.display_skin.message": "Selecciona un archivo de una skin de tu ordenador o escribe el nombre de un jugador",
|
||||
"message.display_skin.upload": "Subir Skin",
|
||||
"message.display_skin.upload": "Seleccionar Archivo",
|
||||
"message.display_skin.reset": "Restablecer",
|
||||
"message.invalid_plugin": "Archivo de plugin inválido, lee la Consola",
|
||||
"message.load_plugin_app": "¿Quieres permitir a este plugin que haga cambios a tu PC? Carga sólo plugins de personas en las que confíes.",
|
||||
@ -94,7 +94,7 @@
|
||||
"dialog.project.title": "Proyecto",
|
||||
"dialog.project.name": "Nombre de Archivo",
|
||||
"dialog.project.parent": "Modelo Padre",
|
||||
"dialog.project.geoname": "Nombre de la Geometría del Mob",
|
||||
"dialog.project.geoname": "Identificador del Modelo",
|
||||
"dialog.project.ao": "Oclusión Ambiental",
|
||||
"dialog.texture.title": "Textura",
|
||||
"dialog.texture.variable": "Variable",
|
||||
@ -114,7 +114,7 @@
|
||||
"dialog.select.title": "Seleccionar",
|
||||
"dialog.select.group": "En el Grupo Seleccionado",
|
||||
"dialog.select.name": "El Nombre Contiene",
|
||||
"dialog.select.random": "Aleatorio",
|
||||
"dialog.select.random": "Oportunidad Aleatoria (%)",
|
||||
"dialog.select.select": "Seleccionar",
|
||||
"dialog.scale.title": "Reescalar Modelo",
|
||||
"dialog.scale.axis": "Ejes",
|
||||
@ -160,7 +160,7 @@
|
||||
"layout.color.light": "Claro",
|
||||
"layout.color.light.desc": "Texto destacado",
|
||||
"layout.color.accent_text": "Acento del texto",
|
||||
"layout.color.accent_text.desc": "Texto en elementos claros o acentuados",
|
||||
"layout.color.accent_text.desc": "Texto sobre fondos con acento",
|
||||
"layout.font.main": "Fuente principal",
|
||||
"layout.font.headline": "Fuente para títulos",
|
||||
"about.version": "Versión:",
|
||||
@ -173,28 +173,28 @@
|
||||
"settings.category.dialogs": "Diálogos",
|
||||
"settings.category.export": "Exportar",
|
||||
"settings.language": "Lenguaje",
|
||||
"settings.language.desc": "Lenguaje de la interfaz. Reinicia Blockbench para aplicar los cambios.",
|
||||
"settings.language.desc": "Lenguaje de Interfaz",
|
||||
"settings.backup_interval": "Intervalo de Respaldos",
|
||||
"settings.backup_interval.desc": "Intervalo de los respaldos automáticos en minutos",
|
||||
"settings.origin_size": "Marcador de Pivote",
|
||||
"settings.origin_size.desc": "Tamaño del marcador del punto de pivote",
|
||||
"settings.control_size": "Tamaño del control de los ejes",
|
||||
"settings.control_size.desc": "Tamaño de la herramienta de control de los 3 ejes",
|
||||
"settings.display_skin": "Mostrar Skin",
|
||||
"settings.display_skin.desc": "Skin usada para la referencia del modelo de jugador",
|
||||
"settings.control_size": "Transformar el tamaño del artilugio",
|
||||
"settings.control_size.desc": "Tamaño del artilugio de transformación",
|
||||
"settings.display_skin": "Skin de Minecraft",
|
||||
"settings.display_skin.desc": "Skin usada para la referencia del modelo jugador",
|
||||
"settings.shading": "Sombreado",
|
||||
"settings.shading.desc": "Activar sombreado",
|
||||
"settings.shading.desc": "Habilitar sombreado en vista previa",
|
||||
"settings.texture_fps": "FPS de las Texturas Animadas",
|
||||
"settings.texture_fps.desc": "Cuadros por segundo para texturas animadas",
|
||||
"settings.base_grid": "Cuadrícula Pequeña",
|
||||
"settings.base_grid.desc": "Mostrar cuadrícula y ejes pequeños",
|
||||
"settings.large_grid": "Cuadrícula Grande",
|
||||
"settings.large_grid.desc": "Mostrar cuadrícula de 3x3",
|
||||
"settings.full_grid": "Cuadrícula Muy Grande",
|
||||
"settings.full_grid.desc": "Mostar cuadrícula precisa de 3x3",
|
||||
"settings.large_box": "Caja grande",
|
||||
"settings.large_box.desc": "Mostrar los límites de 3x3x3",
|
||||
"settings.display_grid": "Modo de visualización",
|
||||
"settings.large_grid": "Cuadrícula de bloques",
|
||||
"settings.large_grid.desc": "Mostrar cuadrícula de 16x16 bloques",
|
||||
"settings.full_grid": "Cuadrícula de bloques precisa",
|
||||
"settings.full_grid.desc": "Mostrar cuadrícula de bloques con precisión de píxeles",
|
||||
"settings.large_box": "Caja con límite de tamaño",
|
||||
"settings.large_box.desc": "Mostrar límites de tamaño",
|
||||
"settings.display_grid": "Modo de Visualización Cuadrícula",
|
||||
"settings.display_grid.desc": "Mostrar cuadrícula en el modo de visualización",
|
||||
"settings.undo_limit": "Límite de deshacer",
|
||||
"settings.undo_limit.desc": "Número de acciones que puedes deshacer",
|
||||
@ -209,7 +209,7 @@
|
||||
"settings.create_rename": "Renombrar Nuevo Elemento",
|
||||
"settings.create_rename.desc": "Campo de nombre de enfoque al crear nuevo elemento o grupo",
|
||||
"settings.edit_size": "Resolución de la Cuadrícula",
|
||||
"settings.edit_size.desc": "Resolución de la cuadrícula a la que se engancha el cubo",
|
||||
"settings.edit_size.desc": "Resolución de la cuadrícula a la que se ajustan los elementos",
|
||||
"settings.shift_size": "Resolución de Shift",
|
||||
"settings.shift_size.desc": "Resolución de la cuadrícula al mantener Shift",
|
||||
"settings.ctrl_size": "Resolución de Control",
|
||||
@ -217,9 +217,9 @@
|
||||
"settings.negative_size": "Tamaño Negativo",
|
||||
"settings.negative_size.desc": "Permitir a la herramienta de reescalado usar tamaños negativos",
|
||||
"settings.minifiedout": "Exportación minimizada",
|
||||
"settings.minifiedout.desc": "Escribir el archivo JSON en una sola línea",
|
||||
"settings.minifiedout.desc": "Escribir archivos JSON en una línea",
|
||||
"settings.export_groups": "Exportar Grupos en modelos item/bloque de Java",
|
||||
"settings.export_groups.desc": "Guardar grupos en modelos de bloques",
|
||||
"settings.export_groups.desc": "Guardar grupos en archivos JSON de bloques java o modelos de item",
|
||||
"settings.credit": "Comentario de Créditos",
|
||||
"settings.credit.desc": "Añadir un comentario de créditos a archivos exportados",
|
||||
"settings.default_path": "Directorio por defecto de las texturas de Minecraft",
|
||||
@ -250,13 +250,13 @@
|
||||
"action.slider_brush_softness": "Suavidad",
|
||||
"action.slider_brush_softness.desc": "Suavidad del pincel en porcentaje",
|
||||
"action.uv_slider_pos_x": "Mover Horizontal",
|
||||
"action.uv_slider_pos_x.desc": "Mover la selección del UV de todos los cubos seleccionados horizontalmente",
|
||||
"action.uv_slider_pos_x.desc": "Mover horizontalmente todas las caras UV seleccionadas",
|
||||
"action.uv_slider_pos_y": "Mover Vertical",
|
||||
"action.uv_slider_pos_y.desc": "Mover la selección del UV de todos los cubos seleccionados verticalmente",
|
||||
"action.uv_slider_size_x": "Reescalar Horizontal",
|
||||
"action.uv_slider_size_x.desc": "Reescalar la selección del UV de todos los cubos seleccionados horizontalmente",
|
||||
"action.uv_slider_size_y": "Reescalar Vertical",
|
||||
"action.uv_slider_size_y.desc": "Reescalar la selección del UV de todos los cubos seleccionados verticalmente",
|
||||
"action.uv_slider_pos_y.desc": "Mover verticalmente todas las caras UV seleccionadas",
|
||||
"action.uv_slider_size_x": "Tamaño Horizontal",
|
||||
"action.uv_slider_size_x.desc": "Redimensionar horizontalmente todas las caras UV seleccionadas",
|
||||
"action.uv_slider_size_y": "Tamaño Vertical",
|
||||
"action.uv_slider_size_y.desc": "Redimensionar verticalmente todas las caras UV seleccionadas",
|
||||
"action.vertex_snap_mode": "Modo Imán",
|
||||
"action.vertex_snap_mode.desc": "Seleccionar si el Imán para Vertices mueve los elementos a la posición seleccionada o si los reescala",
|
||||
"action.move_tool": "Mover",
|
||||
@ -264,7 +264,7 @@
|
||||
"action.resize_tool": "Reescalar",
|
||||
"action.resize_tool.desc": "Herramienta para seleccionar y reescalar elementos",
|
||||
"action.brush_tool": "Pincel de pintura",
|
||||
"action.brush_tool.desc": "Herramienta para pintar en texturas bitmap en superficies o en el editor de UV",
|
||||
"action.brush_tool.desc": "Pincel de color para dibujar sobre texturas",
|
||||
"action.vertex_snap_tool": "Imán para Vértices",
|
||||
"action.vertex_snap_tool.desc": "Mover un cubo a otro cubo al conectar 2 vértices",
|
||||
"action.swap_tools": "Cambiar Herramientas",
|
||||
@ -275,14 +275,14 @@
|
||||
"action.open_model.desc": "Abre un archivo de modelo de tu ordenador",
|
||||
"action.extrude_texture": "Textura Extruida",
|
||||
"action.extrude_texture.desc": "General un modelo al extender una textura",
|
||||
"action.export_blockmodel": "Exportar Modelo de Bloque",
|
||||
"action.export_blockmodel.desc": "Exporta un modelo de bloque o de ítem",
|
||||
"action.export_blockmodel": "Exportar modelo de bloque/item",
|
||||
"action.export_blockmodel.desc": "Exportar un modelo de bloque o de item de Minecraft Java Edition",
|
||||
"action.export_optifine_part": "Exportar Parte de Optifine",
|
||||
"action.export_optifine_part.desc": "Exportar una sola parte para un modelo de entidad de OptiFine",
|
||||
"action.export_optifine_full": "Exportar a OptiFine JEM",
|
||||
"action.export_optifine_full.desc": "Exportar un modelo completo de entidad de OptiFine",
|
||||
"action.export_obj": "Exportar Modelo OBJ",
|
||||
"action.export_obj.desc": "Exportar a un modelo Wavefront OBJ para renderizar o motores de juego",
|
||||
"action.export_obj.desc": "Exportar un modelo Wavefront OBJ para su renderización",
|
||||
"action.settings_window": "Ajustes...",
|
||||
"action.settings_window.desc": "Abre la ventana de ajustes de Blockbench",
|
||||
"action.plugins_window": "Plugins...",
|
||||
@ -310,33 +310,33 @@
|
||||
"action.outliner_toggle": "Activar Más Opciones",
|
||||
"action.outliner_toggle.desc": "Cambia los botones para más opciones en el Esquema",
|
||||
"action.duplicate": "Duplicar",
|
||||
"action.duplicate.desc": "Duplica los grupos o cubos seleccionados",
|
||||
"action.duplicate.desc": "Duplica los elementos o el grupo seleccionados",
|
||||
"action.delete": "Borrar",
|
||||
"action.delete.desc": "Borra los grupos o cubos seleccionados",
|
||||
"action.delete.desc": "Elimina los elementos o el grupo seleccionados",
|
||||
"action.sort_outliner": "Ordenar Esquema",
|
||||
"action.sort_outliner.desc": "Ordena el esquema alfabéticamente",
|
||||
"action.select_window": "Seleccionar...",
|
||||
"action.select_window.desc": "Busca y selecciona cubos basados en sus propiedades",
|
||||
"action.select_window.desc": "Busca y seleccionar elementos basados en sus propiedades",
|
||||
"action.invert_selection": "Invertir Selección",
|
||||
"action.invert_selection.desc": "Invierte la selección actual de los cubos",
|
||||
"action.invert_selection.desc": "Invertir la selección actual de elementos",
|
||||
"action.select_all": "Seleccionar Todo",
|
||||
"action.select_all.desc": "Selecciona todos los elementos, caras, vértices, o fotogramas",
|
||||
"action.collapse_groups": "Colapsar Grupos",
|
||||
"action.collapse_groups.desc": "Colapsa todos los grupos",
|
||||
"action.collapse_groups.desc": "Contraer todos los grupos del esquema",
|
||||
"action.scale": "Reescalar...",
|
||||
"action.scale.desc": "Reescala los cubos seleccionados",
|
||||
"action.scale.desc": "Escalar los elementos seleccionados",
|
||||
"action.toggle_visibility": "Cambiar Visibilidad",
|
||||
"action.toggle_visibility.desc": "Cambia el ajuste de visibilidad de los cubos seleccionados.",
|
||||
"action.toggle_visibility.desc": "Cambiar la visibilidad de los elementos seleccionados",
|
||||
"action.toggle_export": "Cambiar Exportación",
|
||||
"action.toggle_export.desc": "Cambia el ajuste de exportación de los cubos seleccionados",
|
||||
"action.toggle_export.desc": "Cambia el ajuste de exportación de los elementos seleccionados",
|
||||
"action.toggle_autouv": "Cambiar Auto UV",
|
||||
"action.toggle_autouv.desc": "Cambia el ajuste de Auto UV de los cubos seleccionados",
|
||||
"action.toggle_autouv.desc": "Cambia el ajuste de Auto UV de los elementos seleccionados",
|
||||
"action.toggle_shade": "Cambiar Sombreado",
|
||||
"action.toggle_shade.desc": "Cambia el ajuste de sombreado de los cubos seleccionados",
|
||||
"action.toggle_shade.desc": "Cambia el ajuste de sombreado de los elementos seleccionados",
|
||||
"action.rename": "Renombrar",
|
||||
"action.rename.desc": "Cambia el nombre de los cubos seleccionados",
|
||||
"action.rename.desc": "Cambia el nombre de los elementos seleccionados",
|
||||
"action.add_display_preset": "Nueva Plantilla",
|
||||
"action.add_display_preset.desc": "Añade una nueva plantilla de ajustes de visualización",
|
||||
"action.add_display_preset.desc": "Añadir un nuevo pre-ajuste de visualización",
|
||||
"action.fullscreen": "Pantalla Completa",
|
||||
"action.fullscreen.desc": "Cambia el modo de pantalla completa",
|
||||
"action.zoom_in": "Hacer zoom",
|
||||
@ -395,8 +395,8 @@
|
||||
"menu.texture.file": "Archivo",
|
||||
"menu.texture.refresh": "Refrescar",
|
||||
"menu.texture.change": "Cambiar Archivo",
|
||||
"menu.texture.folder": "Abrir en Carpeta",
|
||||
"menu.texture.edit": "Editar Externamente",
|
||||
"menu.texture.folder": "Mostrar en el Explorador de archivos",
|
||||
"menu.texture.edit": "Editar",
|
||||
"menu.texture.export": "Guardar Como",
|
||||
"menu.texture.save": "Guardar",
|
||||
"menu.texture.properties": "Propiedades",
|
||||
@ -460,7 +460,7 @@
|
||||
"display.reference.baby_zombie": "Zombie bebé",
|
||||
"display.reference.armor_stand_small": "Armor Stand Pequeño",
|
||||
"display.reference.monitor": "Normal",
|
||||
"display.reference.bow": "Arco",
|
||||
"display.reference.bow": "Arco Cargado",
|
||||
"display.reference.block": "Bloque",
|
||||
"display.reference.frame": "Marco de Ítems",
|
||||
"display.reference.inventory_nine": "3x3",
|
||||
@ -483,7 +483,7 @@
|
||||
"action.change_textures_folder.desc": "Cambia la carpeta que en la que se guardan todas las texturas",
|
||||
"menu.texture.particle": "Usar para Partículas",
|
||||
"message.update_notification.title": "No fue posible Instalar la Actualización",
|
||||
"message.update_notification.message": "Una nueva versión está disponible. ¡Active Actualizaciones Automáticas para actualizar!",
|
||||
"message.update_notification.message": "Una nueva versión de Blockbench está disponible. ¡Active Actualizaciones Automáticas para actualizar!",
|
||||
"message.untextured": "La superficie no tiene una textura",
|
||||
"dialog.toolbar_edit.title": "Personalizar Barra de Herramientas",
|
||||
"keybindings.reset": "Resetear",
|
||||
@ -504,7 +504,7 @@
|
||||
"action.uv_mirror_x.desc": "Invierte el UV de esta cara en el eje X",
|
||||
"action.uv_mirror_y": "Invertir UV en Y",
|
||||
"action.uv_mirror_y.desc": "Invierte el UV de esta cara en el eje Y",
|
||||
"action.uv_transparent": "Cara Transparente",
|
||||
"action.uv_transparent": "Eliminar cara",
|
||||
"action.uv_transparent.desc": "Convierte la cara actual en transparente",
|
||||
"action.uv_reset": "Resetear Cara",
|
||||
"action.uv_reset.desc": "Resetea la cara actual",
|
||||
@ -550,7 +550,7 @@
|
||||
"action.move_right": "Mover Hacia Derecha",
|
||||
"action.move_right.desc": "Mueve los cubos seleccionados hacia la derecha relativo al ángulo actual de la cámara",
|
||||
"action.move_forth": "Mover Hacia Delante",
|
||||
"action.move_forth.desc": "Mueve los cubos seleccionados hacia delante relativo al ángulo actual de la cámara",
|
||||
"action.move_forth.desc": "Mueva los elementos seleccionados hacia adelante en relación con el ángulo actual de la cámara",
|
||||
"action.move_back": "Mover Hacia Atrás",
|
||||
"action.move_back.desc": "Mueve los cubos seleccionados hacia atrás relativo al ángulo actual de la cámara",
|
||||
"layout.color.wireframe": "Estructura",
|
||||
@ -579,7 +579,7 @@
|
||||
"action.delete_keyframes": "Eliminar Fotogramas Clave",
|
||||
"action.delete_keyframes.desc": "Elimina todos los fotogramas clave seleccionados",
|
||||
"menu.animation": "Animación",
|
||||
"menu.animation.loop": "Repetición",
|
||||
"menu.animation.loop": "Modo de bucle",
|
||||
"menu.animation.override": "Sobreescribir",
|
||||
"menu.animation.anim_time_update": "Actualizar Variable",
|
||||
"message.display_skin_model.title": "Modelo de Skin",
|
||||
@ -595,9 +595,9 @@
|
||||
"dialog.create_gif.title": "Grabar GIF",
|
||||
"dialog.create_gif.length": "Duración",
|
||||
"dialog.create_gif.fps": "FPS",
|
||||
"dialog.create_gif.play": "Empezar Animación",
|
||||
"dialog.create_gif.play": "Reproducir Animación",
|
||||
"category.animation": "Animación",
|
||||
"action.record_model_gif": "Grabar GIF",
|
||||
"action.record_model_gif": "Grabar GIF...",
|
||||
"action.record_model_gif.desc": "Graba un GIF animado de este modelo desde este ángulo",
|
||||
"display.mirror": "Invertir",
|
||||
"data.separator": "Separador",
|
||||
@ -611,8 +611,8 @@
|
||||
"mode.paint": "Pintar",
|
||||
"mode.display": "Mostrar",
|
||||
"mode.animate": "Animar",
|
||||
"status_bar.recording_gif": "Grabando GIF",
|
||||
"status_bar.processing_gif": "Procesando GIF",
|
||||
"status_bar.recording_gif": "Grabando",
|
||||
"status_bar.processing_gif": "Procesando",
|
||||
"settings.backup_retain": "Mantenimiento de Respaldos",
|
||||
"settings.backup_retain.desc": "Ajustar cuanto tiempo Blockbench mantiene respaldos viejos en días",
|
||||
"action.rotate_tool": "Rotar",
|
||||
@ -631,7 +631,7 @@
|
||||
"menu.preview.perspective.reset": "Resetear Cámara",
|
||||
"action.fill_mode": "Modo de Llenado",
|
||||
"action.fill_mode.face": "Cara",
|
||||
"action.fill_mode.color": "Color",
|
||||
"action.fill_mode.color": "Colores",
|
||||
"action.toggle_mirror_uv": "Invertir UV",
|
||||
"action.toggle_mirror_uv.desc": "Activa el invertido de UV en el eje X de los cubos seleccionados",
|
||||
"menu.texture.blank": "Aplicar a Caras sin Textura",
|
||||
@ -673,7 +673,7 @@
|
||||
"action.element_colors.desc": "Muestra los colores de cubo en el borde",
|
||||
"texture.error.file": "Archivo no encontrado",
|
||||
"texture.error.parent": "Archivo de textura proveído por el modelo padre",
|
||||
"message.recover_backup.title": "Recuperar Modelo",
|
||||
"message.recover_backup.title": "Recuperar Modelos",
|
||||
"message.recover_backup.message": "Blockbench fue cerrado sin guardar. ¿Quieres recuperar el modelo?",
|
||||
"message.invalid_session.title": "Token de Sesión Inválido",
|
||||
"message.invalid_session.message": "La sesión a la que estas intentando entrar ha expirado o el token proveído es inválido.",
|
||||
@ -718,7 +718,7 @@
|
||||
"format.java_block": "Item/Bloque de Java",
|
||||
"format.java_block.desc": "Modelo de bloque o item para la edición Java.",
|
||||
"format.bedrock": "Entidad de Bedrock",
|
||||
"format.bedrock.desc": "Modelo para la edición Bedrock.",
|
||||
"format.bedrock.desc": "Modelo de Minecraft Bedrock Edition para entidades y objetos acoplables",
|
||||
"format.bedrock_old": "Modelo Antiguo de Bedrock",
|
||||
"format.bedrock_old.desc": "Modelo de entidad de las ediciones de Bedrock anteriores a 1.12",
|
||||
"format.modded_entity": "Entidad de Mod",
|
||||
@ -762,7 +762,7 @@
|
||||
"action.remove_blank_faces.desc": "Elimina todas las caras sin textura de la selección",
|
||||
"web.download_app": "Descargar Aplicación",
|
||||
"uv_editor.turned": "Mapeado Girado",
|
||||
"display.reference.crossbow": "Ballesta",
|
||||
"display.reference.crossbow": "Ballesta Cargada",
|
||||
"dialog.settings.search_results": "Resultados de Búsqueda",
|
||||
"settings.animation_snap": "Imán de Animación",
|
||||
"settings.animation_snap.desc": "Intervalo del imán para fotogramas clave en la línea de tiempo de la animación en pasos por segundo. Esto puede ser modificado para cada animación. El valor por defecto es 24.",
|
||||
@ -801,9 +801,9 @@
|
||||
"message.removed_faces": "Eliminadas %0 caras",
|
||||
"dialog.sketchfab_uploader.draft": "Borrador",
|
||||
"action.slider_pos": "Mover %0",
|
||||
"action.slider_pos.desc": "Mover cubos en el eje %0",
|
||||
"action.slider_pos.desc": "Mover elementos en el eje %0",
|
||||
"action.slider_size": "Tamaño %0",
|
||||
"action.slider_size.desc": "Redimensionar cubos en el eje %0",
|
||||
"action.slider_size.desc": "Redimensionar elementos en el eje %0",
|
||||
"action.slider_rotation": "Rotar %0",
|
||||
"action.slider_rotation.desc": "Rotar cubos en el eje %0",
|
||||
"action.slider_origin": "Pivote %0",
|
||||
@ -885,7 +885,7 @@
|
||||
"format.skin.desc": "Editar las skins de entidades y jugadores",
|
||||
"message.sketchfab.setup_guide": "¿Quieres aprender a preparar modelos en Sketchfab? Lee %0",
|
||||
"dialog.skin.title": "Crear Skin",
|
||||
"dialog.skin.model": "Skin",
|
||||
"dialog.skin.model": "Modelo",
|
||||
"dialog.skin.texture": "Textura (Opcional)",
|
||||
"action.toggle_skin_layer": "Cambiar Capa de Skin",
|
||||
"action.toggle_skin_layer.desc": "Cambia la capa del gorro y de la ropa en el modelo de skin",
|
||||
@ -1070,7 +1070,7 @@
|
||||
"settings.motion_trails": "Senderos de movimiento",
|
||||
"settings.motion_trails.desc": "Mostrar senderos de movimiento en el editor de animación",
|
||||
"settings.antialiasing": "Anti-aliasing",
|
||||
"settings.antialiasing.desc": "Modificar el anti-aliassing en la vista previa. Debes reiniciar Blockbench para aplicar los cambios",
|
||||
"settings.antialiasing.desc": "Alternar el anti-aliasing en la vista previa",
|
||||
"action.timeline_frame_back": "Avanza un fotograma atras",
|
||||
"action.timeline_frame_forth": "Avanza un fotograma adelante",
|
||||
"panel.bone.ik": "Cinemáticas inversas (Experimental)",
|
||||
@ -1078,7 +1078,7 @@
|
||||
"settings.particle_tick_rate.desc": "Efectos de partículas en la tasa de tic por segundo. El defecto es 30",
|
||||
"action.lock_motion_trail": "Bloquear el rastro de movimiento",
|
||||
"action.lock_motion_trail.desc": "Bloquear el rastro de movimiento en el grupo seleccionado",
|
||||
"menu.animation_file.unload": "Descargar archivo de animación",
|
||||
"menu.animation_file.unload": "Descargar archivo",
|
||||
"data.null_object": "Objeto Nulo",
|
||||
"status_bar.toggle_sidebar": "Mostrarbarralateral",
|
||||
"message.load_plugin_failed.title": "Falló al cargar el plugin",
|
||||
@ -1098,7 +1098,7 @@
|
||||
"settings.ctrl_shift_size": "Resolución de Control + Shift",
|
||||
"settings.ctrl_shift_size.desc": "Resolución del mapa mientras mantienes presionado control y shift",
|
||||
"settings.hardware_acceleration": "Aceleración de Hardware",
|
||||
"settings.hardware_acceleration.desc": "Subcontrato en tareas de renderizado a la tarjeta gráfica. Reinicia Blockbench para aplicar los cambios",
|
||||
"settings.hardware_acceleration.desc": "Subcontratar tareas de renderizado a la tarjeta gráfica",
|
||||
"action.explode_skin_model": "Expandir Modelo de Skin",
|
||||
"action.explode_skin_model.desc": "Alternar a una vista de explosión que le permite editar caras cubiertas",
|
||||
"action.export_minecraft_skin": "Exportar Skin de Minecraft",
|
||||
@ -1175,7 +1175,7 @@
|
||||
"action.load_keymap.cinema4d.desc": "Mapa de Teclas para usuarios que están familiarizados con los controles de Cinema 4D",
|
||||
"action.load_keymap.maya.desc": "Mapa de Teclas para usuarios que estan familiarizados con los controles de Autodek Maya",
|
||||
"action.import_keymap": "Importar Mapa de Teclas",
|
||||
"action.import_keymap.desc": "Importar atajos de teclado como un archivo .bbkeymap",
|
||||
"action.import_keymap.desc": "Importar atajos de teclado a un archivo .bbkeymap",
|
||||
"action.export_keymap": "Exportar Mapa de Teclas",
|
||||
"action.export_keymap.desc": "Exportar los actuales atajos de teclado como un archivo .bbkeymap",
|
||||
"action.edit_history": "Editar Historial...",
|
||||
@ -1229,7 +1229,7 @@
|
||||
"message.invalid_link": "Link del Modelo Inválido o Expirado",
|
||||
"message.default_textures.current": "Ruta actual",
|
||||
"message.update_after_restart": "La actualización será instalada después del próximo reinicio",
|
||||
"message.copy_paste_tool_viewport": "Este objeto solo puede usarse en el panel UV",
|
||||
"message.copy_paste_tool_viewport": "Esta herramienta sólo puede utilizarse en el editor 2D",
|
||||
"dialog.project.shadow_size": "Tamaño de la Sombra",
|
||||
"dialog.find_replace.target": "Objetivo",
|
||||
"dialog.find_replace.target.element_names": "Nombres de los Elementos",
|
||||
@ -1246,22 +1246,22 @@
|
||||
"dialog.add_primitive.shape.cylinder": "Cilindro",
|
||||
"dialog.add_primitive.shape.sphere": "Esfera",
|
||||
"dialog.add_primitive.shape.torus": "Toro",
|
||||
"dialog.add_primitive.shape.cube": "Cubo",
|
||||
"dialog.add_primitive.shape.cube": "Cuboide",
|
||||
"dialog.add_primitive.shape.pyramid": "Pirámide",
|
||||
"dialog.add_primitive.diameter": "Diámetro",
|
||||
"dialog.add_primitive.height": "Peso",
|
||||
"dialog.add_primitive.sides": "Lados",
|
||||
"dialog.add_primitive.minor_diameter": "Espesor",
|
||||
"dialog.add_primitive.minor_sides": "Lador Menores",
|
||||
"dialog.create_texture.combine_polys": "Combinar Caras",
|
||||
"dialog.create_texture.combine_polys.desc": "Combinar las caras conectadas en una en la sección UV",
|
||||
"dialog.create_texture.combine_polys": "Combinar islas",
|
||||
"dialog.create_texture.combine_polys.desc": "Combinar caras en islas UV conectadas",
|
||||
"dialog.model_stats.meshes": "Mallas",
|
||||
"dialog.export_private_settings.omit": "Salir",
|
||||
"layout.select": "Seleccionar",
|
||||
"layout.options": "Opciones",
|
||||
"layout.color": "Escama de color",
|
||||
"layout.documentation": "Documentación",
|
||||
"layout.color.bright_ui_text": "Interfaz clara",
|
||||
"layout.color.bright_ui_text": "Texto de interfaz brillante",
|
||||
"layout.color.bright_ui_text.desc": "Texto en fondos claros",
|
||||
"layout.name": "Nombre",
|
||||
"layout.author": "Autor",
|
||||
@ -1333,8 +1333,8 @@
|
||||
"action.split_mesh": "Separar mallas",
|
||||
"action.split_mesh.desc": "Separar las mallas seleccionadas en una nueva malla",
|
||||
"action.merge_vertices": "Combinar vértices",
|
||||
"action.merge_vertices.desc": "Combinar los vértices seleccionados en la posición del primer verted seleccionado",
|
||||
"action.view_mode.normal": "Cara normal",
|
||||
"action.merge_vertices.desc": "Fusionar los vértices seleccionados en la posición del primer vértice seleccionado",
|
||||
"action.view_mode.normal": "Orientación de la cara",
|
||||
"action.snap_uv_to_pixels": "Cambiar UV a píxeles",
|
||||
"action.snap_uv_to_pixels.desc": "Ajusta los vértices UV seleccionados a la cuadrícula de píxeles",
|
||||
"menu.file.import.import_open_project": "Importar proyecto abierto",
|
||||
@ -2238,7 +2238,7 @@
|
||||
"settings.classroom_mode": "Classroom Mode",
|
||||
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
|
||||
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
|
||||
"settings.tone_mapping": "Tone Mapping",
|
||||
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
|
||||
"settings.audio_scrubbing": "Timline Scrubbing Audio",
|
||||
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "Longest Axis",
|
||||
"edit.vertex_snap.align.direction": "Direction from Pivot",
|
||||
"edit.vertex_snap.align.align_axis": "%0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore %0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore Axis",
|
||||
"codec.common.format": "Format",
|
||||
"codec.image.quality": "Quality",
|
||||
"panel.collections": "Collections",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Selection Tolerance",
|
||||
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
|
||||
"action.delete.keep_vertices": "Keep Edges/Vertices",
|
||||
"menu.mesh": "Mesh"
|
||||
"menu.mesh": "Mesh",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
12
lang/fr.json
12
lang/fr.json
@ -2238,7 +2238,7 @@
|
||||
"settings.classroom_mode": "Classroom Mode",
|
||||
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
|
||||
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
|
||||
"settings.tone_mapping": "Tone Mapping",
|
||||
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
|
||||
"settings.audio_scrubbing": "Timline Scrubbing Audio",
|
||||
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "Longest Axis",
|
||||
"edit.vertex_snap.align.direction": "Direction from Pivot",
|
||||
"edit.vertex_snap.align.align_axis": "%0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore %0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore Axis",
|
||||
"codec.common.format": "Format",
|
||||
"codec.image.quality": "Quality",
|
||||
"panel.collections": "Collections",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Selection Tolerance",
|
||||
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
|
||||
"action.delete.keep_vertices": "Keep Edges/Vertices",
|
||||
"menu.mesh": "Mesh"
|
||||
"menu.mesh": "Mesh",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
3002
lang/it.json
3002
lang/it.json
File diff suppressed because it is too large
Load Diff
10
lang/ja.json
10
lang/ja.json
@ -2238,7 +2238,7 @@
|
||||
"settings.classroom_mode": "クラスルームモード",
|
||||
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
|
||||
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
|
||||
"settings.tone_mapping": "トーンマッピング",
|
||||
"settings.tone_mapping.desc": "PBR レンダリングにハイダイナミックレンジを表示します。",
|
||||
"settings.audio_scrubbing": "Timline Scrubbing Audio",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Selection Tolerance",
|
||||
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
|
||||
"action.delete.keep_vertices": "Keep Edges/Vertices",
|
||||
"menu.mesh": "Mesh"
|
||||
"menu.mesh": "メッシュ",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
16
lang/ko.json
16
lang/ko.json
@ -512,7 +512,7 @@
|
||||
"action.cullface.desc": "선택한 모델의 측면이 덮인 경우 이 면에 대한 렌더링 비활성화",
|
||||
"action.auto_cullface": "후면 제거 키기",
|
||||
"action.auto_cullface.desc": "이 표면의 후면 제거를 자체로 설정",
|
||||
"action.face_tint": "옅은 색",
|
||||
"action.face_tint": "색조",
|
||||
"action.face_tint.desc": "현재 표면에 대한 색조 옵션을 사용 가능으로 설정",
|
||||
"menu.toolbar.edit": "사용자 정의",
|
||||
"menu.toolbar.reset": "초기화",
|
||||
@ -2088,7 +2088,7 @@
|
||||
"action.slider_color_select_threshold.desc": "How close the color of a neighboring pixel has to be to get selected by color or wand select",
|
||||
"action.stretch_tool": "Stretch",
|
||||
"action.stretch_tool.desc": "Tool to select and stretch elements",
|
||||
"action.knife_tool": "Knife Tool",
|
||||
"action.knife_tool": "나이프 도구",
|
||||
"action.knife_tool.desc": "Tool to cut mesh faces into smaller pieces",
|
||||
"action.duplicate_project": "Duplicate Project",
|
||||
"action.duplicate_project.desc": "Creates a copy of the open project",
|
||||
@ -2238,7 +2238,7 @@
|
||||
"settings.classroom_mode": "Classroom Mode",
|
||||
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
|
||||
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
|
||||
"settings.tone_mapping": "Tone Mapping",
|
||||
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
|
||||
"settings.audio_scrubbing": "Timline Scrubbing Audio",
|
||||
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "Longest Axis",
|
||||
"edit.vertex_snap.align.direction": "Direction from Pivot",
|
||||
"edit.vertex_snap.align.align_axis": "%0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore %0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore Axis",
|
||||
"codec.common.format": "Format",
|
||||
"codec.image.quality": "Quality",
|
||||
"panel.collections": "Collections",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Selection Tolerance",
|
||||
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
|
||||
"action.delete.keep_vertices": "Keep Edges/Vertices",
|
||||
"menu.mesh": "Mesh"
|
||||
"menu.mesh": "Mesh",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
12
lang/nl.json
12
lang/nl.json
@ -2238,7 +2238,7 @@
|
||||
"settings.classroom_mode": "Classroom Mode",
|
||||
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
|
||||
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
|
||||
"settings.tone_mapping": "Tone Mapping",
|
||||
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
|
||||
"settings.audio_scrubbing": "Timline Scrubbing Audio",
|
||||
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "Longest Axis",
|
||||
"edit.vertex_snap.align.direction": "Direction from Pivot",
|
||||
"edit.vertex_snap.align.align_axis": "%0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore %0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore Axis",
|
||||
"codec.common.format": "Format",
|
||||
"codec.image.quality": "Quality",
|
||||
"panel.collections": "Collections",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Selection Tolerance",
|
||||
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
|
||||
"action.delete.keep_vertices": "Keep Edges/Vertices",
|
||||
"menu.mesh": "Mesh"
|
||||
"menu.mesh": "Mesh",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
12
lang/pl.json
12
lang/pl.json
@ -2238,7 +2238,7 @@
|
||||
"settings.classroom_mode": "Classroom Mode",
|
||||
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
|
||||
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
|
||||
"settings.tone_mapping": "Tone Mapping",
|
||||
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
|
||||
"settings.audio_scrubbing": "Timline Scrubbing Audio",
|
||||
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "Longest Axis",
|
||||
"edit.vertex_snap.align.direction": "Direction from Pivot",
|
||||
"edit.vertex_snap.align.align_axis": "%0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore %0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore Axis",
|
||||
"codec.common.format": "Format",
|
||||
"codec.image.quality": "Quality",
|
||||
"panel.collections": "Collections",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Selection Tolerance",
|
||||
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
|
||||
"action.delete.keep_vertices": "Keep Edges/Vertices",
|
||||
"menu.mesh": "Mesh"
|
||||
"menu.mesh": "Mesh",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
16
lang/pt.json
16
lang/pt.json
@ -222,7 +222,7 @@
|
||||
"settings.export_groups.desc": "Salvar grupos em modelos de bloco ou item",
|
||||
"settings.credit": "Comentário de crédito",
|
||||
"settings.credit.desc": "Adicionar um comentário de crédito aos arquivos exportados",
|
||||
"settings.default_path": "Default Minecraft Textures Path",
|
||||
"settings.default_path": "Caminho Padrão de Texturas do Minecraft",
|
||||
"settings.default_path.desc": "Pasta da qual o Blockbench carrega texturas padrão",
|
||||
"settings.image_editor": "Editor de imagem",
|
||||
"settings.image_editor.desc": "Editor de imagens padrão para editar texturas",
|
||||
@ -1699,7 +1699,7 @@
|
||||
"action.slider_color_red": "Color Red",
|
||||
"action.slider_color_green": "Color Green",
|
||||
"action.slider_color_blue": "Color Blue",
|
||||
"action.add_animation_controller": "Add Animation Controller",
|
||||
"action.add_animation_controller": "Adicionar Controlador de Animação",
|
||||
"action.add_animation_controller.desc": "Create a blank animation controller",
|
||||
"action.animation_controller_preview_mode": "Controller Preview",
|
||||
"action.animation_controller_preview_mode.paused": "Paused",
|
||||
@ -2238,7 +2238,7 @@
|
||||
"settings.classroom_mode": "Classroom Mode",
|
||||
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
|
||||
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
|
||||
"settings.tone_mapping": "Tone Mapping",
|
||||
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
|
||||
"settings.audio_scrubbing": "Timline Scrubbing Audio",
|
||||
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "Longest Axis",
|
||||
"edit.vertex_snap.align.direction": "Direction from Pivot",
|
||||
"edit.vertex_snap.align.align_axis": "%0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore %0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore Axis",
|
||||
"codec.common.format": "Format",
|
||||
"codec.image.quality": "Quality",
|
||||
"panel.collections": "Collections",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Selection Tolerance",
|
||||
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
|
||||
"action.delete.keep_vertices": "Keep Edges/Vertices",
|
||||
"menu.mesh": "Mesh"
|
||||
"menu.mesh": "Mesh",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
82
lang/ru.json
82
lang/ru.json
@ -237,7 +237,7 @@
|
||||
"category.textures": "Текстуры",
|
||||
"category.misc": "Разное",
|
||||
"keybind.preview_select": "Выделить элемент",
|
||||
"keybind.preview_rotate": "Вращать вид",
|
||||
"keybind.preview_rotate": "Вращение вида",
|
||||
"keybind.preview_drag": "Перетащить вид",
|
||||
"keybind.confirm": "Подтвердить",
|
||||
"keybind.cancel": "Отменить",
|
||||
@ -610,12 +610,12 @@
|
||||
"mode.edit": "Редактирование",
|
||||
"mode.paint": "Рисование",
|
||||
"mode.display": "Предпросмотр",
|
||||
"mode.animate": "Анимировать",
|
||||
"mode.animate": "Анимация",
|
||||
"status_bar.recording_gif": "Запись GIF",
|
||||
"status_bar.processing_gif": "Обработка GIF",
|
||||
"settings.backup_retain": "Время хранения автосохранений",
|
||||
"settings.backup_retain.desc": "Установить продолжительность жизни автосохранения в днях",
|
||||
"action.rotate_tool": "Вращать",
|
||||
"action.rotate_tool": "Вращение",
|
||||
"action.rotate_tool.desc": "Выбрать и провернуть элементы",
|
||||
"action.fill_tool": "Заполнение",
|
||||
"action.fill_tool.desc": "Инструмент для заполнения граней одним цветом",
|
||||
@ -666,8 +666,8 @@
|
||||
"data.origin": "Центр поворота",
|
||||
"message.sketchfab.success": "Загрузка модели прошла успешно",
|
||||
"message.sketchfab.error": "Не удалось загрузить модель на Sketchfab",
|
||||
"settings.outliner_colors": "Цвета Элементов",
|
||||
"settings.outliner_colors.desc": "Показывать цвета элементов в списке элементов",
|
||||
"settings.outliner_colors": "Цвета элементов",
|
||||
"settings.outliner_colors.desc": "Показывать цвета в списке элементов",
|
||||
"action.upload_sketchfab.desc": "Загрузить модель на Sketchfab",
|
||||
"action.element_colors": "Цвета элементов",
|
||||
"action.element_colors.desc": "Показывать цвета элементов в списке элементов",
|
||||
@ -686,7 +686,7 @@
|
||||
"dialog.edit_session.title": "Редактирование сессии",
|
||||
"edit_session.username": "Имя пользователя",
|
||||
"edit_session.token": "Токен",
|
||||
"edit_session.about": "Сессии редактирования позволяют совместно работать над моделями через интернет. Создай сессию, скопируй токен и отправь его друзьям, чтобы они могли присоединиться.",
|
||||
"edit_session.about": "Сессии редактирования позволяют совместно работать над моделями в онлайн-формате. Создай сессию, скопируй токен и отправь его присоединяемому.",
|
||||
"edit_session.join": "Присоединиться к сессии",
|
||||
"edit_session.create": "Создать сессию",
|
||||
"edit_session.quit": "Покинуть сессию",
|
||||
@ -714,16 +714,16 @@
|
||||
"mode.start.new": "Создать",
|
||||
"mode.start.recent": "Недавние",
|
||||
"format.free": "Общая модель",
|
||||
"format.free.desc": "Модель без ограничений для Unity и т. п.",
|
||||
"format.free.desc": "Модель без осевых, размерных и каких-либо иных ограничений для игровых движков (Unity, Godot) и рендеринга",
|
||||
"format.java_block": "Модель для Minecraft JE",
|
||||
"format.java_block.desc": "Модель для Minecraft JE.",
|
||||
"format.bedrock": "Модель Bedrock",
|
||||
"format.bedrock.desc": "Модель для Bedrock Edition",
|
||||
"format.java_block.desc": "Модель для блоков и предметов в Minecraft JE",
|
||||
"format.bedrock": "Модель для Minecraft BE",
|
||||
"format.bedrock.desc": "Модель для сущностей и экипированных предметов в Minecraft BE",
|
||||
"format.bedrock_old": "Устаревшая модель Bedrock",
|
||||
"format.bedrock_old.desc": "Модель Bedrock Edition для версий старее 1.12",
|
||||
"format.modded_entity": "Сущность для модов",
|
||||
"format.modded_entity.desc": "Модель модовой сущности для Minecraft JE. Может быть экспортирована как файл класса .java.",
|
||||
"format.optifine_entity": "Сущность OptiFine",
|
||||
"format.bedrock_old.desc": "Устаревшая модель для версий игры до 1.12 в Minecraft BE",
|
||||
"format.modded_entity": "Модовая сущность",
|
||||
"format.modded_entity.desc": "Модель модовой сущности для Minecraft JE. Может быть экспортирована в виде .java-файла",
|
||||
"format.optifine_entity": "OptiFine-сущность",
|
||||
"format.optifine_entity.desc": "Пользовательская модель сущности для OptiFine",
|
||||
"keys.mouse": "Кнопка Мыши %0",
|
||||
"message.cleared_blank_faces.title": "Пустые грани",
|
||||
@ -764,7 +764,7 @@
|
||||
"uv_editor.turned": "Преоброзование овёрнуто",
|
||||
"display.reference.crossbow": "Заряженный арбалет",
|
||||
"dialog.settings.search_results": "Результаты поиска",
|
||||
"settings.animation_snap": "Привязка Анимаций",
|
||||
"settings.animation_snap": "Привязка анимаций",
|
||||
"settings.animation_snap.desc": "Интервал привязки по умолчанию для ключевых кадров в анимационной шкале времени, измеряемый в FPS. Этот параметр можно изменить для каждой анимации. Значение по умолчанию — 24.",
|
||||
"action.import_optifine_part": "Импортирование части OptiFine-модели",
|
||||
"action.import_optifine_part.desc": "Импортировать часть модели сущности OptiFine",
|
||||
@ -924,10 +924,10 @@
|
||||
"dialog.sketchfab_uploader.animations": "Анимации",
|
||||
"dialog.settings.theme": "Тема",
|
||||
"settings.category.interface": "Интерфейс",
|
||||
"settings.preview_checkerboard": "Предпросмотр шахматной доски",
|
||||
"settings.preview_checkerboard.desc": "Переключить фон шахматной доски за предварительным просмотром",
|
||||
"settings.preview_checkerboard": "Шахматная доска в предпросмотре",
|
||||
"settings.preview_checkerboard.desc": "Переключить отображение шахматной доски на фоне предварительного просмотра",
|
||||
"settings.uv_checkerboard": "Шахматная доска UV-редактора",
|
||||
"settings.uv_checkerboard.desc": "Переключить фон шахматной доски за UV редактором",
|
||||
"settings.uv_checkerboard.desc": "Переключить отображение шахматной доски на фоне UV-редактора",
|
||||
"category.paint": "Рисование",
|
||||
"action.fill_mode.color_connected": "Соединённые цвета",
|
||||
"action.draw_shape_type": "Тип фигуры",
|
||||
@ -944,8 +944,8 @@
|
||||
"action.draw_shape_tool.desc": "Инструмент для рисования простых фигур",
|
||||
"action.export_gltf": "Экспорт gLTF-модели",
|
||||
"action.export_gltf.desc": "Экспортировать модель и анимации как glTF-файл для использования в других программах",
|
||||
"action.transform_space": "Место для Трансформации",
|
||||
"action.transform_space.desc": "Обычное место для трансформации для элементов и костей",
|
||||
"action.transform_space": "Способ трансформация",
|
||||
"action.transform_space.desc": "Метод трансформации элементов относительно собственной, родительской или глобальной осей",
|
||||
"action.transform_space.global": "Глобальный",
|
||||
"action.transform_space.local": "Локальный",
|
||||
"action.toggle_camera_projection": "Включить проекцию камеры",
|
||||
@ -957,7 +957,7 @@
|
||||
"menu.help.quickstart": "Путеводитель Blockbench",
|
||||
"menu.help.developer": "Фунции разработчика",
|
||||
"menu.help.developer.dev_tools": "Открыть инструменты разработчика",
|
||||
"menu.help.developer.reset_storage": "Перезагрузка фабрики",
|
||||
"menu.help.developer.reset_storage": "Сброс до заводских настроек",
|
||||
"menu.help.developer.reset_storage.confirm": "Ты уверен, что хочешь вернуть Blockbench до заводских параметров? Это сбросит все пользовательские настройки, горячие клавиши и плагины.",
|
||||
"menu.help.developer.cache_reload": "Перезагрузить кэш",
|
||||
"menu.preview.orthographic": "Ортография",
|
||||
@ -1036,7 +1036,7 @@
|
||||
"dialog.animation_import.title": "Выбери анимации для импорта",
|
||||
"dialog.create_texture.padding": "Отступ",
|
||||
"settings.fov": "FOV",
|
||||
"settings.fov.desc": "Поле зрения камеры. Стандартное 45",
|
||||
"settings.fov.desc": "Поле зрения камеры. Значение по умолчанию — 45°",
|
||||
"settings.sync_color": "Синхронизовать цвет",
|
||||
"settings.sync_color.desc": "Синхронизовать цвет между разными окнами Blockbench",
|
||||
"settings.minify_bbmodel": "Уменьшенные файлы проекта",
|
||||
@ -1075,7 +1075,7 @@
|
||||
"action.timeline_frame_forth": "Перейти на кадр вперед",
|
||||
"panel.bone.ik": "Инверсная кинематика",
|
||||
"settings.particle_tick_rate": "Частота тактов частиц",
|
||||
"settings.particle_tick_rate.desc": "Частота для эффектов частиц в тактах в секунду. По умолчанию 30",
|
||||
"settings.particle_tick_rate.desc": "Частота для эффектов партиклей в тактах в секунду. Значение по умолчанию — 30",
|
||||
"action.lock_motion_trail": "Блокировка пути движения",
|
||||
"action.lock_motion_trail.desc": "Заблокировать пути движения для выбраных групп",
|
||||
"menu.animation_file.unload": "Скачать файл с анимацией",
|
||||
@ -1330,8 +1330,8 @@
|
||||
"action.inset_mesh_selection.desc": "Вставь выбранные части мэша",
|
||||
"action.dissolve_edges": "Растворение краёв",
|
||||
"action.dissolve_edges.desc": "Растворить выбранные ребра в сетке и объединить грани, разделяемые ими",
|
||||
"action.split_mesh": "Разделённая сетка",
|
||||
"action.split_mesh.desc": "Разделить выбранные грани сетки на новую сетку",
|
||||
"action.split_mesh": "Разделение мэшей",
|
||||
"action.split_mesh.desc": "Отделить выбранные грани в новый мэш",
|
||||
"action.merge_vertices": "Объединение вершин",
|
||||
"action.merge_vertices.desc": "Объединить выбранные вершины в положение первой выбранной вершины",
|
||||
"action.view_mode.normal": "Ориентация грани",
|
||||
@ -1401,7 +1401,7 @@
|
||||
"action.export_collada.desc": "Экспортировать модель и анимации как DAE-файл для использования в других программах",
|
||||
"action.paint_mode_uv_overlay": "UV-наложение",
|
||||
"action.paint_mode_uv_overlay.desc": "Отображение UV-карты в виде наложения в режиме рисования",
|
||||
"action.bake_animation_into_model": "Запекание анимации в модель",
|
||||
"action.bake_animation_into_model": "Запечь анимации в модель",
|
||||
"action.bake_animation_into_model.desc": "Запеки отображаемый кадр анимации в модель. Применяется только вращение и положение, масштаб игнорируется.",
|
||||
"action.keyframe_interpolation.step": "Пошаговый",
|
||||
"action.set_ik_target": "Установить цель IK",
|
||||
@ -1430,7 +1430,7 @@
|
||||
"panel.skin_pose.jumping": "Прыжок",
|
||||
"panel.skin_pose.aiming": "Прицеливание",
|
||||
"edit.loop_cut.direction": "Направление",
|
||||
"data.texture_mesh": "Текстурная сетка",
|
||||
"data.texture_mesh": "Текстура мэша",
|
||||
"generic.left": "Левый",
|
||||
"generic.right": "Правый",
|
||||
"mode.start.quick_setup": "Быстрая установка",
|
||||
@ -1466,8 +1466,8 @@
|
||||
"action.select_seam": "Выбери UV-шов",
|
||||
"action.select_seam.desc": "Выбери режим шва UV для выбранных краев.",
|
||||
"action.select_seam.auto": "Авто",
|
||||
"action.select_seam.join": "Присоединиться",
|
||||
"action.select_seam.divide": "Разделять",
|
||||
"action.select_seam.join": "Присоединить",
|
||||
"action.select_seam.divide": "Разделить",
|
||||
"action.adjust_brightness_contrast": "Яркость и контрастность...",
|
||||
"action.adjust_brightness_contrast.desc": "Отрегулировать яркость и контрастность выбранной текстуры",
|
||||
"action.adjust_saturation_hue": "Насыщенность и оттенок...",
|
||||
@ -1603,8 +1603,8 @@
|
||||
"menu.mirror_painting.local.desc": "Включить зеркальное рисование в локальном пространстве для каждого элемента",
|
||||
"menu.mirror_painting.texture_frames": "Повтор на кадрах анимированных текстур",
|
||||
"menu.mirror_painting.texture_frames.desc": "Отражай мазки краской в каждом кадре анимированных текстур.",
|
||||
"format.bedrock_block.info.size_limit": "Размер Общий размер блока ограничен 30 пикселями во всех измерениях. Предел может быть смещен во всех направлениях на 7 пикселей от центра блока.",
|
||||
"format.bedrock_block.info.textures": "Несколько текстур можно применять к разным кубам в Blockbench, но для правильной работы в игре требуется дополнительная настройка в пакете поведения.",
|
||||
"format.bedrock_block.info.size_limit": "Общий размер блока ограничен 30 пикселями во всех измерениях. Предел может быть смещён во всех направлениях на 7 пикселей от центра блока.",
|
||||
"format.bedrock_block.info.textures": "Несколько текстур можно применять к разным кубам в Blockbench, но для их правильной работы требуется дополнительная настройка в пакете поведения.",
|
||||
"format.image.desc": "Редактировать изображения в редакторе 2D-изображений",
|
||||
"generic.delete_all": "Удалить всё",
|
||||
"message.child_model_only.open": "Открытый родитель",
|
||||
@ -1845,7 +1845,7 @@
|
||||
"dialog.copy_to_clipboard": "Скопировать в буфер обмена",
|
||||
"dialog.open_url": "Открыть URL",
|
||||
"reference_image.image": "Изображение",
|
||||
"uv_editor.rotate_uv": "Вращать UV",
|
||||
"uv_editor.rotate_uv": "Вращение UV",
|
||||
"generic.error": "Ошибка",
|
||||
"projects.start_screen": "Начальный экран",
|
||||
"message.invalid_link.message": "Модель %0, которую ты пытаешься загрузить, недействительна или доступ к ней истёк.",
|
||||
@ -1876,8 +1876,8 @@
|
||||
"dialog.share_model.too_large_references": "Не удалось загрузить: Слишком большая модель. Попробуй убрать встроенные референсы.",
|
||||
"settings.stretch_linked": "Связное растяжение",
|
||||
"settings.stretch_linked.desc": "Растянуть куб во всех направлениях на одно и то же значение",
|
||||
"settings.grids": "Показать сетки",
|
||||
"settings.grids.desc": "Показать или скрыть все 3D-сетки",
|
||||
"settings.grids": "Показать сетку",
|
||||
"settings.grids.desc": "Показать или скрыть сетку редактирования",
|
||||
"settings.double_click_switch_tools": "Переключать инструменты двойным щелчком",
|
||||
"settings.double_click_switch_tools.desc": "Дважды нажать по области просмотра для переключения между инструментами",
|
||||
"settings.outlines_in_paint_mode": "Контуры выделения в режиме рисования",
|
||||
@ -1992,7 +1992,7 @@
|
||||
"action.export_modded_animations.desc": "Экспортировать анимации для модели модовой сущности Minecraft Java Edition",
|
||||
"action.swap_colors": "Поменять цвета",
|
||||
"action.swap_colors.desc": "Поменять основной цвет с вторичным",
|
||||
"action.apply_mesh_rotation": "Запекание вращения",
|
||||
"action.apply_mesh_rotation": "Запечь вращения",
|
||||
"action.apply_mesh_rotation.desc": "Применить вращение к геометрии модели, убрав его из свойств элемента",
|
||||
"action.flip_texture_x.desc": "Отразить текстуру или слой по-горизонтали",
|
||||
"action.flip_texture_y.desc": "Отразить текстуру или слой по-вертикали",
|
||||
@ -2009,7 +2009,7 @@
|
||||
"action.merge_layer_down.desc": "Соединить выбранный слой с лежащим снизу",
|
||||
"action.advanced_screenshot": "Продвинутый снимок экрана...",
|
||||
"action.advanced_screenshot.desc": "Сделать снимок модели с расширенными опциями",
|
||||
"action.bake_ik_animation": "Запекание анимации обратной кинематики",
|
||||
"action.bake_ik_animation": "Запечь анимации обратной кинематики",
|
||||
"action.bake_ik_animation.desc": "Запечь вращения, применённые инверсной кинематикой, в выбранную анимацию",
|
||||
"action.save_animation_preset": "Сохранить шаблон анимации...",
|
||||
"action.save_animation_preset.desc": "Сохранить выбранные ключевые кадры как шаблон анимации",
|
||||
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "По длиннейшей оси",
|
||||
"edit.vertex_snap.align.direction": "По направлению от центра поворота",
|
||||
"edit.vertex_snap.align.align_axis": "По оси %0",
|
||||
"edit.vertex_snap.ignore_axis": "Игнорирование оси %0",
|
||||
"edit.vertex_snap.ignore_axis": "Игнорирование оси",
|
||||
"codec.common.format": "Формат",
|
||||
"codec.image.quality": "Качество",
|
||||
"panel.collections": "Коллекции",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Допуск выделения",
|
||||
"settings.selection_tolerance.desc": "Размер области, по которой можно нажать, чтобы выбрать ребро или вершину",
|
||||
"action.delete.keep_vertices": "Сохранить рёбра/вершины",
|
||||
"menu.mesh": "Мэш"
|
||||
"menu.mesh": "Мэш",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
12
lang/sv.json
12
lang/sv.json
@ -2238,7 +2238,7 @@
|
||||
"settings.classroom_mode": "Classroom Mode",
|
||||
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
|
||||
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
|
||||
"settings.tone_mapping": "Tone Mapping",
|
||||
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
|
||||
"settings.audio_scrubbing": "Timline Scrubbing Audio",
|
||||
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "Longest Axis",
|
||||
"edit.vertex_snap.align.direction": "Direction from Pivot",
|
||||
"edit.vertex_snap.align.align_axis": "%0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore %0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore Axis",
|
||||
"codec.common.format": "Format",
|
||||
"codec.image.quality": "Quality",
|
||||
"panel.collections": "Collections",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Selection Tolerance",
|
||||
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
|
||||
"action.delete.keep_vertices": "Keep Edges/Vertices",
|
||||
"menu.mesh": "Mesh"
|
||||
"menu.mesh": "Mesh",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
1058
lang/uk.json
1058
lang/uk.json
File diff suppressed because it is too large
Load Diff
42
lang/vi.json
42
lang/vi.json
@ -293,9 +293,9 @@
|
||||
"action.load_plugin.desc": "Tải một plugin bằng cách nhập tệp nguồn",
|
||||
"action.reload_plugins": "Reload các plugin",
|
||||
"action.reload_plugins.desc": "Tải lại toàn bộ Plugin cho Nhà Phát Triển",
|
||||
"action.undo": "Quay lại",
|
||||
"action.undo": "Hoàn tác",
|
||||
"action.undo.desc": "Quay lại thay đổi trước",
|
||||
"action.redo": "Tiến",
|
||||
"action.redo": "Làm lại",
|
||||
"action.redo.desc": "Quay lại thay đổi cuối",
|
||||
"action.copy": "Sao chép",
|
||||
"action.copy.desc": "Sao chép những đồ vật, mặt hay những điều chỉnh hiển thị đã được chọn",
|
||||
@ -833,7 +833,7 @@
|
||||
"dialog.timelapse.source.interface": "Giao diện",
|
||||
"dialog.timelapse.source.locked": "Góc khóa",
|
||||
"dialog.timelapse.destination": "Thư mục đích",
|
||||
"layout.color.checkerboard": "Bàn cờ",
|
||||
"layout.color.checkerboard": "Nền caro",
|
||||
"layout.color.checkerboard.desc": "Nền của canvas và trình chỉnh sửa UV",
|
||||
"layout.font.code": "Mã phông chữ",
|
||||
"layout.css": "CSS tùy chỉnh",
|
||||
@ -924,10 +924,10 @@
|
||||
"dialog.sketchfab_uploader.animations": "Hoạt ảnh",
|
||||
"dialog.settings.theme": "Chủ đề",
|
||||
"settings.category.interface": "Giao diện",
|
||||
"settings.preview_checkerboard": "Xem trước bàn cờ",
|
||||
"settings.preview_checkerboard.desc": "Chuyển đổi nền bàn cờ đằng sau bản xem trước",
|
||||
"settings.uv_checkerboard": "Chỉnh UV bàn cờ",
|
||||
"settings.uv_checkerboard.desc": "Chuyển đổi nền bàn cờ phía sau trình chỉnh sửa UV",
|
||||
"settings.preview_checkerboard": "Xem trước nền caro",
|
||||
"settings.preview_checkerboard.desc": "Chuyển đổi nền caro đằng sau bản xem trước",
|
||||
"settings.uv_checkerboard": "Chỉnh UV nền caro",
|
||||
"settings.uv_checkerboard.desc": "Chuyển đổi nền caro phía sau trình chỉnh sửa UV",
|
||||
"category.paint": "Vẽ",
|
||||
"action.fill_mode.color_connected": "Kết nối màu sắc",
|
||||
"action.draw_shape_type": "Loại hình dạng",
|
||||
@ -1247,10 +1247,10 @@
|
||||
"dialog.add_primitive.shape.sphere": "Hình cầu",
|
||||
"dialog.add_primitive.shape.torus": "Hình xuyến",
|
||||
"dialog.add_primitive.shape.cube": "Hình khối",
|
||||
"dialog.add_primitive.shape.pyramid": "Hình kim tự tháp",
|
||||
"dialog.add_primitive.shape.pyramid": "Hình chóp",
|
||||
"dialog.add_primitive.diameter": "Đường kính",
|
||||
"dialog.add_primitive.height": "Chiều cao",
|
||||
"dialog.add_primitive.sides": "Bên",
|
||||
"dialog.add_primitive.sides": "Số mặt bên",
|
||||
"dialog.add_primitive.minor_diameter": "Độ dày",
|
||||
"dialog.add_primitive.minor_sides": "Bên nhỏ",
|
||||
"dialog.create_texture.combine_polys": "liên kết bề mặt",
|
||||
@ -1282,13 +1282,13 @@
|
||||
"action.add_plugin.desc": "Cài đặt plugin từ kiểm soát hành động",
|
||||
"action.remove_plugin": "Xóa plugin khỏi kiểm soát hành động",
|
||||
"action.remove_plugin.desc": "Gỡ cài đặt plugin thông qua Kiểm soát hành động",
|
||||
"action.add_mesh": "Thêm khung lưới",
|
||||
"action.add_mesh": "Thêm lưới",
|
||||
"action.add_mesh.desc": "Thêm một khung lưới mới",
|
||||
"action.add_texture_mesh": "Thêm khung lưới kết cấu",
|
||||
"action.add_texture_mesh": "Thêm lưới kết cấu",
|
||||
"action.add_texture_mesh.desc": "Thêm một khung lưới kết cấu mới",
|
||||
"action.find_replace": "Tìm/Thay thế...",
|
||||
"action.find_replace.desc": "Tìm và thay thế các phần của tên",
|
||||
"action.hide_everything_except_selection": "Ẩn mọi thứ trừ lựa chọn",
|
||||
"action.hide_everything_except_selection": "Ẩn mọi thứ (trừ phần lựa chọn)",
|
||||
"action.hide_everything_except_selection.desc": "Chuyển đổi chế độ hiển thị cho tất cả các phần tử ngoại trừ phần tử đã chọn",
|
||||
"action.transform_space.normal": "Bình thường",
|
||||
"action.selection_mode": "Chế độ lựa chọn",
|
||||
@ -1336,7 +1336,7 @@
|
||||
"action.merge_vertices.desc": "Hợp nhất các đỉnh đã chọn vào vị trí của đỉnh được chọn đầu tiên",
|
||||
"action.view_mode.normal": "Mặt thường",
|
||||
"action.snap_uv_to_pixels": "Khớp UV với điểm ảnh",
|
||||
"action.snap_uv_to_pixels.desc": "Gắn các đỉnh UV đã chọn vào lưới đồ thị điểm ảnh",
|
||||
"action.snap_uv_to_pixels.desc": "Gắn các đỉnh UV đã chọn vào lưới điểm ảnh",
|
||||
"menu.file.import.import_open_project": "Nhập dự án mở",
|
||||
"menu.help.unlock_projects": "Mở khóa tất cả các dự án",
|
||||
"status_bar.selection.faces": "%0 mặt",
|
||||
@ -2076,7 +2076,7 @@
|
||||
"dialog.import_obj.mtl": "Tệp MTL",
|
||||
"dialog.import_obj.scale": "Tỉ lệ",
|
||||
"layout.thumbnail": "Tùy chỉnh hình thu nhỏ CSS",
|
||||
"settings.pixel_grid": "Lưới đồ thị điểm ảnh",
|
||||
"settings.pixel_grid": "Lưới điểm ảnh",
|
||||
"settings.pixel_grid.desc": "Hiển thị lưới đồ thị kết cấu điểm ảnh trên các phần tử trong chế độ chỉnh sửa",
|
||||
"settings.image_editor_grid_size": "Kích thước lưới đồ thị của công cụ chỉnh sửa ảnh",
|
||||
"settings.image_editor_grid_size.desc": "Kích thước lưới đồ thị lớn trong công cụ chỉnh sửa ảnh 2D",
|
||||
@ -2092,7 +2092,7 @@
|
||||
"action.knife_tool.desc": "Công cụ để cắt các mặt khung lưới thành các miếng nhỏ hơn",
|
||||
"action.duplicate_project": "Nhân bản dự án",
|
||||
"action.duplicate_project.desc": "Tạo một bản sao của dự án",
|
||||
"action.transform_space.parent": "Phụ huynh",
|
||||
"action.transform_space.parent": "Gốc",
|
||||
"action.transform_pivot_space": "Tâm quay thay đổi không gian",
|
||||
"action.solidify_mesh_selection": "Làm đông đặc các mặt",
|
||||
"action.solidify_mesh_selection.desc": "Làm đông đặc các mặt được chọn của khung lưới",
|
||||
@ -2238,7 +2238,7 @@
|
||||
"settings.classroom_mode": "Classroom Mode",
|
||||
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
|
||||
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
|
||||
"settings.tone_mapping": "Tone Mapping",
|
||||
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
|
||||
"settings.audio_scrubbing": "Timline Scrubbing Audio",
|
||||
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "Longest Axis",
|
||||
"edit.vertex_snap.align.direction": "Direction from Pivot",
|
||||
"edit.vertex_snap.align.align_axis": "%0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore %0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore Axis",
|
||||
"codec.common.format": "Format",
|
||||
"codec.image.quality": "Quality",
|
||||
"panel.collections": "Collections",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Selection Tolerance",
|
||||
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
|
||||
"action.delete.keep_vertices": "Keep Edges/Vertices",
|
||||
"menu.mesh": "Mesh"
|
||||
"menu.mesh": "Mesh",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
10
lang/zh.json
10
lang/zh.json
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "最长轴",
|
||||
"edit.vertex_snap.align.direction": "Direction from Pivot",
|
||||
"edit.vertex_snap.align.align_axis": "轴 %0",
|
||||
"edit.vertex_snap.ignore_axis": "忽略 %0 轴",
|
||||
"edit.vertex_snap.ignore_axis": "忽略 轴",
|
||||
"codec.common.format": "格式",
|
||||
"codec.image.quality": "品质",
|
||||
"panel.collections": "集合",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Selection Tolerance",
|
||||
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
|
||||
"action.delete.keep_vertices": "Keep Edges/Vertices",
|
||||
"menu.mesh": "网格"
|
||||
"menu.mesh": "网格",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
@ -2238,7 +2238,7 @@
|
||||
"settings.classroom_mode": "Classroom Mode",
|
||||
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
|
||||
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
|
||||
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
|
||||
"settings.tone_mapping": "Tone Mapping",
|
||||
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
|
||||
"settings.audio_scrubbing": "Timline Scrubbing Audio",
|
||||
@ -2307,7 +2307,7 @@
|
||||
"edit.vertex_snap.align.longest": "Longest Axis",
|
||||
"edit.vertex_snap.align.direction": "Direction from Pivot",
|
||||
"edit.vertex_snap.align.align_axis": "%0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore %0 Axis",
|
||||
"edit.vertex_snap.ignore_axis": "Ignore Axis",
|
||||
"codec.common.format": "Format",
|
||||
"codec.image.quality": "Quality",
|
||||
"panel.collections": "Collections",
|
||||
@ -2320,5 +2320,11 @@
|
||||
"settings.selection_tolerance": "Selection Tolerance",
|
||||
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
|
||||
"action.delete.keep_vertices": "Keep Edges/Vertices",
|
||||
"menu.mesh": "Mesh"
|
||||
"menu.mesh": "Mesh",
|
||||
"dialog.material_config.subsurface": "Subsurface Scattering",
|
||||
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
|
||||
"settings.pick_combined_color": "Pick Combined Color",
|
||||
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
|
||||
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
|
||||
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
|
||||
}
|
@ -5,11 +5,11 @@ class CanvasFrame {
|
||||
/**
|
||||
*
|
||||
* @param {Number|HTMLCanvasElement|HTMLImageElement} [a] Image source
|
||||
* @param {Number} [b]
|
||||
* @param {Number|Boolean} [b]
|
||||
*/
|
||||
constructor(a, b) {
|
||||
if (a && a.nodeName == 'CANVAS') {
|
||||
if (a.getContext('2d')) {
|
||||
if (a.getContext('2d') && b !== true) {
|
||||
this.canvas = a;
|
||||
} else {
|
||||
this.createCanvas(a.width, a.height)
|
||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "Blockbench",
|
||||
"version": "4.12.0",
|
||||
"version": "4.12.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "Blockbench",
|
||||
"version": "4.12.0",
|
||||
"version": "4.12.3",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@electron/remote": "^2.1.2",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Blockbench",
|
||||
"description": "Low-poly modeling and animation software",
|
||||
"version": "4.12.0",
|
||||
"version": "4.12.4",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"author": {
|
||||
"name": "JannisX11",
|
||||
@ -140,4 +140,4 @@
|
||||
"electron-updater": "^6.3.4",
|
||||
"gifenc": "^1.0.3"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user