This commit is contained in:
JannisX11 2018-12-27 14:03:04 +01:00 committed by GitHub
parent a72d09e872
commit 5e2b5a9e1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 50402 additions and 48039 deletions

View File

@ -490,7 +490,7 @@
}
li.menu_bar_point {
font-size: 1.1em;
padding: 16px;
padding: 12px;
padding-top: 2px;
padding-bottom: 0;
float: left;
@ -532,6 +532,25 @@
}
}
#mode_selector {
float: right;
font-size: 1.1em;
}
#mode_selector li {
display: inline-block;
height: 32px;
margin-left: 5px;
margin-right: 5px;
overflow: hidden;
padding-top: 2px;
}
#mode_selector li:hover {
color: var(--color-light);
}
#mode_selector li.selected {
border-bottom: 4px solid var(--color-accent);
}
/*Actions*/
.toolbar {
width: 100%;
@ -599,9 +618,6 @@
grid-area: right_bar;
}
.panel {
}
.panel.grow {
flex-grow: 1;
display: flex;
@ -613,7 +629,6 @@
padding-bottom: 8px;
}
h3.panel_handle {
width: calc(100% - 6px);
height: auto;
@ -621,7 +636,7 @@
padding: 6px;
background: var(--color-ui);
}
.panel > p {
.panel p {
margin-left: 12px;
}
body > h3.panel_handle {
@ -629,7 +644,6 @@
width: auto;
}
div#preview {
grid-area: preview;
background: var(--color-dark);
@ -886,6 +900,7 @@
#cubes_list > div.vue-tree > ul > li > *:not(ul) {
display: none;
}
/*
#cubes_list > div > ul > li > ul > li > ul > li > div {
padding-left: 20px;
}
@ -904,6 +919,7 @@
#cubes_list > div > ul > li > ul > li > ul > li > ul > li > ul > li > ul > li > ul > li > ul li > div {
padding-left: 120px;
}
*/
.outliner_object i.fa {
text-align: center;
width: 18px;
@ -1254,6 +1270,7 @@
background-color: var(--color-back);
padding: 3px;
padding-left: 8px;
overflow: hidden;
}
#timeline_head > .channel_head {
height: 31px;
@ -2178,12 +2195,13 @@
/*Status Bar*/
#status_bar {
background: var(--color-back);
position: relative;
padding: 2px;
padding-top: 0;
box-sizing: border-box;
display: block;
font-size: 0.92em;
background: var(--color-back);
border: 1px solid var(--color-border);
}
#status_bar > div {
@ -2194,6 +2212,13 @@
#status_bar > div#status_fps {
float: right;
}
#status_bar #status_progress {
position: absolute;
height: 4px;
background: var(--color-accent);
bottom: 0;
left: 0;
}
/*Entity Mode*/

View File

@ -13,7 +13,9 @@
<style type="text/css" id="bbstyle"></style>
</head>
<body spellcheck="false">
<div id="loading_error_message" style="display: none;">An error occurred while loading Blockbench</div>
<div id="loading_error_message" style="display: none;">An error occurred while loading Blockbench
<button onclick="Blockbench.reload()" class="large" style="display: block; margin-right: auto; margin-left: auto;">Reload</button>
</div>
<script>
if (typeof module === 'object') {window.module = module; module = undefined;}//jQuery Fix
var isApp = typeof require !== 'undefined'
@ -28,6 +30,7 @@
<script src="lib/gif.js"></script>
<script src="lib/spectrum.js"></script>
<script src="lib/three.js"></script>
<script src="lib/three_custom.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/TransformControls.js"></script>
<script src="js/OBJExporter.js"></script>
@ -36,6 +39,7 @@
<script src="js/util.js"></script>
<script src="js/keyboard.js"></script>
<script src="js/settings.js"></script>
<script src="js/actions.js"></script>
<script src="js/blockbench.js"></script>
<script src="js/undo.js"></script>
@ -48,7 +52,6 @@
</script>
<script src="js/api.js"></script>
<script src="js/actions.js"></script>
<script src="js/io.js"></script>
<script src="js/elements.js"></script>
<script src="js/preview.js"></script>
@ -63,8 +66,6 @@
<script src="js/plugin_loader.js"></script>
<script>if (window.module) module = window.module;</script>
<div id="post_model" class="web_only post_data" hidden></div>
<div id="post_textures" class="web_only post_data" hidden></div>
<div style="display: none;"></div>
@ -297,55 +298,44 @@
<div class="dialog draggable paddinged" id="create_preset">
<h2 class="dialog_handle tl">dialog.display_preset.title</h2>
<div class="dialog_bar tl">dialog.display_preset.message</div>
<div class="dialog_bar">
<input type="checkbox" id="thirdperson_righthand_save" checked>
<label for="thirdperson_righthand_save" class="tl">display.slot.third_right</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="thirdperson_lefthand_save" checked>
<label for="thirdperson_lefthand_save" class="tl">display.slot.third_left</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="firstperson_righthand_save" checked>
<label for="firstperson_righthand_save" class="tl">display.slot.first_right</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="firstperson_lefthand_save" checked>
<label for="firstperson_lefthand_save" class="tl">display.slot.first_left</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="head_save" checked>
<label for="head_save" class="tl">display.slot.head</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="ground_save" checked>
<label for="ground_save" class="tl">display.slot.ground</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="fixed_save" checked>
<label for="fixed_save" class="tl">display.slot.frame</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="gui_save" checked>
<label for="gui_save" class="tl">display.slot.gui</label>
</div>
<div class="dialog_bar narrow">
<label class="tl">display.presetname</label>
</div>
<div class="dialog_bar">
<input type="text" id="preset_name" class="input_wide" id="new preset">
</div>
<div class="dialog_bar">
<button type="button" class="large tl confirm_btn" onclick="DisplayMode.createPreset()">dialog.display_preset.create</button>
<button type="button" class="large tl cancel_btn" onclick="hideDialog()">dialog.cancel</button>
@ -444,9 +434,9 @@
</h3>
<ul v-if="category.open">
<li v-for="(setting, key) in category.items" v-on="setting.click ? {click: setting.click} : {}">
<li v-for="(setting, key) in category.items" v-if="Condition(setting.condition)" v-on="setting.click ? {click: setting.click} : {}">
<template v-if="setting.type === 'number'">
<div class="setting_element"><input type="number" v-model="setting.value" v-on:input="saveSettings()"></div>
<div class="setting_element"><input type="number" v-model.number="setting.value" v-on:input="saveSettings()"></div>
</template>
<template v-else-if="setting.type === 'click'">
<div class="setting_element" v-html="Blockbench.getIconNode(setting.icon).outerHTML"></div>
@ -699,6 +689,14 @@
<ul id="menu_bar"></ul>
<div class="toolbar_wrapper narrow tools"></div>
<div class="toolbar_wrapper narrow tool_options"></div>
<div id="mode_selector">
<li
v-for="mode in options"
v-if="Condition(mode.condition)"
v-bind:class="{selected: mode.selected}"
v-on:click="mode.select()"
>{{ mode.name }}</li>
</div>
</header>
<div id="left_bar" class="sidebar">
<div id="uv" class="panel selection_only">
@ -754,55 +752,36 @@
<div id="display_ref_bar" class="bar tabs_small reference_model_bar">
</div>
<p class="tl">display.rotation</p><div class="tool head_right" onclick="DisplayMode.resetDisplaySettings('rotation')"><i class="material-icons">replay</i></div>
<div class="bar">
<input type="range" class="tool disp_range" id="rotation_x" name="" min="-180" max="180" step="1" value="0" oninput="DisplayMode.syncDispInput(this, 'rotation', 'x')">
<input type="number" class="tool disp_text" id="rotation_x" oninput="DisplayMode.syncDispInput(this, 'rotation', 'x')" min="-180" max="180" step="0.5" value="0">
</div>
<div class="bar">
<input type="range" class="tool disp_range" id="rotation_y" name="" min="-180" max="180" step="1" value="0" oninput="DisplayMode.syncDispInput(this, 'rotation', 'y')">
<input type="number" class="tool disp_text" id="rotation_y" oninput="DisplayMode.syncDispInput(this, 'rotation', 'y')" min="-180" max="180" step="0.5" value="0">
</div>
<div class="bar">
<input type="range" class="tool disp_range" id="rotation_z" name="" min="-180" max="180" step="1" value="0" oninput="DisplayMode.syncDispInput(this, 'rotation', 'z')">
<input type="number" class="tool disp_text" id="rotation_z" oninput="DisplayMode.syncDispInput(this, 'rotation', 'z')" min="-180" max="180" step="0.5" value="0">
</div>
<div id="display_sliders">
<p class="tl">display.rotation</p><div class="tool head_right" v-on:click="resetChannel('rotation')"><i class="material-icons">replay</i></div>
<div class="bar" v-for="axis in [0, 1, 2]">
<input type="range" class="tool disp_range" v-model.number="slot.rotation[axis]" min="-180" max="180" step="1" value="0" @input="change" @input="change(axis, 'rotation')" @mousedown="start" @change="save">
<input type="number" class="tool disp_text" v-model.number="slot.rotation[axis]" min="-180" max="180" step="0.5" value="0" @input="change(axis, 'rotation');save()" @mousedown="start">
</div>
<p class="tl">display.translation</p><div class="tool head_right" v-on:click="resetChannel('translation')"><i class="material-icons">replay</i></div>
<div class="bar" v-for="axis in [0, 1, 2]">
<input type="range" class="tool disp_range" v-model.number="slot.translation[axis]"
v-bind:min="Math.abs(slot.translation[axis]) < 10 ? -20 : (slot.translation[axis] > 0 ? -70*3+10 : -80)"
v-bind:max="Math.abs(slot.translation[axis]) < 10 ? 20 : (slot.translation[axis] < 0 ? 70*3-10 : 80)"
v-bind:step="Math.abs(slot.translation[axis]) < 10 ? 0.25 : 1"
value="0" @input="change(axis, 'rotation')" @mousedown="start" @change="save">
<input type="number" class="tool disp_text" v-model.number="slot.translation[axis]" min="-80" max="80" step="0.5" value="0" @input="change(axis, 'rotation');save()" @mousedown="start">
</div>
<p class="tl">display.translation</p><div class="tool head_right" onclick="DisplayMode.resetDisplaySettings('translation')"><i class="material-icons">replay</i></div>
<div class="bar">
<input type="range" class="tool disp_range" id="translation_x" name="" min="-32" max="32" step="0.5" value="0" oninput="DisplayMode.syncDispInput(this, 'translation', 'x')">
<input type="number" class="tool disp_text" id="translation_x" oninput="DisplayMode.syncDispInput(this, 'translation', 'x')" min="-80" max="80" step="0.5" value="0">
</div>
<div class="bar">
<input type="range" class="tool disp_range" id="translation_y" name="" min="-32" max="32" step="0.5" value="0" oninput="DisplayMode.syncDispInput(this, 'translation', 'y')">
<input type="number" class="tool disp_text" id="translation_y" oninput="DisplayMode.syncDispInput(this, 'translation', 'y')" min="-80" max="80" step="0.5" value="0">
</div>
<div class="bar">
<input type="range" class="tool disp_range" id="translation_z" name="" min="-32" max="32" step="0.5" value="0" oninput="DisplayMode.syncDispInput(this, 'translation', 'z')">
<input type="number" class="tool disp_text" id="translation_z" oninput="DisplayMode.syncDispInput(this, 'translation', 'z')" min="-80" max="80" step="0.5" value="0">
</div>
<p class="tl">display.scale</p><div class="tool head_right" onclick="DisplayMode.resetDisplaySettings('scale')"><i class="material-icons">replay</i></div>
<div class="bar">
<div class="tool display_scale_invert" id="display_scale_invert_x" onclick="DisplayMode.syncDispMirror(this, 'x')">
<i class="material-icons">check_box_outline_blank</i><div class="tooltip tl">display.mirror</div>
<p class="tl">display.scale</p><div class="tool head_right" v-on:click="resetChannel('scale')"><i class="material-icons">replay</i></div>
<div class="bar" v-for="axis in [0, 1, 2]">
<div class="tool display_scale_invert" v-on:click="invert(axis)">
<i class="material-icons">{{ slot.mirror[axis] ? 'check_box' : 'check_box_outline_blank' }}</i><div class="tooltip tl">display.mirror</div>
</div>
<input type="range" class="tool disp_range scaleRange" v-model.number="slot.scale[axis]" v-bind:id="'scale_range_'+axis"
v-bind:min="slot.scale[axis] > 1 ? -2 : 0"
v-bind:max="slot.scale[axis] > 1 ? 4 : 2"
step="0.01"
value="0" @input="change(axis, 'scale')" @mousedown="start" @change="save">
<input type="number" class="tool disp_text" v-model.number="slot.scale[axis]" min="0" max="4" step="0.01" value="0" @input="change(axis, 'scale');save()" @mousedown="start">
</div>
<input type="range" class="tool disp_range scaleRange" id="scale_x" name="" min="-4" max="4" step="0.1" value="0" oninput="DisplayMode.syncDispInput(this, 'scaleRange', 'x', event)">
<input type="number" class="tool disp_text scale" id="scale_x" oninput="DisplayMode.syncDispInput(this, 'scale', 'x')" step="0.1" min="-4" max="4">
</div>
<div class="bar">
<div class="tool display_scale_invert" id="display_scale_invert_y" onclick="DisplayMode.syncDispMirror(this, 'x')">
<i class="material-icons">check_box_outline_blank</i><div class="tooltip tl">display.mirror</div>
</div>
<input type="range" class="tool disp_range scaleRange" id="scale_y" name="" min="-4" max="4" step="0.1" value="0" oninput="DisplayMode.syncDispInput(this, 'scaleRange', 'y', event)">
<input type="number" class="tool disp_text scale" id="scale_y" oninput="DisplayMode.syncDispInput(this, 'scale', 'y')" step="0.1" min="-4" max="4">
</div>
<div class="bar">
<div class="tool display_scale_invert" id="display_scale_invert_z" onclick="DisplayMode.syncDispMirror(this, 'x')">
<i class="material-icons">check_box_outline_blank</i><div class="tooltip tl">display.mirror</div>
</div>
<input type="range" class="tool disp_range scaleRange" id="scale_z" name="" min="-4" max="4" step="0.1" value="0" oninput="DisplayMode.syncDispInput(this, 'scaleRange', 'z', event)">
<input type="number" class="tool disp_text scale" id="scale_z" oninput="DisplayMode.syncDispInput(this, 'scale', 'z')" step="0.1" min="-4" max="4">
</div>
</div>
<div id="animations" class="panel">
@ -854,12 +833,12 @@
v-bind:class="{ selected: texture.selected, particle: texture.particle}"
v-bind:texid="texture.id"
class="texture"
v-on:click.stop="texture.select()"
v-on:click.stop="texture.select($event)"
v-on:dblclick="texture.openMenu($event)"
@contextmenu.prevent.stop="texture.showContextMenu($event)"
>
<div class="texture_icon_wrapper">
<img v-bind:texid="texture.id" v-bind:src="texture.source" class="texture_icon" width="48px" alt="missing image" v-if="texture.show_icon" />
<img v-bind:texid="texture.id" v-bind:src="texture.source" class="texture_icon" width="48px" alt="[E]" v-if="texture.show_icon" />
<i class="material-icons texture_error" title="Image Error" v-if="texture.error">error_outline</i>
<i class="texture_movie fa fa_big fa-film" title="Animated Texture" v-if="texture.frameCount > 1"></i>
</div>
@ -945,6 +924,7 @@
<div class="f_right">
{{ Prop.fps }} FPS
</div>
<div id="status_progress" v-if="Prop.progress" v-bind:style="{width: Prop.progress*100+'%'}"></div>
</div>
<script>
initCanvas()

110
index.php
View File

@ -13,7 +13,9 @@
<style type="text/css" id="bbstyle"></style>
</head>
<body spellcheck="false">
<div id="loading_error_message" style="display: none;">An error occurred while loading Blockbench</div>
<div id="loading_error_message" style="display: none;">An error occurred while loading Blockbench
<button onclick="Blockbench.reload()" class="large" style="display: block; margin-right: auto; margin-left: auto;">Reload</button>
</div>
<script>
if (typeof module === 'object') {window.module = module; module = undefined;}//jQuery Fix
var isApp = typeof require !== 'undefined'
@ -28,6 +30,7 @@
<script src="lib/gif.js"></script>
<script src="lib/spectrum.js"></script>
<script src="lib/three.js"></script>
<script src="lib/three_custom.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/TransformControls.js"></script>
<script src="js/OBJExporter.js"></script>
@ -36,6 +39,7 @@
<script src="js/util.js"></script>
<script src="js/keyboard.js"></script>
<script src="js/settings.js"></script>
<script src="js/actions.js"></script>
<script src="js/blockbench.js"></script>
<script src="js/undo.js"></script>
@ -48,7 +52,6 @@
</script>
<script src="js/api.js"></script>
<script src="js/actions.js"></script>
<script src="js/io.js"></script>
<script src="js/elements.js"></script>
<script src="js/preview.js"></script>
@ -311,55 +314,44 @@
<div class="dialog draggable paddinged" id="create_preset">
<h2 class="dialog_handle tl">dialog.display_preset.title</h2>
<div class="dialog_bar tl">dialog.display_preset.message</div>
<div class="dialog_bar">
<input type="checkbox" id="thirdperson_righthand_save" checked>
<label for="thirdperson_righthand_save" class="tl">display.slot.third_right</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="thirdperson_lefthand_save" checked>
<label for="thirdperson_lefthand_save" class="tl">display.slot.third_left</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="firstperson_righthand_save" checked>
<label for="firstperson_righthand_save" class="tl">display.slot.first_right</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="firstperson_lefthand_save" checked>
<label for="firstperson_lefthand_save" class="tl">display.slot.first_left</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="head_save" checked>
<label for="head_save" class="tl">display.slot.head</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="ground_save" checked>
<label for="ground_save" class="tl">display.slot.ground</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="fixed_save" checked>
<label for="fixed_save" class="tl">display.slot.frame</label>
</div>
<div class="dialog_bar">
<input type="checkbox" id="gui_save" checked>
<label for="gui_save" class="tl">display.slot.gui</label>
</div>
<div class="dialog_bar narrow">
<label class="tl">display.presetname</label>
</div>
<div class="dialog_bar">
<input type="text" id="preset_name" class="input_wide" id="new preset">
</div>
<div class="dialog_bar">
<button type="button" class="large tl confirm_btn" onclick="DisplayMode.createPreset()">dialog.display_preset.create</button>
<button type="button" class="large tl cancel_btn" onclick="hideDialog()">dialog.cancel</button>
@ -458,9 +450,9 @@
</h3>
<ul v-if="category.open">
<li v-for="(setting, key) in category.items" v-on="setting.click ? {click: setting.click} : {}">
<li v-for="(setting, key) in category.items" v-if="Condition(setting.condition)" v-on="setting.click ? {click: setting.click} : {}">
<template v-if="setting.type === 'number'">
<div class="setting_element"><input type="number" v-model="setting.value" v-on:input="saveSettings()"></div>
<div class="setting_element"><input type="number" v-model.number="setting.value" v-on:input="saveSettings()"></div>
</template>
<template v-else-if="setting.type === 'click'">
<div class="setting_element" v-html="Blockbench.getIconNode(setting.icon).outerHTML"></div>
@ -713,6 +705,14 @@
<ul id="menu_bar"></ul>
<div class="toolbar_wrapper narrow tools"></div>
<div class="toolbar_wrapper narrow tool_options"></div>
<div id="mode_selector">
<li
v-for="mode in options"
v-if="Condition(mode.condition)"
v-bind:class="{selected: mode.selected}"
v-on:click="mode.select()"
>{{ mode.name }}</li>
</div>
</header>
<div id="left_bar" class="sidebar">
<div id="uv" class="panel selection_only">
@ -768,55 +768,36 @@
<div id="display_ref_bar" class="bar tabs_small reference_model_bar">
</div>
<p class="tl">display.rotation</p><div class="tool head_right" onclick="DisplayMode.resetDisplaySettings('rotation')"><i class="material-icons">replay</i></div>
<div class="bar">
<input type="range" class="tool disp_range" id="rotation_x" name="" min="-180" max="180" step="1" value="0" oninput="DisplayMode.syncDispInput(this, 'rotation', 'x')">
<input type="number" class="tool disp_text" id="rotation_x" oninput="DisplayMode.syncDispInput(this, 'rotation', 'x')" min="-180" max="180" step="0.5" value="0">
</div>
<div class="bar">
<input type="range" class="tool disp_range" id="rotation_y" name="" min="-180" max="180" step="1" value="0" oninput="DisplayMode.syncDispInput(this, 'rotation', 'y')">
<input type="number" class="tool disp_text" id="rotation_y" oninput="DisplayMode.syncDispInput(this, 'rotation', 'y')" min="-180" max="180" step="0.5" value="0">
</div>
<div class="bar">
<input type="range" class="tool disp_range" id="rotation_z" name="" min="-180" max="180" step="1" value="0" oninput="DisplayMode.syncDispInput(this, 'rotation', 'z')">
<input type="number" class="tool disp_text" id="rotation_z" oninput="DisplayMode.syncDispInput(this, 'rotation', 'z')" min="-180" max="180" step="0.5" value="0">
</div>
<div id="display_sliders">
<p class="tl">display.rotation</p><div class="tool head_right" v-on:click="resetChannel('rotation')"><i class="material-icons">replay</i></div>
<div class="bar" v-for="axis in [0, 1, 2]">
<input type="range" class="tool disp_range" v-model.number="slot.rotation[axis]" min="-180" max="180" step="1" value="0" @input="change" @input="change(axis, 'rotation')" @mousedown="start" @change="save">
<input type="number" class="tool disp_text" v-model.number="slot.rotation[axis]" min="-180" max="180" step="0.5" value="0" @input="change(axis, 'rotation');save()" @mousedown="start">
</div>
<p class="tl">display.translation</p><div class="tool head_right" v-on:click="resetChannel('translation')"><i class="material-icons">replay</i></div>
<div class="bar" v-for="axis in [0, 1, 2]">
<input type="range" class="tool disp_range" v-model.number="slot.translation[axis]"
v-bind:min="Math.abs(slot.translation[axis]) < 10 ? -20 : (slot.translation[axis] > 0 ? -70*3+10 : -80)"
v-bind:max="Math.abs(slot.translation[axis]) < 10 ? 20 : (slot.translation[axis] < 0 ? 70*3-10 : 80)"
v-bind:step="Math.abs(slot.translation[axis]) < 10 ? 0.25 : 1"
value="0" @input="change(axis, 'rotation')" @mousedown="start" @change="save">
<input type="number" class="tool disp_text" v-model.number="slot.translation[axis]" min="-80" max="80" step="0.5" value="0" @input="change(axis, 'rotation');save()" @mousedown="start">
</div>
<p class="tl">display.translation</p><div class="tool head_right" onclick="DisplayMode.resetDisplaySettings('translation')"><i class="material-icons">replay</i></div>
<div class="bar">
<input type="range" class="tool disp_range" id="translation_x" name="" min="-32" max="32" step="0.5" value="0" oninput="DisplayMode.syncDispInput(this, 'translation', 'x')">
<input type="number" class="tool disp_text" id="translation_x" oninput="DisplayMode.syncDispInput(this, 'translation', 'x')" min="-80" max="80" step="0.5" value="0">
</div>
<div class="bar">
<input type="range" class="tool disp_range" id="translation_y" name="" min="-32" max="32" step="0.5" value="0" oninput="DisplayMode.syncDispInput(this, 'translation', 'y')">
<input type="number" class="tool disp_text" id="translation_y" oninput="DisplayMode.syncDispInput(this, 'translation', 'y')" min="-80" max="80" step="0.5" value="0">
</div>
<div class="bar">
<input type="range" class="tool disp_range" id="translation_z" name="" min="-32" max="32" step="0.5" value="0" oninput="DisplayMode.syncDispInput(this, 'translation', 'z')">
<input type="number" class="tool disp_text" id="translation_z" oninput="DisplayMode.syncDispInput(this, 'translation', 'z')" min="-80" max="80" step="0.5" value="0">
</div>
<p class="tl">display.scale</p><div class="tool head_right" onclick="DisplayMode.resetDisplaySettings('scale')"><i class="material-icons">replay</i></div>
<div class="bar">
<div class="tool display_scale_invert" id="display_scale_invert_x" onclick="DisplayMode.syncDispMirror(this, 'x')">
<i class="material-icons">check_box_outline_blank</i><div class="tooltip tl">display.mirror</div>
<p class="tl">display.scale</p><div class="tool head_right" v-on:click="resetChannel('scale')"><i class="material-icons">replay</i></div>
<div class="bar" v-for="axis in [0, 1, 2]">
<div class="tool display_scale_invert" v-on:click="invert(axis)">
<i class="material-icons">{{ slot.mirror[axis] ? 'check_box' : 'check_box_outline_blank' }}</i><div class="tooltip tl">display.mirror</div>
</div>
<input type="range" class="tool disp_range scaleRange" v-model.number="slot.scale[axis]" v-bind:id="'scale_range_'+axis"
v-bind:min="slot.scale[axis] > 1 ? -2 : 0"
v-bind:max="slot.scale[axis] > 1 ? 4 : 2"
step="0.01"
value="0" @input="change(axis, 'scale')" @mousedown="start" @change="save">
<input type="number" class="tool disp_text" v-model.number="slot.scale[axis]" min="0" max="4" step="0.01" value="0" @input="change(axis, 'scale');save()" @mousedown="start">
</div>
<input type="range" class="tool disp_range scaleRange" id="scale_x" name="" min="-4" max="4" step="0.1" value="0" oninput="DisplayMode.syncDispInput(this, 'scaleRange', 'x', event)">
<input type="number" class="tool disp_text scale" id="scale_x" oninput="DisplayMode.syncDispInput(this, 'scale', 'x')" step="0.1" min="-4" max="4">
</div>
<div class="bar">
<div class="tool display_scale_invert" id="display_scale_invert_y" onclick="DisplayMode.syncDispMirror(this, 'x')">
<i class="material-icons">check_box_outline_blank</i><div class="tooltip tl">display.mirror</div>
</div>
<input type="range" class="tool disp_range scaleRange" id="scale_y" name="" min="-4" max="4" step="0.1" value="0" oninput="DisplayMode.syncDispInput(this, 'scaleRange', 'y', event)">
<input type="number" class="tool disp_text scale" id="scale_y" oninput="DisplayMode.syncDispInput(this, 'scale', 'y')" step="0.1" min="-4" max="4">
</div>
<div class="bar">
<div class="tool display_scale_invert" id="display_scale_invert_z" onclick="DisplayMode.syncDispMirror(this, 'x')">
<i class="material-icons">check_box_outline_blank</i><div class="tooltip tl">display.mirror</div>
</div>
<input type="range" class="tool disp_range scaleRange" id="scale_z" name="" min="-4" max="4" step="0.1" value="0" oninput="DisplayMode.syncDispInput(this, 'scaleRange', 'z', event)">
<input type="number" class="tool disp_text scale" id="scale_z" oninput="DisplayMode.syncDispInput(this, 'scale', 'z')" step="0.1" min="-4" max="4">
</div>
</div>
<div id="animations" class="panel">
@ -868,12 +849,12 @@
v-bind:class="{ selected: texture.selected, particle: texture.particle}"
v-bind:texid="texture.id"
class="texture"
v-on:click.stop="texture.select()"
v-on:click.stop="texture.select($event)"
v-on:dblclick="texture.openMenu($event)"
@contextmenu.prevent.stop="texture.showContextMenu($event)"
>
<div class="texture_icon_wrapper">
<img v-bind:texid="texture.id" v-bind:src="texture.source" class="texture_icon" width="48px" alt="missing image" v-if="texture.show_icon" />
<img v-bind:texid="texture.id" v-bind:src="texture.source" class="texture_icon" width="48px" alt="[E]" v-if="texture.show_icon" />
<i class="material-icons texture_error" title="Image Error" v-if="texture.error">error_outline</i>
<i class="texture_movie fa fa_big fa-film" title="Animated Texture" v-if="texture.frameCount > 1"></i>
</div>
@ -959,6 +940,7 @@
<div class="f_right">
{{ Prop.fps }} FPS
</div>
<div id="status_progress" v-if="Prop.progress" v-bind:style="{width: Prop.progress*100+'%'}"></div>
</div>
<script>
initCanvas()

View File

@ -482,7 +482,7 @@ THREE.OrbitControls = function ( object, preview ) {
// console.log( 'handleMouseWheel' );
if ( event.deltaY < 0 ) {
dollyOut( getZoomScale() );
} else if ( event.deltaY > 0 ) {

File diff suppressed because it is too large Load Diff

View File

@ -146,6 +146,7 @@ class Action extends BarItem {
this.menu_node = $(`<li>${this.name}</li>`).get(0)
$(this.node).add(this.menu_node).prepend(this.icon_node)
$(this.node).click(function(e) {scope.trigger(e)})
if (data.linked_setting) {
this.toggleLinkedSetting(false)
}
@ -194,12 +195,14 @@ class Action extends BarItem {
}
}
}
class Tool extends Action {
constructor(data) {
super(data)
var scope = this;
this.type = 'tool'
this.toolbar = data.toolbar;
this.alt_tool = data.alt_tool;
this.selectFace = data.selectFace;
this.selectCubes = data.selectCubes !== false;
this.paintTool = data.paintTool;
@ -224,6 +227,7 @@ class Tool extends Action {
Toolbox.selected.onUnselect()
}
Toolbox.selected = this;
delete Toolbox.original;
if (this.transformerMode) {
Transformer.setMode(this.transformerMode)
@ -234,7 +238,6 @@ class Tool extends Action {
}
if (this.toolbar && Toolbars[this.toolbar]) {
Toolbars[this.toolbar].toPlace('tool_options')
resizeWindow()
} else {
$('.toolbar_wrapper.tool_options > .toolbar').detach()
}
@ -382,7 +385,7 @@ class NumSlider extends Widget {
var scope = this;
var number = 0;
//Math
var offset = Math.round((event.clientX-scope.left)/50)
var offset = Math.round((event.clientX-scope.left)/30)
if (scope.uv === false) {
offset *= canvasGridSize();
}
@ -461,7 +464,7 @@ class NumSlider extends Widget {
if (!BARS.condition(this.condition)) return;
var number = this.get();
this.setValue(number)
$('#nslide_head #nslide_offset').text(this.name+': '+number)
$('#nslide_head #nslide_offset').text(this.name+': '+this.value)
}
}
class BarSlider extends Widget {
@ -643,9 +646,6 @@ class Toolbar {
var items = data.children
if (!force && BARS.stored[scope.id] && typeof BARS.stored[scope.id] === 'object') {
items = BARS.stored[scope.id]
if (this.id === 'tools' && !items.includes('animation_mode_tool')) {
items.push('animation_mode_tool')
}
}
if (items && items.constructor.name === 'Array') {
var content = $(scope.node).find('div.content')
@ -786,15 +786,7 @@ var BARS = {
stored: {},
editing_bar: undefined,
action_definers: [],
condition: function(condition, context) {
if (condition === undefined) {
return true;
} else if (typeof condition === 'function') {
return condition(context)
} else {
return !!condition
}
},
condition: Condition,
defineActions: function(definer) {
BARS.action_definers.push(definer)
},
@ -837,7 +829,9 @@ var BARS = {
selectFace: true,
transformerMode: 'translate',
toolbar: 'transform',
keybind: new Keybind({key: 86})
alt_tool: 'resize_tool',
keybind: new Keybind({key: 86}),
condition: () => Modes.id === 'edit' || Modes.id === 'animate' || Modes.id === 'display'
})
new Tool({
id: 'resize_tool',
@ -846,7 +840,20 @@ var BARS = {
selectFace: true,
transformerMode: 'scale',
toolbar: 'transform',
keybind: new Keybind({key: 83})
alt_tool: 'move_tool',
keybind: new Keybind({key: 83}),
condition: () => Modes.id === 'edit' || Modes.id === 'animate' || Modes.id === 'display'
})
new Tool({
id: 'rotate_tool',
icon: 'sync',
category: 'tools',
selectFace: true,
transformerMode: 'rotate',
toolbar: 'transform',
alt_tool: 'move_tool',
keybind: new Keybind({key: 82}),
condition: () => Modes.id === 'edit' || Modes.id === 'animate' || Modes.id === 'display'
})
new Tool({
id: 'vertex_snap_tool',
@ -857,6 +864,7 @@ var BARS = {
selectCubes: true,
cursor: 'copy',
keybind: new Keybind({key: 88}),
condition: () => Modes.id === 'edit',
onCanvasClick: function(data) {
Vertexsnap.canvasClick(data)
},
@ -877,47 +885,11 @@ var BARS = {
scale: true
}
})
new Tool({
id: 'display_mode_tool',
icon: 'icon-player',
transformerMode: 'hidden',
category: 'tools',
selectCubes: false,
condition: () => !Blockbench.entity_mode,
onCanvasClick: function(data) {
},
onSelect: function() {
enterDisplaySettings()
},
onUnselect: function() {
exitDisplaySettings()
}
})
new Tool({
id: 'animation_mode_tool',
icon: 'movie',
transformerMode: 'hidden',
category: 'tools',
selectCubes: false,
condition: () => Blockbench.entity_mode,
onCanvasClick: function(data) {
if (data.cube && data.cube.parent.type === 'group') {
data.cube.parent.select()
}
},
onSelect: function() {
Animator.join()
},
onUnselect: function() {
Animator.leave()
}
})
new Action({
id: 'swap_tools',
icon: 'swap_horiz',
category: 'tools',
condition: () => !Animator.open,
keybind: new Keybind({key: 32}),
click: function () {
if (Toolbox.selected.id === 'move_tool') {
@ -944,6 +916,15 @@ var BARS = {
shell.showItemInFolder(Prop.file_path)
}
})
new Action({
id: 'open_backup_folder',
icon: 'fa-archive',
category: 'file',
condition: () => isApp,
click: function (e) {
shell.showItemInFolder(app.app.getPath('userData')+osfs+'backups'+osfs+'.')
}
})
new Action({
id: 'settings_window',
icon: 'settings',
@ -951,12 +932,6 @@ var BARS = {
keybind: new Keybind({key: 69, ctrl: true}),
click: function () {openSettings()}
})
new Action({
id: 'plugins_window',
icon: 'extension',
category: 'blockbench',
click: function () {showDialog('plugins')}
})
new Action({
id: 'update_window',
icon: 'update',
@ -979,22 +954,6 @@ var BARS = {
})
//Edit
new Action({
id: 'undo',
icon: 'undo',
category: 'edit',
condition: () => (!display_mode),
keybind: new Keybind({key: 90, ctrl: true}),
click: function () {Undo.undo()}
})
new Action({
id: 'redo',
icon: 'redo',
category: 'edit',
condition: () => (!display_mode),
keybind: new Keybind({key: 89, ctrl: true}),
click: function () {Undo.redo()}
})
new Action({
id: 'copy',
icon: 'fa-clone',
@ -1023,7 +982,7 @@ var BARS = {
id: 'duplicate',
icon: 'content_copy',
category: 'edit',
condition: () => (!display_mode && !Animator.open),
condition: () => (!display_mode && !Animator.open && selected.length),
keybind: new Keybind({key: 68, ctrl: true}),
click: function () {
duplicateCubes();
@ -1033,7 +992,7 @@ var BARS = {
id: 'delete',
icon: 'delete',
category: 'edit',
condition: () => (!display_mode && !Animator.open),
condition: () => (!display_mode && !Animator.open && selected.length),
keybind: new Keybind({key: 46}),
click: function () {
deleteCubes();
@ -1267,10 +1226,12 @@ var BARS = {
children: [
'move_tool',
'resize_tool',
'rotate_tool',
'vertex_snap_tool',
'brush_tool',
'display_mode_tool',
'animation_mode_tool'
'fill_tool',
'eraser',
'color_picker'
],
default_place: true
})
@ -1500,6 +1461,25 @@ var BARS = {
uv_dialog.all_editors.forEach((editor) => {
editor.updateInterface()
})
BARS.updateToolToolbar()
},
updateToolToolbar: function() {
if (!Toolbars || !Toolbars[Toolbox.selected.toolbar]) return;
Toolbars[Toolbox.selected.toolbar].children.forEach(function(action) {
if (action.type === 'numslider') {
action.setWidth(40)
}
})
if ($('div.tool_options .toolbar').length > 0) {
var sliders = $('header .tool.nslide_tool').length
var space = $(window).width() - $('div.tool_options .toolbar').offset().left - $('div.tool_options .toolbar').width() - $('#mode_selector').width() + 6
var width = limitNumber(37 + space / sliders, 40, 80)
Toolbars[Toolbox.selected.toolbar].children.forEach(function(action) {
if (action.type === 'numslider') {
action.setWidth(width)
}
})
}
}
}

View File

@ -117,6 +117,9 @@ class Animation {
for (var uuid in this.bones) {
this.bones[uuid].displayFrame(time)
}
if (selected_group) {
centerTransformer()
}
}
add() {
if (!Animator.animations.includes(this)) {
@ -174,9 +177,7 @@ class Animation {
delete
*/
])
/*
*/
class BoneAnimator {
constructor() {
this.keyframes = []
@ -200,26 +201,31 @@ class BoneAnimator {
y: values[1],
z: values[2]
})
if (values[3]) {
keyframe.extend({w: values[3], isQuaternion: true})
}
} else if (typeof values === 'number' || typeof values === 'string') {
keyframe.extend({
x: values
})
} else {
var ref = this.interpolate(time, channel)
var ref = this.interpolate(time, channel, true)
if (ref) {
let e = 1e2
ref.forEach((r, i) => {
if (!isNaN(r)) {
ref[i] = Math.round(parseFloat(r)*e)/e
}
})
keyframe.extend({
x: Math.round(ref[0]*e)/e,
y: Math.round(ref[1]*e)/e,
z: Math.round(ref[2]*e)/e,
w: ref.length === 4 ? Math.round(ref[3]*e)/e : undefined,
x: ref[0],
y: ref[1],
z: ref[2],
w: ref.length === 4 ? ref[3] : undefined,
isQuaternion: ref.length === 4
})
}
}
if (values.length > 3) {
keyframe.extend({w: values[3], isQuaternion: true})
}
this.keyframes.push(keyframe)
keyframe.parent = this;
return keyframe;
@ -270,7 +276,7 @@ class BoneAnimator {
}
return this;
}
interpolate(time, channel) {
interpolate(time, channel, allow_expression) {
var i = 0;
var before = false
var after = false
@ -304,31 +310,28 @@ class BoneAnimator {
} else {
let alpha = Math.lerp(before.time, after.time, time)
result = [
before.calc('x') + (after.calc('x') - before.calc('x')) * alpha
before.getLerp(after, 'x', alpha, allow_expression)
]
if (before.channel !== 'scale') {
result[1] = (before.calc('y') + (after.calc('y') - before.calc('y')) * alpha)
result[1] = before.getLerp(after, 'y', alpha, allow_expression)
result[2] = before.getLerp(after, 'z', alpha, allow_expression)
}
if (before.channel !== 'scale') {
result[2] = (before.calc('z') + (after.calc('z') - before.calc('z')) * alpha)
}
if (before.isQuaternion && after.isQuaternion) {
result[3] = (before.calc('w') + (after.calc('w') - before.calc('w')) * alpha)
if (before.isQuaternion && after.isQuaternion) {
result[3] = before.getLerp(after, 'q', alpha, allow_expression)
}
}
if (result && result.type === 'keyframe') {
let keyframe = result
let method = allow_expression ? 'get' : 'calc'
result = [
keyframe.calc('x')
keyframe[method]('x')
]
if (keyframe.channel !== 'scale') {
result[1] = keyframe.calc('y')
}
if (keyframe.channel !== 'scale') {
result[2] = keyframe.calc('z')
result[1] = keyframe[method]('y')
result[2] = keyframe[method]('z')
}
if (keyframe.isQuaternion) {
result[3] = keyframe.calc('w')
result[3] = keyframe[method]('w')
}
}
return result
@ -346,6 +349,7 @@ class BoneAnimator {
this.displayScale(result)
}
}
this.group.getMesh().updateMatrixWorld()
}
select() {
var duplicates;
@ -422,6 +426,66 @@ class Keyframe {
if (axis === 'x' || axis === 'y' || axis === 'z' || axis === 'w') {
this[axis] = value
}
return this;
}
offset(axis, amount) {
var value = this.get(axis)
if (!value || value === '0') {
this.set(axis, amount)
}
if (typeof value === 'number') {
this.set(axis, value+amount)
return value+amount
}
var start = value.match(/^-?\s*\d*(\.\d+)?\s*(\+|-)/)
if (start) {
var number = parseFloat( start[0].substr(0, start[0].length-1) ) + amount
value = trimFloatNumber(number) + value.substr(start[0].length-1)
} else {
var end = value.match(/(\+|-)\s*\d*(\.\d+)?\s*$/)
if (end) {
var number = (parseFloat( end[0] ) + amount)+''
value = value.substr(0, end.index) + (number.substr(0,1)=='-'?'':'+') + trimFloatNumber(number)
} else {
value = trimFloatNumber(amount) +(value.substr(0,1)=='-'?'':'+')+ value
}
}
this.set(axis, value)
return value;
/*
function iterate(string, index) {
if (!isNaN(string)) {
return [index, string.length]
}
var splices = splitUpMolang(string, ['+', '-'])
if (!splices) return false;
var result = iterate(splices[1], index+splices[0].length)
if (result) return result;
result = iterate(splices[0], index)
if (result) return result;
}
var p = iterate(value, 0)
if (p) {
value = value.substr(0, p[0]) + amount + value.substr(p[0]+p[1])
this.set(axis, value)
} else {
amount = ''+amount
if (amount.substr(0, 1) !== '-') amount = '+'+amount
this.set(axis, value+amount)
}*/
}
getLerp(other, axis, amount, allow_expression) {
if (allow_expression && this.get(axis) === other.get(axis)) {
return this.get(axis)
} else {
let calc = this.calc(axis)
return calc + (other.calc(axis) - calc) * amount
}
}
getArray() {
if (this.channel === 'scale') {
@ -531,6 +595,8 @@ class Keyframe {
extend(data) {
if (data.channel && Animator.possible_channels[data.channel]) {
Merge.string(this, data, 'channel')
} else if (typeof data.channel === 'number') {
this.channel = Animator.channel_index[data.channel]
}
Merge.number(this, data, 'time')
@ -540,7 +606,7 @@ class Keyframe {
Merge.string(this, data, 'w')
Merge.boolean(this, data, 'isQuaternion')
this.channel_index = this.channel === 'rotation' ? 0 : (this.channel === 'position' ? 1 : 2)
this.channel_index = Animator.channel_index.indexOf(this.channel)
return this;
}
undoCopy() {
@ -583,6 +649,7 @@ class Keyframe {
*/
])
function updateKeyframeValue(obj) {
var axis = $(obj).attr('axis')
var value = $(obj).val()
@ -614,10 +681,21 @@ function updateKeyframeSelection() {
$('#keyframe_bar_y, #keyframe_bar_z').toggle(first.channel !== 'scale')
$('#keyframe_bar_w').toggle(first.channel === 'rotation' && first.isQuaternion)
$('#keyframe_bar_x input').val(first['x'])
$('#keyframe_bar_y input').val(first['y'])
$('#keyframe_bar_z input').val(first['z'])
$('#keyframe_bar_w input').val(first['w'])
var values = [
first.get('x'),
first.get('y'),
first.get('z'),
first.get('w')
]
values.forEach((v, vi) => {
if (typeof v === 'number') {
values[vi] = trimFloatNumber(v)
}
})
$('#keyframe_bar_x input').val(values[0])
$('#keyframe_bar_y input').val(values[1])
$('#keyframe_bar_z input').val(values[2])
$('#keyframe_bar_w input').val(values[3])
BarItems.slider_keyframe_time.update()
} else {
@ -656,7 +734,7 @@ function removeSelectedKeyframes() {
const Animator = {
possible_channels: {rotation: true, position: true, scale: true},
channel_index: {rotation: true, position: true, scale: true},
channel_index: ['rotation', 'position', 'scale'],
open: false,
animations: [],
frame: 0,
@ -669,12 +747,9 @@ const Animator = {
if (quad_previews.enabled) {
quad_previews.enabled_before = true
main_preview.fullscreen()
}
main_preview.fullscreen()
main_preview.setNormalCamera()
main_preview.camPers.position.set(-80, 40, -30)
main_preview.camPers.setFocalLength(45)
$('body').addClass('animation_mode')
$('.m_edit').hide()
@ -753,6 +828,9 @@ const Animator = {
}
}
}
if (!Animator.selected) {
animation.select()
}
}
if (isApp && file.path) {
Prop.animation_path = file.path
@ -819,12 +897,20 @@ const Timeline = {
selected: [],//frames
second: 0,
playing: false,
setTime: function(seconds) {
setTime: function(seconds, editing) {
seconds = limitNumber(seconds, 0, 1000)
Timeline.vue._data.marker = seconds
Timeline.second = seconds
Timeline.setTimecode(seconds)
if (!editing) {
Timeline.setTimecode(seconds)
}
Timeline.updateSize()
//Scroll
var scroll = $('#timeline_inner').scrollLeft()
var marker = Timeline.second * Timeline.vue._data.size + 8
if (marker < scroll || marker > scroll + $('#timeline_inner').width()) {
$('#timeline_inner').scrollLeft(marker-16)
}
},
setTimecode: function(time) {
let m = Math.floor(time/60)
@ -882,7 +968,65 @@ const Timeline = {
}).focusout(e => {
Undo.finishEdit('edit keyframe')
})
$('#timeline_corner').click(e => {
if ($('#timeline_corner').attr('contenteditable') == 'true') return;
$('#timeline_corner').attr('contenteditable', true).focus().select()
var times = $('#timeline_corner').text().split(':')
while (times.length < 3) {
times.push('00')
}
var node = $('#timeline_corner').get(0).childNodes[0]
var selection = window.getSelection();
var range = document.createRange();
var sel = [0, node.length]
if (e.offsetX < 24) {
sel = [0, times[0].length]
} else if (e.offsetX < 54) {
sel = [times[0].length+1, times[1].length]
} else if (e.offsetX < 80) {
sel = [times[0].length+times[1].length+2, times[2].length]
}
sel[1] = limitNumber(sel[0]+sel[1], sel[0], node.length)
range.setStart(node, sel[0])
range.setEnd(node, sel[1])
selection.removeAllRanges();
selection.addRange(range);
})
.on('focusout keydown', e => {
if (e.type === 'focusout' || Keybinds.extra.confirm.keybind.isTriggered(e) || Keybinds.extra.cancel.keybind.isTriggered(e)) {
$('#timeline_corner').attr('contenteditable', false)
Timeline.setTimecode(Timeline.second)
}
})
.on('keyup', e => {
var times = $('#timeline_corner').text().split(':')
times.forEach((t, i) => {
times[i] = parseInt(t)
if (isNaN(times[i])) {
times[i] = 0
}
})
while (times.length < 3) {
times.push(0)
}
var seconds
= times[0]*60
+ limitNumber(times[1], 0, 59)
+ limitNumber(times[2]/30, 0, 29)
if (Math.abs(seconds-Timeline.second) > 1e-3 ) {
Timeline.setTime(seconds, true)
if (Animator.selected) {
Animator.preview()
}
}
})
Timeline.is_setup = true
Timeline.setTime(0)
},
update: function() {
//Draggable
@ -1073,7 +1217,7 @@ BARS.defineActions(function() {
condition: () => Animator.open,
click: function () {
var animation = new Animation({
name: 'animation.' + (Project.parent.replace(/geometry./, '')||'model') + '.new'
name: 'animation.' + (Project.parent||'model') + '.new'
}).add().select()
}
@ -1136,6 +1280,10 @@ BARS.defineActions(function() {
condition: () => Animator.open,
click: function () {
if (!Animator.selected) {
Blockbench.showQuickMessage('message.no_animation_selected')
return;
}
if (Timeline.playing) {
Timeline.pause()
} else {

View File

@ -74,6 +74,7 @@ class API {
return jq.get(0)
}
showQuickMessage(message, time) {
$('#quick_message_box').remove()
var quick_message_box = $('<div id="quick_message_box" class="hidden"></div>')
$('body').append(quick_message_box)
@ -99,6 +100,9 @@ class API {
Prop.file_name = Prop.file_name_alt||''
}
}
setProgress(progress, time, bar) {
setProgressBar(bar, progress||0, time)
}
showMessage(message, location) {
if (location === 'status_bar') {
Blockbench.showStatusMessage(message)
@ -277,6 +281,8 @@ class API {
} else {
reader.readAsDataURL(file)
}
} else if (options.readtype === 'buffer') {
reader.readAsArrayBuffer(file)
} else /*text*/ {
reader.readAsText(file)
}
@ -367,6 +373,7 @@ class API {
content
startpath
savetype
project_file
custom_writer
*/
if (Blockbench.isWeb) {
@ -386,6 +393,10 @@ class API {
var blob = new Blob([options.content], {type: "text/plain;charset=utf-8"});
saveAs(blob, file_name, {autoBOM: true})
}
if (options.project_file) {
Prop.project_saved = true;
setProjectTitle(options.name)
}
if (typeof cb === 'function') {
cb()
}
@ -399,31 +410,51 @@ class API {
? options.startpath.replace(/\.\w+$/, '')
: options.name
}, function (file_path) {
if (file_path === undefined) {
Blockbench.writeFile(file_path, options, cb)
})
}
}
writeFile(file_path, options, cb) {
/*
content
savetype
project_file
custom_writer
*/
if (!isApp || file_path === undefined) {
return;
}
if (options.savetype === 'image' && typeof options.content === 'string') {
if (options.content.substr(0, 10) === 'data:image') {
options.content = nativeImage.createFromDataURL(options.content).toPNG()
} else {
options.content = nativeImage.createFromPath(options.content).toPNG()
}
}
if (options.custom_writer) {
options.custom_writer(options.content, file_path)
} else {
fs.writeFile(file_path, options.content, function (err) {
if (err) {
console.log('Error exporting file: '+err)
return;
}
if (options.savetype === 'image' && typeof options.content === 'string') {
if (options.content.substr(0, 10) === 'data:image') {
options.content = nativeImage.createFromDataURL(options.content).toPNG()
} else {
options.content = nativeImage.createFromPath(options.content).toPNG()
}
}
if (options.custom_writer) {
options.custom_writer(options.content, file_path)
} else {
fs.writeFile(file_path, options.content, function (err) {
if (err) {
console.log('Error exporting file: '+err)
return;
}
if (cb) {
cb(file_path)
}
})
if (cb) {
cb(file_path)
}
})
}
if (options.project_file) {
Prop.file_path = file_path
Prop.project_saved = true;
Project.name = pathToName(file_path, true)
setProjectTitle(pathToName(file_path, false))
addRecentProject({name: pathToName(file_path, Blockbench.entity_mode ? 'mobs_id' : false), path: Prop.file_path})
Blockbench.showQuickMessage(tl('message.save_file', [Project.name]))
if (Blockbench.hasFlag('close_after_saving')) {
closeBlockbenchWindow()
}
}
}
//Flags
addFlag(flag) {

273
js/app.js
View File

@ -27,7 +27,7 @@ $(document).ready(function() {
if (fs.existsSync(app.app.getPath('userData')+osfs+'backups') === false) {
fs.mkdirSync( app.app.getPath('userData')+osfs+'backups')
}
createBackup()
createBackup(true)
$('.web_only').remove()
if (__dirname.includes('C:\\xampp\\htdocs\\blockbench\\web')) {
Blockbench.addFlag('dev')
@ -206,10 +206,6 @@ function changeImageEditor(texture) {
dialog.hide()
}
}).show()
/*
Ask for file IF
_other selected
*/
}
function selectImageEditorFile(texture) {
app.dialog.showOpenDialog(currentwindow, {
@ -254,79 +250,80 @@ function openDefaultTexturePath() {
}
function findEntityTexture(mob, return_path) {
var textures = {
'geometry.chicken': 'chicken',
'geometry.blaze': 'blaze',
'geometry.llamaspit': 'llama/spit',
'geometry.llama': 'llama/llama_creamy',
'geometry.dragon': 'dragon/dragon',
'geometry.ghast': 'ghast/ghast',
'geometry.slime': 'slime/slime',
'geometry.slime.armor': 'slime/slime',
'geometry.lavaslime': 'slime/magmacube',
'geometry.silverfish': 'silverfish',
'geometry.shulker': 'shulker/shulker_undyed',
'geometry.rabbit': 'rabbit/brown',
'geometry.horse': 'horse/horse_brown',
'geometry.horse.v2': 'horse2/horse_brown',
'geometry.humanoid': 'steve',
'geometry.creeper': 'creeper/creeper',
'geometry.enderman': 'enderman/enderman',
'geometry.zombie': 'zombie/zombie',
'geometry.zombie.husk': 'zombie/husk',
'geometry.zombie.drowned': 'zombie/drowned',
'geometry.pigzombie': 'pig/pigzombie',
'geometry.pigzombie.baby': 'pig/pigzombie',
'geometry.skeleton': 'skeleton/skeleton',
'geometry.skeleton.wither': 'skeleton/wither_skeleton',
'geometry.skeleton.stray': 'skeleton/stray',
'geometry.squid': 'squid',
'geometry.spider': 'spider/spider',
'geometry.cow': 'cow/cow',
'geometry.mooshroom': 'cow/mooshroom',
'geometry.sheep.sheared': 'sheep/sheep',
'geometry.sheep': 'sheep/sheep',
'geometry.phantom': 'phantom',
'geometry.pig': 'pig/pig',
'geometry.bat': 'bat',
'geometry.dolphin': 'dolphin',
'geometry.irongolem': 'iron_golem',
'geometry.snowgolem': 'snow_golem',
'geometry.zombie.villager': 'zombie_villager/zombie_farmer',
'geometry.evoker': 'illager/evoker',
'geometry.vex': 'vex/vex',
'geometry.vindicator': 'vindicator',
'geometry.wolf': 'wolf/wolf',
'geometry.ocelot': 'cat/ocelot',
'geometry.cat': 'cat/siamese',
'geometry.trident': 'trident',
'geometry.guardian': 'guardian',
'geometry.polarbear': 'polarbear',
'geometry.turtle': 'sea_turtle',
'geometry.villager': 'villager/farmer',
'geometry.villager.witch': 'witch',
'geometry.witherBoss': 'wither_boss/wither',
'geometry.agent': 'agent',
'geometry.armor_stand': 'armor_stand',
'geometry.parrot': 'parrot/parrot_red_blue',
'geometry.bed': 'bed/white',
'geometry.player_head': 'steve',
'geometry.mob_head': 'skeleton/skeleton',
'geometry.dragon_head': 'dragon/dragon',
'geometry.boat': 'boat/boat_oak',
'geometry.minecart': 'minecart',
'geometry.cod': 'fish/fish',
'geometry.pufferfish.small': 'fish/pufferfish',
'geometry.pufferfish.mid': 'fish/pufferfish',
'geometry.pufferfish.large': 'fish/pufferfish',
'geometry.salmon': 'fish/salmon',
'geometry.tropicalfish_a': 'fish/tropical_a',
'geometry.tropicalfish_b': 'fish/tropical_b',
'geometry.endermite': 'endermite',
'geometry.panda': 'panda/panda',
'chicken': 'chicken',
'blaze': 'blaze',
'llamaspit': 'llama/spit',
'llama': 'llama/llama_creamy',
'dragon': 'dragon/dragon',
'ghast': 'ghast/ghast',
'slime': 'slime/slime',
'slime.armor': 'slime/slime',
'lavaslime': 'slime/magmacube',
'silverfish': 'silverfish',
'shulker': 'shulker/shulker_undyed',
'rabbit': 'rabbit/brown',
'horse': 'horse/horse_brown',
'horse.v2': 'horse2/horse_brown',
'humanoid': 'steve',
'creeper': 'creeper/creeper',
'enderman': 'enderman/enderman',
'zombie': 'zombie/zombie',
'zombie.husk': 'zombie/husk',
'zombie.drowned': 'zombie/drowned',
'pigzombie': 'pig/pigzombie',
'pigzombie.baby': 'pig/pigzombie',
'skeleton': 'skeleton/skeleton',
'skeleton.wither': 'skeleton/wither_skeleton',
'skeleton.stray': 'skeleton/stray',
'squid': 'squid',
'spider': 'spider/spider',
'cow': 'cow/cow',
'mooshroom': 'cow/mooshroom',
'sheep.sheared': 'sheep/sheep',
'sheep': 'sheep/sheep',
'phantom': 'phantom',
'pig': 'pig/pig',
'bat': 'bat',
'dolphin': 'dolphin',
'irongolem': 'iron_golem',
'snowgolem': 'snow_golem',
'zombie.villager': 'zombie_villager/zombie_farmer',
'evoker': 'illager/evoker',
'vex': 'vex/vex',
'vindicator': 'vindicator',
'wolf': 'wolf/wolf',
'ocelot': 'cat/ocelot',
'cat': 'cat/siamese',
'trident': 'trident',
'guardian': 'guardian',
'polarbear': 'polarbear',
'turtle': 'sea_turtle',
'villager': 'villager/farmer',
'villager.witch': 'witch',
'witherBoss': 'wither_boss/wither',
'agent': 'agent',
'armor_stand': 'armor_stand',
'parrot': 'parrot/parrot_red_blue',
'bed': 'bed/white',
'player_head': 'steve',
'mob_head': 'skeleton/skeleton',
'dragon_head': 'dragon/dragon',
'boat': 'boat/boat_oak',
'minecart': 'minecart',
'cod': 'fish/fish',
'pufferfish.small': 'fish/pufferfish',
'pufferfish.mid': 'fish/pufferfish',
'pufferfish.large': 'fish/pufferfish',
'salmon': 'fish/salmon',
'tropicalfish_a': 'fish/tropical_a',
'tropicalfish_b': 'fish/tropical_b',
'endermite': 'endermite',
'panda': 'panda/panda',
}
var path = textures[mob.split(':')[0]]
mob = mob.split(':')[0].replace(/^geometry\./, '')
var path = textures[mob]
if (!path) {
path = mob.split(':')[0].replace('geometry.', '')
path = mob
}
if (path) {
var texture_path = Prop.file_path.split(osfs)
@ -368,68 +365,30 @@ function findBedrockAnimation() {
})
}
}
//Writers
function saveFile(props) {
if (Prop.file_path) {
Prop.project_saved = true;
setProjectTitle(pathToName(Prop.file_path, false))
addRecentProject({name: pathToName(Prop.file_path, true), path: Prop.file_path})
var extension = pathToExtension(Prop.file_path)
if (Blockbench.entity_mode === false) {
if (extension === 'jpm') {
BarItems.export_optifine_part.trigger()
} else {
var content = buildBlockModel()
fs.writeFile(Prop.file_path, content, function (err) {
if (err) {
console.log('Error Saving File: '+err)
}
if (props && props.closeAfter) {
preventClosing = false
setTimeout(function() {
currentwindow.close()
}, 12)
}
Blockbench.showQuickMessage(tl('message.save_file', [pathToName(Prop.file_path, true)]))
})
}
Blockbench.writeFile(Prop.file_path, {
project_file: true,
content: buildBlockModel()
})
} else {
if (extension === 'jem') {
BarItems.export_optifine_full.trigger()
} else {
var content = buildEntityModel({raw: true})
writeFileEntity(content, Prop.file_path)
}
writeFileEntity(buildEntityModel({raw: true}), Prop.file_path)
}
} else {
if (Blockbench.entity_mode === false) {
Blockbench.export({
type: 'JSON Model',
extensions: ['json'],
name: Project.name||'model',
startpath: Prop.file_path,
custom_writer: function(content, path) {
Prop.file_path = path
Project.name = pathToName(path, true)
saveFile(props)
}
})
BarItems.export_blockmodel.trigger()
} else {
var content = buildEntityModel({raw: true});
Blockbench.export({
type: 'JSON Entity Model',
extensions: ['json'],
name: Project.name,
startpath: Prop.file_path,
content: content,
custom_writer: writeFileEntity
})
BarItems.export_entity.trigger()
}
}
}
function writeFileEntity(content, filepath) {
Prop.file_path = filepath
var model_name = 'geometry.' + (Project.parent.replace(/^geometry\./, '')||'unknown')
fs.readFile(filepath, 'utf-8', function (errx, data) {
var obj = {}
if (!errx) {
@ -482,8 +441,6 @@ function writeFileEntity(content, filepath) {
}
}
}
var model_name = Project.parent
if (model_name == '') model_name = 'geometry.unknown'
obj[model_name] = content
content = autoStringify(obj)
@ -495,6 +452,9 @@ function writeFileEntity(content, filepath) {
Prop.project_saved = true;
setProjectTitle(pathToName(filepath, false))
addRecentProject({name: pathToName(filepath, 'mobs_id'), path: filepath})
if (Blockbench.hasFlag('close_after_saving')) {
closeBlockbenchWindow()
}
})
})
}
@ -503,18 +463,15 @@ function writeFileObj(content, filepath) {
return;
}
var content = buildOBJModel(pathToName(filepath, false))
//OBJECT
fs.writeFile(filepath, content.obj, function (err) {})
//MATERIAL
fs.writeFile(filepath.split('.obj').join('.mtl'), content.mtl, function (err) {})
//IMAGES
if (settings.obj_textures.value === true) {
for (var key in content.images) {
var texture = content.images[key]
if (content.images.hasOwnProperty(key) && texture.path) {
if (texture && texture.path) {
if (texture.mode === 'link') {
var native_image_instance = nativeImage.createFromPath(texture.path)
} else {
@ -533,6 +490,8 @@ function writeFileObj(content, filepath) {
}
Blockbench.showQuickMessage('message.save_obj')
}
//Open
function readFile(filepath, makeNew) {
fs.readFile(filepath, 'utf-8', function (err, data) {
@ -552,7 +511,34 @@ function readFile(filepath, makeNew) {
function createBackup(init) {
setTimeout(createBackup, limitNumber(parseFloat(settings.backup_interval.value), 1, 10e8)*60000)
var duration = parseInt(settings.backup_retain.value)+1
var folder_path = app.app.getPath('userData')+osfs+'backups'
var d = new Date()
var days = d.getDate() + (d.getMonth()+1)*30.44 + (d.getYear()-100)*365.25
if (init) {
fs.readdir(folder_path, (err, files) => {
if (!err) {
files.forEach((name, i) => {
var date = name.split('_')[1]
if (date) {
var nums = date.split('.')
nums.forEach((n, ni) => {
nums[ni] = parseInt(n)
})
var b_days = nums[0] + nums[1]*30.44 + nums[2]*365.25
if (!isNaN(b_days) && days - b_days > duration) {
try {
fs.unlinkSync(folder_path +osfs+ name)
} catch (err) {console.log(err)}
}
}
})
}
})
}
if (init || elements.length === 0) return;
var model = buildBlockModel({
backup: true,
raw: true,
@ -561,15 +547,15 @@ function createBackup(init) {
comment: false,
groups: true
})
var d = new Date()
var file_name = 'backup_'+d.getDate()+'.'+(d.getMonth()+1)+'.'+(d.getYear()-100)+'_'+d.getHours()+'.'+d.getMinutes()
var file_path = app.app.getPath('userData')+osfs+'backups'+osfs+file_name+'.json'
var file_path = folder_path+osfs+file_name+'.json'
fs.writeFile(file_path, JSON.stringify(model), function (err) {
if (err) {
console.log('Error creating backup: '+err)
}
})
//trimBackups
}
//Zoom
@ -593,7 +579,7 @@ window.onbeforeunload = function() {
}
}
function showSaveDialog(close) {
if (Blockbench.flags.includes('allow_reload')) {
if (Blockbench.hasFlag('allow_reload')) {
close = false
}
var unsaved_textures = 0;
@ -611,26 +597,29 @@ function showSaveDialog(close) {
noLink: true
})
if (answer === 0) {
saveFile({closeAfter: close})
return false;
if (close === true) {
Blockbench.addFlag('close_after_saving')
}
BarItems.save.trigger()
return true;
} else if (answer === 2) {
return false;
} else {
if (close === true) {
preventClosing = false
setTimeout(function() {
currentwindow.close()
}, 12)
closeBlockbenchWindow()
}
return true;
}
} else {
if (close === true) {
preventClosing = false
setTimeout(function() {
currentwindow.close()
}, 12)
closeBlockbenchWindow()
}
return true;
}
}
function closeBlockbenchWindow() {
preventClosing = false
setTimeout(function() {
currentwindow.close()
}, 12)
}

View File

@ -1,4 +1,4 @@
const appVersion = '2.2.2'
const appVersion = '2.3.0'
var osfs = '/'
var File, i;
const elements = [];
@ -24,6 +24,7 @@ const Prop = {
project_saved: true,
fps: 0,
zoom: 100,
progress: 0,
facing: 'north'
}
const Project = {
@ -118,6 +119,7 @@ function initializeApp() {
setupInterface()
setupDragHandlers()
Modes.options.edit.select()
Blockbench.setup_successful = true
}
function setupVue() {
@ -196,7 +198,53 @@ function setupVue() {
el: '#project_settings',
data: {Project}
})
//project_vue._data.Project = Project
DisplayMode.vue = new Vue({
el: '#display_sliders',
data: {
slot: new DisplaySlot()
},
methods: {
isMirrored: (axis) => {
if (display[display_slot]) {
return display[display_slot].scale[axis] < 0;
}
},
change: (axis, channel) => {
if (channel === 'scale') {
var val = limitNumber(DisplayMode.slot.scale[axis], 0, 4)
DisplayMode.slot.scale[axis] = val;
if (holding_shift) {
DisplayMode.slot.scale[0] = val;
DisplayMode.slot.scale[1] = val;
DisplayMode.slot.scale[2] = val;
}
} else if (channel === 'translation') {
DisplayMode.slot.translation[axis] = limitNumber(DisplayMode.slot.translation[axis], -80, 80)
} else {
DisplayMode.slot.rotation[axis] = Math.trimDeg(DisplayMode.slot.rotation[axis])
}
DisplayMode.updateDisplayBase()
},
resetChannel: (channel) => {
Undo.initEdit({display_slots: [display_slot]})
DisplayMode.slot.extend({[channel]: [0, 0, 0]})
Undo.finishEdit('reset display')
},
invert: (axis) => {
Undo.initEdit({display_slots: [display_slot]})
DisplayMode.slot.mirror[axis] = !DisplayMode.slot.mirror[axis];
DisplayMode.slot.update()
Undo.finishEdit('mirror display')
},
start: () => {
Undo.initEdit({display_slots: [display_slot]})
},
save: () => {
Undo.finishEdit('change_display')
}
}
})
Animator.vue = new Vue({
el: '#animations_list',
@ -204,7 +252,6 @@ function setupVue() {
animations: Animator.animations
}
})
//project_vue._data.Project = Project
Timeline.vue = new Vue({
@ -222,13 +269,19 @@ function setupVue() {
el: '#status_bar',
data: {Prop}
})
//project_vue._data.Prop = Prop
Modes.vue = new Vue({
el: '#mode_selector',
data: {
options: Modes.options
}
})
}
function canvasGridSize(shift, ctrl) {
if (!shift && !ctrl) {
return 16 / limitNumber(settings.edit_size.value, 1, 64)
return 16 / limitNumber(settings.edit_size.value, 1, 1024)
} else if (ctrl && shift) {
var basic = 16 / limitNumber(settings.edit_size.value, 1, 64)
var basic = 16 / limitNumber(settings.edit_size.value, 1, 1024)
var control = 16 / limitNumber(settings.ctrl_size.value, 1, 1024)
var shift = 16 / limitNumber(settings.shift_size.value, 1, 1024)
control = basic / control
@ -281,13 +334,17 @@ function updateSelection() {
Transformer.detach()
Transformer.hoverAxis = null;
if (display_mode) {
DisplayMode.centerTransformer()
}
elements.forEach(function(obj) {
var is_in_selection = selected.includes(obj)
if (is_in_selection !== obj.selected) {
obj.selected = is_in_selection
}
if (obj.selected === true) {
if (Toolbox.selected.transformerMode !== 'hidden' && obj.visibility === true) {
if (Toolbox.selected.transformerMode !== 'hidden' && obj.visibility === true && (Toolbox.selected.transformerMode !== 'rotate' || !Blockbench.entity_mode)) {
Transformer.attach(obj.getMesh())
}
}
@ -318,6 +375,9 @@ function updateSelection() {
if (settings.origin_size.value > 0 && selected_group.visibility) {
selected_group.getMesh().add(rot_origin)
}
if (Toolbox.selected.transformerMode === 'rotate') {
Transformer.attach(selected_group.getMesh())
}
} else {
$('.selection_only#options').css('visibility', 'hidden')
}
@ -426,6 +486,92 @@ function createSelection() {
}
hideDialog()
}
//Modes
class Mode extends KeybindItem {
constructor(data) {
super(data)
this.id = data.id;
this.name = data.name || tl('mode.'+this.id);
this.selected = false
this.default_tool = data.default_tool;
this.selectCubes = data.selectCubes !== false
this.condition = data.condition;
this.onSelect = data.onSelect;
this.onUnselect = data.onUnselect;
this.category = data.category;
Modes.options[this.id] = this;
}
select() {
if (typeof Modes.selected.onUnselect === 'function') {
Modes.selected.onUnselect()
}
if (Modes.selected.selected) {
Modes.selected.selected = false
}
if (typeof this.onSelect === 'function') {
this.onSelect()
}
this.selected = true;
Modes.id = this.id
Modes.selected = this;
updateInterface()
Canvas.updateRenderSides()
resizeWindow()
if (BarItems[this.default_tool]) {
BarItems[this.default_tool].select()
} else {
BarItems.move_tool.select()
}
updateSelection()
}
trigger() {
if (Condition(this.condition)) {
this.select()
}
}
}
const Modes = {
id: 'edit',
selected: false,
options: {},
};
BARS.defineActions(function() {
new Mode({
id: 'edit',
default_tool: 'move_tool',
keybind: new Keybind({key: 49})
})
new Mode({
id: 'paint',
default_tool: 'brush_tool',
keybind: new Keybind({key: 50})
})
new Mode({
id: 'display',
selectCubes: false,
default_tool: 'move_tool',
keybind: new Keybind({key: 51}),
condition: () => !Blockbench.entity_mode,
onSelect: () => {
enterDisplaySettings()
},
onUnselect: () => {
exitDisplaySettings()
},
})
new Mode({
id: 'animate',
default_tool: 'move_tool',
keybind: new Keybind({key: 51}),
condition: () => Blockbench.entity_mode,
onSelect: () => {
Animator.join()
},
onUnselect: () => {
Animator.leave()
}
})
})
//Misc
var Screencam = {
fullScreen: function(options, cb) {
@ -461,7 +607,7 @@ var Screencam = {
var is_gif = dataUrl.substr(5, 9) == 'image/gif'
img.src = dataUrl
var btns = [tl('dialog.save')]
var btns = [tl('dialog.cancel'), tl('dialog.save')]
if (!is_gif) {
btns.push(tl('message.screenshot.clipboard'))
}
@ -469,10 +615,10 @@ var Screencam = {
translateKey: 'screenshot',
icon: img,
buttons: btns,
confirm: 0,
cancel: btns.length-1
confirm: 1,
cancel: 0
}, function(result) {
if (result === 0) {
if (result === 1) {
app.dialog.showSaveDialog(currentwindow, {filters: [ {name: tl('data.image'), extensions: [is_gif ? 'gif' : 'png']} ]}, function (fileName) {
if (fileName === undefined) {
return;
@ -480,7 +626,7 @@ var Screencam = {
//fs.writeFile(fileName, screenshot.toPNG(), function (err) {})
fs.writeFile(fileName, Buffer(dataUrl.split(',')[1],'base64'), err => {})
})
} else if (result === 1) {
} else if (result === 2) {
clipboard.writeImage(screenshot)
}
})
@ -501,31 +647,81 @@ var Screencam = {
if (typeof options !== 'object') {
options = {}
}
if (!options.length) {
options.length = 1000
}
var interval = options.fps ? (1000/options.fps) : 100
var gif = new GIF({
repeat: options.repeat,
quality: options.quality,
transparent: 0x000000,
})
var frame_count = (options.length/interval)
/*
gif.on('finished', blob => {
var reader = new FileReader()
reader.onload = () => {
Screencam.returnScreenshot(reader.result, cb)
}
if (Animator.open && Timeline.playing) {
Timeline.pause()
}
reader.readAsDataURL(blob)
if (!options.silent) {
Blockbench.setProgress(0)
Blockbench.setStatusBarText()
}
})
if (!options.silent) {
Blockbench.setStatusBarText(tl('status_bar.recording_gif'))
gif.on('progress', Blockbench.setProgress)
}
for (var frame = 0; frame < frame_count; frame++) {
gif.addFrame(quad_previews.current.canvas, {delay: interval})
}
gif.render()*/
//Problem with this ^^ When recording, frames get generated as fast as possible
gif.on('finished', blob => {
var reader = new FileReader()
reader.onload = () => {
if (!options.silent) {
Blockbench.setProgress(0)
Blockbench.setStatusBarText()
}
Screencam.returnScreenshot(reader.result, cb)
}
reader.readAsDataURL(blob)
})
gif.addFrame(quad_previews.current.canvas)
if (!options.silent) {
Blockbench.setStatusBarText(tl('status_bar.recording_gif'))
gif.on('progress', Blockbench.setProgress)
}
var frames = 0;
var loop = setInterval(() => {
gif.addFrame(quad_previews.current.canvas, {delay: interval})
var img = new Image()
img.src = quad_previews.current.canvas.toDataURL()
img.onload = () => {
gif.addFrame(img, {delay: interval})
}
Blockbench.setProgress(interval*frames/options.length)
frames++;
}, interval)
setTimeout(() => {
clearInterval(loop)
if (!options.silent) {
Blockbench.setStatusBarText(tl('status_bar.processing_gif'))
}
gif.render()
if (Animator.open && Timeline.playing) {
Timeline.pause()
}
}, options.length || 1000)
}, options.length)
}
}
var Clipbench = {
@ -974,6 +1170,7 @@ const entityMode = {
//UI Changes
$('.block_mode_only').hide()
$('.entity_mode_only').show()
Modes.options.edit.select()
//UV
main_uv.buildDom().setToMainSlot().setFace('north')
main_uv.autoGrid = true
@ -999,6 +1196,7 @@ const entityMode = {
//UI Changes
$('.block_mode_only').show()
$('.entity_mode_only').hide()
Modes.options.edit.select()
//Update
if (textures.length) {
textures[0].load()

View File

@ -11,8 +11,60 @@ const DisplayMode = {};
(function() {
class DisplaySlot {
constructor(id, data) {
this.rotation = [0, 0, 0];
this.translation = [0, 0, 0];
this.scale = [1, 1, 1];
this.mirror = [false, false, false]
if (data) this.extend(data)
}
copy() {
return {
rotation: this.rotation.slice(),
translation: this.translation.slice(),
scale: this.scale.slice(),
mirror: this.mirror.slice()
}
}
export() {
var build = {}
if (!this.rotation.allEqual(0)) build.rotation = this.rotation
if (!this.translation.allEqual(0)) build.translation = this.translation
if (!this.scale.allEqual(1) || !this.mirror.allEqual(false)) {
build.scale = this.scale.slice()
if (!this.mirror.allEqual(false)) {
build.scale.forEach((s, i) => {
build.scale[i] *= s ? -1 : 1;
})
}
}
if (Object.keys(build).length) {
return build;
}
}
extend(data) {
if (!data) return this;
for (var i = 0; i < 3; i++) {
if (data.rotation) Merge.number(this.rotation, data.rotation, i)
if (data.translation) Merge.number(this.translation, data.translation, i)
if (data.mirror) Merge.boolean(this.mirror, data.mirror, i)
if (data.scale) Merge.number(this.scale, data.scale, i)
if (data.scale && data.scale[i] < 0) this.mirror[i] = true;
}
this.update()
return this;
}
update() {
if (this === DisplayMode.slot) {
DisplayMode.vue.$forceUpdate()
DisplayMode.updateDisplayBase()
}
return this;
}
}
(function() {
class refModel {
constructor(id) {
@ -1223,20 +1275,22 @@ enterDisplaySettings = function() { //Enterung Display Setting Mode, changes th
display_preview.setNormalCamera()
display_preview.camPers.position.set(-80, 40, -30)
display_preview.camPers.setFocalLength(45)
$('body').addClass('display_mode')
$('.m_edit').hide()
$('.m_disp').show()
$('#display_bar input#thirdperson_righthand').prop("checked", true)
updateInterface()
//return;
DisplayMode.loadThirdRight()
buildGrid()
setShading()
DisplayMode.loadThirdRight()
Canvas.updateRenderSides()
resizeWindow()
display_area.updateMatrixWorld()
display_base.updateMatrixWorld()
DisplayMode.centerTransformer()
if (outlines.children.length) {
outlines.children.length = 0
Canvas.updateAllPositions()
@ -1260,6 +1314,7 @@ exitDisplaySettings = function() { //Enterung Display Setting Mode, changes the
if (quad_previews.enabled_before) {
openQuadView()
}
scene.add(Transformer)
buildGrid()
setShading()
Canvas.updateRenderSides()
@ -1276,135 +1331,51 @@ function axisIndex(index) {
}
}
function resetDisplayBase() {
display_base.rotation['x'] = Math.PI / (180 / 0.1);
display_base.rotation['y'] = Math.PI / (180 / 0.1);
display_base.rotation['z'] = Math.PI / (180 / 0.1);
display_base.position['x'] = 0;
display_base.position['y'] = 0;
display_base.position['z'] = 0;
display_base.scale['x'] = 1;
display_base.scale['y'] = 1;
display_base.scale['z'] = 1;
display_base.rotation.x = Math.PI / (180 / 0.1);
display_base.rotation.y = Math.PI / (180 / 0.1);
display_base.rotation.z = Math.PI / (180 / 0.1);
display_base.position.x = 0;
display_base.position.y = 0;
display_base.position.z = 0;
display_base.scale.x = 1;
display_base.scale.y = 1;
display_base.scale.z = 1;
}
DisplayMode.centerTransformer = function() {
display_scene.add(Transformer)
Transformer.attach(display_base)
DisplayMode.syncDispInput = function(obj, sender, axis, event) {//Syncs Range and Input, calls the change functions
var val = $(obj).val()
var range_val;
if (typeof val === 'string' || val instanceof String) {
val = parseFloat(val.replace(/[^-.0-9]/g, ""))
}
if (isNaN(val)) val = 0
display_base.getWorldPosition(Transformer.position)
if (sender === 'rotation') {
val = limitNumber(val, -180, 180)
$(obj).siblings('input').val(val)
dispRotate(val, axis)
return;
} else if (sender === 'translation') {
val = limitNumber(val, -80, 80)
$(obj).siblings('input').val(val);
dispTranslate(val, axis)
return;
} else if (sender === 'scaleRange') {
//From Range to Real
range_val = val
if (val >= 0) {
val = (val*(3/4))+1
if (val >=4) val = 4
} else {
val = (val+4)/4
}
$(obj).parent().find('input.scale').val(val)
} else if (sender === 'scale') {
//From Input(Real) to Range
if (display[display_slot].scale == undefined) {
display[display_slot].scale = [1,1,1]
}
if (val >= 1) {
range_val = (Math.abs(val)-1)*(4/3)
} else {
range_val =(Math.abs(val)*4)-4
}
}
if (holding_shift === true) {
dispScale(val, 'x')
dispScale(val, 'y')
dispScale(val, 'z')
$('.panel#display input.scale').val(Math.abs(val))
$('.panel#display input.scaleRange').val(range_val)
if (Toolbox.selected.transformerMode === 'translate') {
Transformer.rotation.copy(display_area.rotation)
} else if (Toolbox.selected.transformerMode === 'scale') {
var q = display_base.getWorldQuaternion(new THREE.Quaternion())
Transformer.rotation.setFromQuaternion(q)
} else {
dispScale(val, axis)
$(obj).parent().find('input.scaleRange').val(range_val)
Transformer.rotation.set(0, 0, 0)
}
Transformer.update()
}
DisplayMode.syncDispMirror = function(node, axis) {
if (!display[display_slot].scale) {
return;
}
var axis = (node.id||'x').substr(-1)
display_base.scale[axis] = display[display_slot].scale[axisIndex(axis)] *= -1
DisplayMode.load(display_slot)
}
function dispRotate(val, axis) { //Change the actual thing
if (display[display_slot].rotation == undefined) {
display[display_slot].rotation = [0,0,0]
}
display[display_slot].rotation[axisIndex(axis)] = val
if (display_slot === 'thirdperson_lefthand' && axis === 'y') val *= (-1)
if (display_slot === 'firstperson_lefthand' && axis === 'y') val *= (-1)
if (display_slot === 'thirdperson_lefthand' && axis === 'z') val *= (-1)
if (display_slot === 'firstperson_lefthand' && axis === 'z') val *= (-1)
display_base.rotation[axis] = Math.PI / (180 / val);
}
function dispTranslate(val, axis) { //Change the actual thing
if (display[display_slot].translation == undefined) {
display[display_slot].translation = [0,0,0]
}
display[display_slot].translation[axisIndex(axis)] = val
if (display_slot === 'thirdperson_lefthand' && axis === 'x') val *= (-1)
if (display_slot === 'firstperson_lefthand' && axis === 'x') val *= (-1)
display_base.position[axis] = val
}
function dispScale(val, axis) { //Change the actual thing
if (display[display_slot].scale == undefined) {
display[display_slot].scale = [1,1,1]
}
var scale_tag = display[display_slot].scale
var is_inverse = scale_tag[axisIndex(axis)] < 0
DisplayMode.updateDisplayBase = function(slot) {
if (!slot) slot = display[display_slot]
val = limitNumber(val, 0.001, 4)
scale_tag[axisIndex(axis)] = val * (is_inverse ? -1 : 1)
if (val == 0) val = 0.001
display_base.scale[axis] = val * (is_inverse ? -1 : 1)
display_base.rotation.x = Math.PI / (180 / slot.rotation[0]);
display_base.rotation.y = Math.PI / (180 / slot.rotation[1]) * (display_slot.includes('lefthand') ? -1 : 1);
display_base.rotation.z = Math.PI / (180 / slot.rotation[2]) * (display_slot.includes('lefthand') ? -1 : 1);
display_base.position.x = slot.translation[0] * (display_slot.includes('lefthand') ? -1 : 1);
display_base.position.y = slot.translation[1];
display_base.position.z = slot.translation[2];
display_base.scale.x = (slot.scale[0]||0.001) * (slot.mirror[0] ? -1 : 1);
display_base.scale.y = (slot.scale[1]||0.001) * (slot.mirror[1] ? -1 : 1);
display_base.scale.z = (slot.scale[2]||0.001) * (slot.mirror[2] ? -1 : 1);
DisplayMode.centerTransformer()
}
DisplayMode.resetDisplaySettings = function(key) {
delete display[display_slot][key]
$('input#'+key+'_x').val(0)
$('input#'+key+'_y').val(0)
$('input#'+key+'_z').val(0)
if (key == 'rotation') {
display_base.rotation.x = Math.PI / (180 / 0);
display_base.rotation.y = Math.PI / (180 / 0);
display_base.rotation.z = Math.PI / (180 / 0);
} else if (key == 'translation') {
display_base.position.x = 0
display_base.position.y = 0
display_base.position.z = 0
} else if (key == 'scale') {
$('input#scale_x.scale').val(1)
$('input#scale_y.scale').val(1)
$('input#scale_z.scale').val(1)
display_base.scale.x = 1
display_base.scale.y = 1
display_base.scale.z = 1
}
}
DisplayMode.applyPreset = function(preset, all) {
if (preset == undefined) return;
@ -1415,12 +1386,12 @@ DisplayMode.applyPreset = function(preset, all) {
Blockbench.showQuickMessage('message.preset_no_info')
return;
};
Undo.initEdit({display_slots: slots})
slots.forEach(function(sl) {
if (!preset.areas[sl]) return;
if (typeof display[sl] !== 'object') display[sl] = {}
$.extend(true, display[sl], preset.areas[sl])
DisplayMode.slot.extend(preset.areas[sl])
})
DisplayMode.load(display_slot)
DisplayMode.updateDisplayBase()
Undo.finishEdit('apply display preset')
}
DisplayMode.createPreset = function() {
var name = $('input#preset_name').val()
@ -1435,12 +1406,19 @@ DisplayMode.createPreset = function() {
displayReferenceObjects.slots.forEach(function(s) {
if ($('#'+s+'_save').is(':checked')) {
preset.areas[s] = display[s]
preset.areas[s] = display[s].copy()
}
})
hideDialog()
localStorage.setItem('display_presets', JSON.stringify(display_presets))
}
DisplayMode.loadJSON = function(data) {
for (var slot in data) {
if (displayReferenceObjects.slots.includes(slot)) {
display[slot] = new DisplaySlot().extend(data[slot])
}
}
}
var setDisplayArea = DisplayMode.setBase = function(x, y, z, rx, ry, rz, sx, sy, sz) {//Sets the Work Area to the given Space
@ -1455,39 +1433,22 @@ var setDisplayArea = DisplayMode.setBase = function(x, y, z, rx, ry, rz, sx, sy,
display_area.scale['x'] = sx;
display_area.scale['y'] = sy;
display_area.scale['z'] = sz;
display_area.updateMatrixWorld()
DisplayMode.centerTransformer()
}
DisplayMode.groundAnimation = function() {
display_area.rotation.y += 0.015
ground_timer += 1
display_area.position.y = 13.5 + Math.sin(Math.PI * (ground_timer / 100)) * Math.PI/2
DisplayMode.centerTransformer()
if (ground_timer === 200) ground_timer = 0;
}
function getDisplayNumber(key, mode, axis) {
var def = 0
if (mode == 'scale') {
def = 1
}
if (display[key] == undefined) {
return def;
}
if (display[key][mode] == undefined) {
return def;
}
if (display[key][mode][axis] != undefined) {
var val = display[key][mode][axis];
if (mode == 'scale' && val == 0) {
val = 0.001;
}
return val;
} else {
return def;
}
}
function loadDisp(key) { //Loads The Menu and slider values, common for all Radio Buttons
display_slot = key
//enterScene(key)
resetDisplayBase()
if (key !== 'gui' && display_preview.isOrtho === true) {
display_preview.setNormalCamera()
}
@ -1498,37 +1459,12 @@ function loadDisp(key) { //Loads The Menu and slider values, common for all Radi
display_preview.camPers.setFocalLength(45)
if (display[key] == undefined) {
display[key] = {}
display[key] = new DisplaySlot()
}
$('input#rotation_x').val(getDisplayNumber(key, 'rotation', 0))
$('input#rotation_y').val(getDisplayNumber(key, 'rotation', 1))
$('input#rotation_z').val(getDisplayNumber(key, 'rotation', 2))
$('input#translation_x').val(getDisplayNumber(key, 'translation', 0))
$('input#translation_y').val(getDisplayNumber(key, 'translation', 1))
$('input#translation_z').val(getDisplayNumber(key, 'translation', 2))
$('input#scale_x').val(Math.abs(getDisplayNumber(key, 'scale', 0)))
$('input#scale_y').val(Math.abs(getDisplayNumber(key, 'scale', 1)))
$('input#scale_z').val(Math.abs(getDisplayNumber(key, 'scale', 2)))
DisplayMode.syncDispInput($('input#scale_x'), 'scale')
DisplayMode.syncDispInput($('input#scale_y'), 'scale')
DisplayMode.syncDispInput($('input#scale_z'), 'scale')
$('#display_scale_invert_x i').text(getDisplayNumber(key, 'scale', 0) > 0 ? 'check_box_outline_blank' : 'check_box')
$('#display_scale_invert_y i').text(getDisplayNumber(key, 'scale', 1) > 0 ? 'check_box_outline_blank' : 'check_box')
$('#display_scale_invert_z i').text(getDisplayNumber(key, 'scale', 2) > 0 ? 'check_box_outline_blank' : 'check_box')
display_base.rotation['x'] = Math.PI / (180 / getDisplayNumber(key, 'rotation', 0));
display_base.rotation['y'] = Math.PI / (180 / getDisplayNumber(key, 'rotation', 1));
display_base.rotation['z'] = Math.PI / (180 / getDisplayNumber(key, 'rotation', 2));
display_base.position['x'] = getDisplayNumber(key, 'translation', 0);
display_base.position['y'] = getDisplayNumber(key, 'translation', 1);
display_base.position['z'] = getDisplayNumber(key, 'translation', 2);
display_base.scale['x'] = getDisplayNumber(key, 'scale', 0);
display_base.scale['y'] = getDisplayNumber(key, 'scale', 1);
display_base.scale['z'] = getDisplayNumber(key, 'scale', 2);
DisplayMode.vue._data.slot = display[key]
DisplayMode.slot = display[key]
DisplayMode.updateDisplayBase()
DisplayMode.centerTransformer()
}
DisplayMode.loadThirdRight = function() { //Loader
@ -1537,9 +1473,6 @@ DisplayMode.loadThirdRight = function() { //Loader
}
DisplayMode.loadThirdLeft = function() { //Loader
loadDisp('thirdperson_lefthand')
display_base.position['x'] = -getDisplayNumber('thirdperson_lefthand', 'translation', 0)
display_base.rotation['y'] = Math.PI / (180 / -getDisplayNumber('thirdperson_lefthand', 'rotation', 1))
display_base.rotation['z'] = Math.PI / (180 / -getDisplayNumber('thirdperson_lefthand', 'rotation', 2))
displayReferenceObjects.bar(['player', 'zombie', 'baby_zombie', 'armor_stand', 'armor_stand_small'])
}
DisplayMode.loadFirstRight = function() { //Loader
@ -1554,9 +1487,6 @@ DisplayMode.loadFirstRight = function() { //Loader
}
DisplayMode.loadFirstLeft = function() { //Loader
loadDisp('firstperson_lefthand')
display_base.position['x'] = -getDisplayNumber('firstperson_lefthand', 'translation', 0)
display_base.rotation['y'] = Math.PI / (180 / -getDisplayNumber('firstperson_lefthand', 'rotation', 1))
display_base.rotation['z'] = Math.PI / (180 / -getDisplayNumber('firstperson_lefthand', 'rotation', 2))
setDisplayArea(-20.5, -8.4, -9, 0, 270, 0, 1,1,1)
display_preview.camPers.setFocalLength(12)
display_preview.camPers.position.set(-32.4, 0, 0)
@ -1621,36 +1551,11 @@ DisplayMode.load = function(slot) {
}
DisplayMode.copy = function() {
var base_setting = {rotation: [0, 0, 0], translation: [0, 0, 0], scale: [1, 1, 1]}
$.extend(true, base_setting, display[display_slot])
display_clipboard = base_setting
display_clipboard = DisplayMode.slot.copy()
}
DisplayMode.paste = function() {
if (display_clipboard == undefined) return;
if (typeof display_clipboard.rotation === 'object' && display_clipboard.rotation.join('_') === '0_0_0') {
delete display[display_slot].rotation;
} else {
display[display_slot].rotation = display_clipboard.rotation.slice();
}
if (typeof display_clipboard.translation === 'object' && display_clipboard.translation.join('_') === '0_0_0') {
delete display[display_slot].translation;
} else {
display[display_slot].translation = display_clipboard.translation.slice();
}
if (typeof display_clipboard.scale === 'object' && display_clipboard.scale.join('_') === '1_1_1') {
delete display[display_slot].scale;
} else {
display[display_slot].scale = display_clipboard.scale.slice();
}
/*
var clear_content = {}
$.extend(true, clear_content, display_clipboard)
$.extend(true, display[slot], clear_content)
*/
DisplayMode.load(display_slot)
DisplayMode.slot.extend(display_clipboard)
DisplayMode.updateDisplayBase()
}
window.changeDisplaySkin = function() {
@ -1767,9 +1672,6 @@ function updateDisplaySkin() {
}
//displayReferenceObjects.refmodels.player.material
}
BARS.defineActions(function() {
})
BARS.defineActions(function() {
new Action({
id: 'add_display_preset',

View File

@ -230,6 +230,18 @@ class OutlinerElement {
scope.name = '_&/3%6-7A';
scope.name = old_name;
}
getDepth() {
var d = 0;
function it(p) {
if (p.parent) {
d++;
return it(p.parent)
} else {
return d-1;
}
}
return it(this)
}
rename() {
this.showInOutliner()
var obj = $('#'+this.uuid+' > div.outliner_object > input.cube_name')
@ -241,6 +253,27 @@ class OutlinerElement {
this.old_name = this.name
return this;
}
saveName(save) {
var scope = this;
if (save !== false && scope.name.length > 0) {
var name = scope.name
scope.name = scope.old_name
if (scope.type === 'cube') {
Undo.initEdit({cubes: [scope]})
} else {
Undo.initEdit({outliner: true})
}
scope.name = name
delete scope.old_name
if (Blockbench.entity_mode && scope.type === 'group') {
scope.createUniqueName()
}
Undo.finishEdit('rename')
} else {
scope.name = scope.old_name
delete scope.old_name
}
}
isIconEnabled(btn) {
switch (btn.id) {
case 'visibility':
@ -352,6 +385,7 @@ class Cube extends OutlinerElement {
return this.rotation_axis;
}
}
return this.rotation_axis;
}
getMesh() {
return Canvas.meshes[this.uuid]
@ -374,7 +408,7 @@ class Cube extends OutlinerElement {
} else {
starting_point = true
}
if (s.type === 'cube') {
if (s.type !== 'group') {
if (!selected.includes(s)) {
selected.push(s)
just_selected.push(s)
@ -383,7 +417,7 @@ class Cube extends OutlinerElement {
s.selectLow()
}
} else if (starting_point) {
if (s.type === 'cube') {
if (s.type !== 'group') {
if (!selected.includes(s)) {
selected.push(s)
just_selected.push(s)
@ -702,7 +736,7 @@ class Cube extends OutlinerElement {
setColor(index) {
this.color = index;
if (this.visibility) {
Canvas.adaptObjectFaces(obj)
Canvas.adaptObjectFaces(this)
}
}
showContextMenu(event) {
@ -933,8 +967,10 @@ class Cube extends OutlinerElement {
Undo.initEdit({outliner: true, cubes: [], selection: true});
cube.forSelected(function(obj) {
obj.duplicate()
obj.duplicate(false)
})
updateSelection()
loadOutlinerDraggable()
Undo.finishEdit('duplicate', {outliner: true, cubes: selected, selection: true})
}},
{name: 'generic.rename', icon: 'text_format', click: function(cube) {
@ -1162,8 +1198,26 @@ class Group extends OutlinerElement {
Undo.finishEdit('removed_group')
}
}
index() {
return -1;
createUniqueName() {
var scope = this;
var others = getAllOutlinerGroups();
var name = this.name.replace(/\d+$/, '');
function check(n) {
for (var i = 0; i < others.length; i++) {
if (others[i] !== scope && others[i].name == n) return false;
}
return true;
}
if (check(this.name)) {
return this.name;
}
for (var num = 2; num < 256; num++) {
if (check(name+num)) {
scope.name = name+num;
return scope.name;
}
}
return false;
}
resolve() {
var scope = this;
@ -1238,6 +1292,7 @@ class Group extends OutlinerElement {
} else if (destination !== 'cache') {
base_group.addTo(destination, false)
}
base_group.createUniqueName()
Canvas.updatePositions()
loadOutlinerDraggable()
return base_group;
@ -1735,6 +1790,9 @@ function addGroup() {
var base_group = new Group({
origin: add_group ? add_group.origin : undefined
})
if (Blockbench.entity_mode) {
base_group.createUniqueName()
}
selected.forEach(function(s, i) {
s.addTo(base_group, false)
if (i === 0) {
@ -1806,23 +1864,9 @@ function renameCubes(element) {
function stopRenameCubes(save) {
if (Blockbench.hasFlag('renaming')) {
var uuid = $('.outliner_object input.renaming').parent().parent().attr('id')
if (uuid) {
var element = TreeElements.findRecursive('uuid', uuid)
if (save !== false && element.name.length > 0) {
var name = element.name
element.name = element.old_name
if (element.type === 'cube') {
Undo.initEdit({cubes: [element]})
} else {
Undo.initEdit({outliner: true})
}
element.name = name
delete element.old_name
Undo.finishEdit('rename')
} else {
element.name = element.old_name
delete element.old_name
}
var element = TreeElements.findRecursive('uuid', uuid)
if (element) {
element.saveName(save)
}
$('.outliner_object input.renaming').attr('disabled', true).removeClass('renaming')
$('body').focus()

View File

@ -86,6 +86,11 @@ class Panel {
var show = BARS.condition(this.condition)
if (show) {
$(this.node).show()
if (Interface.data.left_bar.includes(this.id)) {
this.width = Interface.data.left_bar_width
} else if (Interface.data.right_bar.includes(this.id)) {
this.width = Interface.data.right_bar_width
}
if (this.onResize) this.onResize()
} else {
$(this.node).hide()
@ -99,6 +104,7 @@ class ResizeLine {
this.horizontal = data.horizontal === true
this.position = data.position
this.condition = data.condition
this.width = 0;
var jq = $('<div class="resizer '+(data.horizontal ? 'horizontal' : 'vertical')+'"></div>')
this.node = jq.get(0)
$('body').append(this.node)
@ -175,7 +181,7 @@ var Interface = {
},
get: function() {return Interface.data.left_bar_width},
set: function(o, diff) {
Interface.data.left_bar_width = limitNumber(o + diff, 64, $(window).width()- 240 - Interface.data.right_bar_width)
Interface.data.left_bar_width = limitNumber(o + diff, 128, $(window).width()- 240 - Interface.data.right_bar_width)
},
position: function(line) {
line.setPosition({
@ -196,7 +202,7 @@ var Interface = {
},
get: function() {return Interface.data.right_bar_width},
set: function(o, diff) {
Interface.data.right_bar_width = limitNumber(o - diff, 64, $(window).width()- 240 - Interface.data.left_bar_width)
Interface.data.right_bar_width = limitNumber(o - diff, 128, $(window).width()- 240 - Interface.data.left_bar_width)
},
position: function(line) {
line.setPosition({
@ -298,6 +304,9 @@ function setupInterface() {
toolbars: {
head: Toolbars.outliner
},
onResize: t => {
getAllOutlinerObjects().forEach(o => o.updateElement())
},
menu: new Menu([
'add_cube',
'add_group',
@ -349,6 +358,7 @@ function setupInterface() {
Interface.status_bar.menu = new Menu([
'project_window',
'open_model_folder',
'open_backup_folder',
'save'
])
@ -407,6 +417,7 @@ function setupInterface() {
})
//Scrolling
/*
$('input[type="range"]').on('mousewheel', function () {
var factor = event.deltaY > 0 ? -1 : 1
var val = parseFloat($(event.target).val()) + parseFloat($(event.target).attr('step')) * factor
@ -415,7 +426,7 @@ function setupInterface() {
$(event.target).val(val)
eval($(event.target).attr('oninput'))
eval($(event.target).attr('onmouseup'))
})
})*/
$('#timeline_inner').on('mousewheel', function() {
if (event.ctrlKey) {
var offset = 1 - event.deltaY/600
@ -459,16 +470,16 @@ function updateInterface() {
localStorage.setItem('interface_data', JSON.stringify(Interface.data))
}
function updateInterfacePanels() {
for (var key in Interface.Panels) {
var panel = Interface.Panels[key]
panel.update()
}
var left_width = $('.sidebar#left_bar > .panel:visible').length ? Interface.data.left_bar_width : 0
var right_width = $('.sidebar#right_bar > .panel:visible').length ? Interface.data.right_bar_width : 0
$('body').css(
'grid-template-columns',
left_width+'px auto '+ right_width +'px'
)
for (var key in Interface.Panels) {
var panel = Interface.Panels[key]
panel.update()
}
$('.quad_canvas_wrapper.qcw_x').css('width', Interface.data.quad_view_x+'%')
$('.quad_canvas_wrapper.qcw_y').css('height', Interface.data.quad_view_y+'%')
$('.quad_canvas_wrapper:not(.qcw_x)').css('width', (100-Interface.data.quad_view_x)+'%')
@ -635,12 +646,12 @@ function updateUIColor() {
var c_grid = parseInt('0x'+app_colors.grid.hex.replace('#', ''))
if (!gizmo_colors.grid || c_grid !== gizmo_colors.grid.getHex()) {
gizmo_colors.grid = new THREE.Color( c_grid )
try {
three_grid.getObjectByName('grid').material.color = gizmo_colors.grid
} catch(err) {}
three_grid.children.forEach(c => {
if (c.name === 'grid' && c.material) {
c.material.color = gizmo_colors.grid;
}
})
}
//gizmo_colors.grid = new THREE.Color( parseInt('0x'+app_colors.accent.hex.replace('#', '')) )
localStorage.setItem('app_colors', JSON.stringify(app_colors))
}
@ -659,7 +670,11 @@ function applyBBStyle(data) {
//UI Edit
function setProgressBar(id, val, time) {
$('#'+id+' > .progress_bar_inner').animate({width: val*488}, time-1)
if (!id || id === 'main') {
Prop.progress = val
} else {
$('#'+id+' > .progress_bar_inner').animate({width: val*488}, time-1)
}
if (isApp) {
currentwindow.setProgressBar(val)
}
@ -679,12 +694,10 @@ $(document).keyup(function(event) {
var splashScreen = {
attempt: function(res) {
//NOW: Internet Available! -- DOM Ready!
//Post Model
if (!isApp && tryLoadPOSTModel()) {
return;
}
//Show
if (res[1] ||//Forced
localStorage.getItem('welcomed_version') != appVersion//Updated
@ -694,8 +707,15 @@ var splashScreen = {
},
show: function() {
if (open_dialog) return;
$('#welcome_content').load('https://www.blockbench.net/api/welcome/index.html', function() {
$('#welcome_content').load('https://www.blockbench.net/api/welcome/index.html', () => {
$('#welcome_screen #welcome_body').css('max-height', ($(window).height() - 478) + 'px')
if (isApp) {
$('#welcome_screen .open-in-browser').click((event) => {
event.preventDefault();
shell.openExternal(event.target.href);
return true;
});
}
showDialog('welcome_screen')
localStorage.setItem('welcomed_version', appVersion)
})

132
js/io.js
View File

@ -25,6 +25,7 @@ function newProject(entity_mode) {
Undo.index = 0;
Painter.current = {};
Animator.animations.length = 1;
Animator.selected = undefined;
Animator.animations.splice(0, 1);
if (entity_mode) {
entityMode.join();
@ -86,7 +87,7 @@ function loadModel(data, filepath, add) {
//Create New Project
if (newProject() == false) return;
Prop.file_path = filepath
setProjectTitle(pathToName(filepath, true))
setProjectTitle(pathToName(filepath))
}
Blockbench.addFlag('importing')
var model = autoParseJSON(data)
@ -122,7 +123,11 @@ function loadBlockModel(model, filepath, add) {
})
return;
}
Blockbench.entity_mode = false;
if (model.mode === 'entity') {
entityMode.join()
} else {
Blockbench.entity_mode = false;
}
saveSettings()
var previous_length = add ? elements.length : 0
@ -134,7 +139,7 @@ function loadBlockModel(model, filepath, add) {
//Load
if (model.display !== undefined) {
display = model.display
DisplayMode.loadJSON(model.display)
}
var oid = elements.length
@ -147,10 +152,16 @@ function loadBlockModel(model, filepath, add) {
var uv_stated = false;
for (var face in base_cube.faces) {
if (obj.faces[face] === undefined) {
base_cube.faces[face].texture = null
base_cube.faces[face].uv = [0,0,0,0]
} else if (typeof obj.faces[face].uv === 'object') {
uv_stated = true
} else {
if (typeof obj.faces[face].uv === 'object') {
uv_stated = true
}
if (obj.faces[face].texture === '#missing') {
delete base_cube.faces[face].texture;
}
}
}
if (!uv_stated) {
@ -215,13 +226,14 @@ function loadBlockModel(model, filepath, add) {
var path_arr = filepath.split(osfs)
var index = path_arr.length - path_arr.indexOf('models')
path_arr.splice(-index)
var texture_arr = model.textures
var names = {}
for (var tex in texture_arr) {
if (texture_arr.hasOwnProperty(tex)) {
if (tex != 'particle') {
var t = new Texture({id: tex}).fromJavaLink(texture_arr[tex], path_arr.slice()).add()
var t = new Texture({id: tex}).fromJavaLink(texture_arr[tex], path_arr.slice()).add(false)
names[texture_arr[tex]] = t
}
}
@ -231,7 +243,7 @@ function loadBlockModel(model, filepath, add) {
if (names[texture_arr.particle]) {
names[texture_arr.particle].enableParticle()
} else {
new Texture({id: 'particle'}).fromJavaLink(texture_arr[tex], path_arr.slice()).add().enableParticle()
new Texture({id: 'particle'}).fromJavaLink(texture_arr[tex], path_arr.slice()).add(false).enableParticle()
}
}
//Get Rid Of ID overlapping
@ -369,7 +381,7 @@ function loadJEMModel(model) {
Canvas.updateAll()
if (model.texture) {
var path = Prop.file_path.replace(/\\[\w .-]+$/, '\\'+model.texture)
new Texture().fromPath(path).add()
new Texture().fromPath(path).add(false)
}
}
function loadPEModelFile(data) {
@ -537,7 +549,7 @@ function loadPEModel(data) {
data = pe_list_data[0]
}
}
Project.parent = data.name
Project.parent = data.name.replace(/^geometry\./, '')
Project.texture_width = 64
Project.texture_height = 64
@ -641,8 +653,8 @@ function loadPEModel(data) {
loadOutlinerDraggable()
Canvas.updateAll()
setProjectTitle()
if (isApp && data.name) {
findEntityTexture(data.name)
if (isApp && Project.parent) {
findEntityTexture(Project.parent)
}
}
var Extruder = {
@ -1025,17 +1037,10 @@ function buildBlockModel(options) {
var new_display = {}
var entries = 0;
for (var key in display) {
if (display.hasOwnProperty(key)) {
if ((typeof display[key].scale === 'object' && display[key].scale.join('_') !== '1_1_1') ||
display[key].rotation ||
display[key].translation
) {
new_display[key] = display[key]
entries++;
if (new_display[key].scale && new_display[key].scale.join('_') === '1_1_1') {
new_display[key].scale = undefined
}
}
var slot = display[key].export()
if (slot) {
new_display[key] = display[key].export()
entries++;
}
}
if (entries) {
@ -1130,7 +1135,7 @@ function buildEntityModel(options) {
bones.push(bone)
})
if (options.visible_box !== false) {
if (bones.length && options.visible_box !== false) {
var offset = new THREE.Vector3(8,8,8)
visible_box.max.add(offset)
visible_box.min.add(offset)
@ -1152,13 +1157,15 @@ function buildEntityModel(options) {
}
entitymodel.visible_bounds_offset = [0, entitymodel.visible_bounds_height/2 , 0]
}
entitymodel.bones = bones
if (bones.length) {
entitymodel.bones = bones
}
if (options.raw) {
return entitymodel
} else {
return autoStringify(entitymodel)
var model_name = 'geometry.' + (Project.parent||'unknown')
return autoStringify({[model_name]: entitymodel})
}
}
function buildJPMModel(options) {
@ -1312,10 +1319,10 @@ function buildClassModel(options) {
return s+'F';
}
var bones = []
var bone_nr = 1
var model_id = Project.parent.replace('geometry.', '') || 'unknown';
var model_id = Project.parent.replace(/^geometry\./, '') || 'unknown';
var all_groups = getAllOutlinerGroups()
var renderers = {}
var loose_cubes = []
TreeElements.forEach(obj => {
@ -1345,9 +1352,9 @@ function buildClassModel(options) {
rootBone: g.parent.type !== 'group',
lines: [
`${id} = new ModelRenderer(this);`,//Texture Offset
`${id}.setRotationPoint(${F(-g.origin[0])}, ${F(24-g.origin[1])}, ${F(g.origin[2])});`,
]
}
var origin = [-g.origin[0], -g.origin[1], g.origin[2]]
//Rotation
if (!g.rotation.allEqual(0)) {
bone.lines.push(
@ -1358,14 +1365,21 @@ function buildClassModel(options) {
)
}
//Parent
if (!bone.rootBone) {
let parent_index = all_groups.indexOf(g.parent)
if (parent_index >= 0) {
bone.lines.push(
`${ g.parent.name }.addChild(${id});`
)
}
if (!bone.rootBone && all_groups.indexOf(g.parent) >= 0) {
bone.lines.push(
`${ g.parent.name }.addChild(${id});`
)
origin[0] += g.parent.origin[0]
origin[1] += g.parent.origin[1]
origin[2] -= g.parent.origin[2]
} else {
origin[1] += 24
}
//origin
bone.lines.splice(1, 0,
`${id}.setRotationPoint(${F(origin[0])}, ${F(origin[1])}, ${F(origin[2])});`
)
//Boxes
g.children.forEach((obj) => {
if (obj.export === false || obj.type !== 'cube') return;
@ -1387,7 +1401,7 @@ function buildClassModel(options) {
)
})
bones.push(bone)
renderers[id] = bone;
})
@ -1404,29 +1418,29 @@ function buildClassModel(options) {
'\nimport net.minecraft.entity.Entity;\n'+
'\npublic class '+model_id+' extends ModelBase {'
bones.forEach((bone) => {
model += `\n private final ModelRenderer ${bone.id};`;
})
for (var r_id in renderers) {
model += `\n private final ModelRenderer ${r_id};`;
}
model += '\n'+
'\n public '+model_id+'() {'+
'\n textureWidth = '+ (Project.texture_width || 32) +';'+
'\n textureHeight = '+ (Project.texture_height|| 32) +';\n';
bones.forEach((bone) => {
model += `\n ${bone.lines.join('\n ')}\n`;
})
for (var r_id in renderers) {
model += `\n ${renderers[r_id].lines.join('\n ')}\n`;
}
model +=
' }\n'+
'\n @Override'+
'\n public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) {'
bones.forEach((bone) => {
if (bone.rootBone) {
model += `\n ${bone.id}.render(f5);`;
for (var r_id in renderers) {
if (renderers[r_id].rootBone) {
model += `\n ${r_id}.render(f5);`;
}
})
}
model +=
'\n }'+
'\n public void setRotationAngle(ModelRenderer modelRenderer, float x, float y, float z) {'+
@ -1555,6 +1569,7 @@ function autoParseJSON(data, feedback) {
}
BARS.defineActions(function() {
//New
new Action({
id: 'new_block_model',
icon: 'insert_drive_file',
@ -1572,6 +1587,7 @@ BARS.defineActions(function() {
showDialog('project_settings');
}
})
//Import
new Action({
id: 'open_model',
icon: 'assessment',
@ -1617,9 +1633,9 @@ BARS.defineActions(function() {
}, function(files) {
if (files.length) {
if (isApp) {
new Texture().fromPath(files[0].path).add().fillParticle()
new Texture().fromPath(files[0].path).add(false).fillParticle()
} else {
new Texture().fromDataURL(files[0].content).add().fillParticle()
new Texture().fromDataURL(files[0].content).add(false).fillParticle()
}
showDialog('image_extruder')
Extruder.drawImage(isApp ? files[0].path : files[0].content)
@ -1627,6 +1643,7 @@ BARS.defineActions(function() {
})
}
})
//Export
new Action({
id: 'export_blockmodel',
icon: 'insert_drive_file',
@ -1634,20 +1651,13 @@ BARS.defineActions(function() {
keybind: new Keybind({key: 83, ctrl: true, shift: true}),
condition: function() {return !Blockbench.entity_mode},
click: function () {
var content = buildBlockModel()
Blockbench.export({
type: 'JSON Model',
extensions: ['json'],
name: Project.name||'model',
startpath: Prop.file_path,
content: content
}, (path) => {
Prop.project_saved = true
if (isApp && path) {
Prop.file_path = path
setProjectTitle(pathToName(Prop.file_path, true))
addRecentProject({name: pathToName(path, true), path: path})
}
project_file: true,
content: buildBlockModel()
})
}
})
@ -1658,14 +1668,14 @@ BARS.defineActions(function() {
keybind: new Keybind({key: 83, ctrl: true, shift: true}),
condition: function() {return Blockbench.entity_mode},
click: function () {
var content = buildEntityModel({raw: true});
Blockbench.export({
type: 'JSON Entity Model',
extensions: ['json'],
name: Project.name,
startpath: Prop.file_path,
content: content,
custom_writer: writeFileEntity
content: buildEntityModel({raw: isApp}),
project_file: true,
custom_writer: isApp ? writeFileEntity : undefined
})
}
})

View File

@ -245,7 +245,16 @@ $(document).keydown(function(e) {
if (e.ctrlKey === true && e.which == 73 && isApp) {
app.getCurrentWindow().toggleDevTools()
used = true
} else if (e.which === 18 && Toolbox.selected.alt_tool && !Toolbox.original) {
//Alt Tool
var orig = Toolbox.selected;
var alt = BarItems[Toolbox.selected.alt_tool]
if (alt && Condition(alt)) {
alt.select()
Toolbox.original = orig
}
}
//Keybinds
if (!input_focus) {
Keybinds.actions.forEach(function(action) {
if (
@ -260,7 +269,7 @@ $(document).keydown(function(e) {
}
})
}
//Dialog
if (open_dialog) {
if (Keybinds.extra.confirm.keybind.isTriggered(e)) {
$('.dialog#'+open_dialog).find('.confirm_btn:not([disabled])').click()
@ -269,6 +278,7 @@ $(document).keydown(function(e) {
$('.dialog#'+open_dialog).find('.cancel_btn:not([disabled])').click()
used = true
}
//Menu
} else if (open_menu) {
used = open_menu.keyNavigate(e)||used
@ -289,4 +299,8 @@ $(document).keydown(function(e) {
$(document).keyup(function(e) {
holding_shift = false;
if (e.which === 18 && Toolbox.original && Toolbox.original.alt_tool) {
Toolbox.original.select()
delete Toolbox.original;
}
});

View File

@ -45,28 +45,43 @@ TODO:
Support for negative numbers
*/
function parseMolang(string) {
if (typeof string === 'number') {
return isNaN(string) ? 0 : string
}
function splitUp(s, char) {
var i = 0;
var level = 0
while (i < s.length) {
let c = s[i];
if (c === '(') {
level++;
} else if (c === ')') {
level--;
} else if (level === 0 && s.substr(i, char.length) === char) {
function splitUpMolang(s, char, inverse) {
var direction = inverse ? -1 : 1;
var i = inverse ? s.length-1 : 0;
var level = 0;
var is_string = typeof char === 'string'
while (inverse ? i >= 0 : i < s.length) {
let c = s[i];
if (c === '(') {
level += direction;
} else if (c === ')') {
level -= direction;
} else if (level === 0) {
var letters = s.substr(i, char.length)
if (is_string && letters === char) {
return [
s.substr(0, i),
s.substr(i+char.length)
];
} else if (!is_string) {
for (var xi = 0; xi < char.length; xi++) {
if (char[xi] === letters) {
return [
s.substr(0, i),
s.substr(i+char[xi].length)
];
}
}
}
i++;
}
i += direction;
}
}
function parseMolang(string) {
if (typeof string === 'number') {
return isNaN(string) ? 0 : string
}
function iterate(s) {
//Spaces and brackets
@ -74,12 +89,12 @@ function parseMolang(string) {
if (s.substr(0, 1) === '(' && s.substr(-1) === ')') {
s = s.substr(1, s.length-2)
}
let split = splitUp(s, '&&')
let split = splitUpMolang(s, '&&')
// a ? b : c
split = splitUp(s, '?')
split = splitUpMolang(s, '?')
if (split) {
let condition = iterate(split[0])
let ab = splitUp(split[1], ':')
let ab = splitUpMolang(split[1], ':')
if (ab.length) {
return iterate(ab[condition?0:1])
}
@ -88,40 +103,40 @@ function parseMolang(string) {
if (split) {
return iterate(split[0]) && iterate(split[1]) ? 1 : 0
}
split = splitUp(s, '||')
split = splitUpMolang(s, '||')
if (split) {
return iterate(split[0]) || iterate(split[1]) ? 1 : 0
}
split = splitUp(s, '<')
split = splitUpMolang(s, '<')
if (split) {
return iterate(split[0]) < iterate(split[1]) ? 1 : 0
}
split = splitUp(s, '<==')
split = splitUpMolang(s, '<==')
if (split) {
return iterate(split[0]) <= iterate(split[1]) ? 1 : 0
}
split = splitUp(s, '>')
split = splitUpMolang(s, '>')
if (split) {
return iterate(split[0]) < iterate(split[1]) ? 1 : 0
}
split = splitUp(s, '>==')
split = splitUpMolang(s, '>==')
if (split) {
return iterate(split[0]) <= iterate(split[1]) ? 1 : 0
}
split = splitUp(s, '===')
split = splitUpMolang(s, '===')
if (split) {
return iterate(split[0]) === iterate(split[1]) ? 1 : 0
}
split = splitUp(s, '!==')
split = splitUpMolang(s, '!==')
if (split) {
return iterate(split[0]) !== iterate(split[1]) ? 1 : 0
}
split = splitUp(s, '+')
split = splitUpMolang(s, '+', true)
if (split) {
return iterate(split[0]) + iterate(split[1])
}
split = splitUp(s, '-')
split = splitUpMolang(s, '-', true)
if (split) {
if (split[0].length === 0) {
return -iterate(split[1])
@ -129,11 +144,11 @@ function parseMolang(string) {
return iterate(split[0]) - iterate(split[1])
}
}
split = splitUp(s, '*')
split = splitUpMolang(s, '*')
if (split) {
return iterate(split[0]) * iterate(split[1])
}
split = splitUp(s, '/')
split = splitUpMolang(s, '/')
if (split) {
return iterate(split[0]) / iterate(split[1])
}

View File

@ -14,32 +14,64 @@ class BBPainter {
if (!options.no_undo) {
Undo.initEdit({textures: [texture], bitmap: true})
}
var instance = Painter.current[options.method === 'canvas' ? 'canvas' : 'image']
Painter.current[options.method === 'canvas' ? 'image' : 'canvas'] = undefined
if (options.use_cache &&
texture === Painter.current.texture &&
typeof Painter.current.image === 'object'
typeof instance === 'object'
) {
Painter.current.image = cb(Painter.current.image) || Painter.current.image
//IS CACHED
if (options.method !== 'canvas') {
instance = cb(instance) || instance
} else {
cb(instance)
}
if (options.no_update === true) {
return;
}
Painter.current.image.getBase64(Jimp.MIME_PNG, function(a, dataUrl){
texture.updateSource(dataUrl)
if (!options.no_undo) {
Undo.finishEdit('edit_texture')
}
})
} else {
Painter.current.texture = texture
Jimp.read(Buffer.from(texture.source.replace('data:image/png;base64,', ''), 'base64')).then(function(image) {
image = cb(image) || image
Painter.current.image = image
image.getBase64(Jimp.MIME_PNG, function(a, dataUrl){
if (options.method !== 'canvas') {
Painter.current.image.getBase64(Jimp.MIME_PNG, function(a, dataUrl){
texture.updateSource(dataUrl)
if (!options.no_undo) {
Undo.finishEdit('edit_texture')
}
})
})
} else {
texture.updateSource(instance.toDataURL())
if (!options.no_undo) {
Undo.finishEdit('edit_texture')
}
}
} else {
if (options.method !== 'canvas') {
Painter.current.texture = texture
Jimp.read(Buffer.from(texture.source.replace('data:image/png;base64,', ''), 'base64')).then(function(image) {
image = cb(image) || image
Painter.current.image = image
image.getBase64(Jimp.MIME_PNG, function(a, dataUrl){
texture.updateSource(dataUrl)
if (!options.no_undo) {
Undo.finishEdit('edit_texture')
}
})
})
} else {
Painter.current.texture = texture
var c = Painter.current.canvas = document.createElement('canvas')
var ctx = c.getContext('2d');
c.width = texture.res;
c.height = texture.img.naturalHeight;
ctx.drawImage(texture.img, 0, 0)
cb(c)
texture.updateSource(c.toDataURL())
if (!options.no_undo) {
Undo.finishEdit('edit_texture')
}
}
}
}
startBrushCanvas(data, event) {
@ -53,7 +85,7 @@ class BBPainter {
var y = Math.floor( (1-data.intersects[0].uv.y) * texture.img.naturalHeight )
Painter.startBrush(texture, x, y, data.cube.faces[data.face].uv, event)
}
if (event.altKey === false && texture) {
if (Toolbox.selected.id !== 'color_picker' && texture) {
document.addEventListener('mousemove', Painter.moveBrushCanvas, false );
document.addEventListener('mouseup', Painter.stopBrushCanvas, false );
}
@ -67,7 +99,7 @@ class BBPainter {
var end_x = x = Math.floor( data.intersects[0].uv.x * texture.img.naturalWidth )
var end_y = y = Math.floor( (1-data.intersects[0].uv.y) * texture.img.naturalHeight )
if (x === Painter.current.x && y === Painter.current.y) {
//return
return
}
if (Painter.current.face !== data.face || Painter.current.cube !== data.cube) {
Painter.current.x = x
@ -75,6 +107,9 @@ class BBPainter {
Painter.current.face = data.face
Painter.current.cube = data.cube
new_face = true
if (texture !== Painter.current.texture) {
Undo.current_save.addTexture(texture)
}
}
var diff = {
x: x - (Painter.current.x||x),
@ -91,6 +126,7 @@ class BBPainter {
Painter.useBrush(texture, x, y, data.cube.faces[data.face].uv, i < length-1)
i++;
}
Painter.current.x = end_x
Painter.current.y = end_y
}
@ -102,7 +138,7 @@ class BBPainter {
Painter.stopBrush()
}
startBrush(texture, x, y, uvTag, event) {
if (event.altKey === false) {
if (Toolbox.selected.id !== 'color_picker') {
Undo.initEdit({textures: [texture], bitmap: true})
Painter.brushChanges = false
Painter.useBrush(texture, x, y, uvTag)
@ -129,64 +165,83 @@ class BBPainter {
Painter.currentPixel = [x, y]
Painter.brushChanges = true
texture.edit(function(image) {
var color = BarItems.brush_color.get().toRgb()
texture.edit(function(canvas) {
var ctx = canvas.getContext('2d')
ctx.save()
var color = BarItems.brush_color.get().toRgb();//.toRgbString()
var size = BarItems.slider_brush_size.get();
var softness = BarItems.slider_brush_softness.get()/100;
var b_opacity = BarItems.slider_brush_opacity.get()/100;
var brush_mode = BarItems.brush_mode.get()
var tool = Toolbox.selected.id;
var noise = BarItems.brush_mode.get() == 'noise';
ctx.beginPath();
if (uvTag) {
Painter.editing_area = [
var rect = Painter.editing_area = [
uvTag[0] / 16 * texture.img.naturalWidth,
uvTag[1] / 16 * texture.img.naturalHeight,
uvTag[2] / 16 * texture.img.naturalWidth,
uvTag[3] / 16 * texture.img.naturalHeight
]
} else {
Painter.editing_area = [0, 0, texture.red, texture.red]
var rect = Painter.editing_area = [0, 0, texture.red, texture.red]
}
for (var t = 0; t < 2; t++) {
if (rect[t] > rect[t+2]) {
[rect[t], rect[t+2]] = [rect[t+2], rect[t]]
}
}
ctx.rect(rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1])
if (Painter.editing_area[0] > Painter.editing_area[2]) {
var sw = Painter.editing_area[2]
Painter.editing_area[2] = Painter.editing_area[0]
Painter.editing_area[0] = sw
}
if (Painter.editing_area[1] > Painter.editing_area[3]) {
var sw = Painter.editing_area[3]
Painter.editing_area[3] = Painter.editing_area[1]
Painter.editing_area[1] = sw
}
if (tool === 'fill_tool') {
if (brush_mode === 'brush') {
Painter.editCircle(image, x, y, size, softness, function(pxcolor, opacity) {
var result_color = Painter.combineColors(pxcolor, color, opacity*b_opacity);
return result_color;
})
} else if (brush_mode === 'noise') {
Painter.editCircle(image, x, y, size, softness, function(pxcolor, opacity) {
var result_color = Painter.combineColors(pxcolor, color, opacity*b_opacity*Math.random());
return result_color;
})
} else if (brush_mode === 'eraser') {
Painter.editCircle(image, x, y, size, softness, function(pxcolor, opacity) {
return {r: pxcolor.r, g: pxcolor.g, b: pxcolor.b, a: pxcolor.a*(1-b_opacity*opacity)};
})
} else if (brush_mode === 'fill') {
Painter.editFace(image, x, y, function(pxcolor) {
return Painter.combineColors(pxcolor, color, 1)
})
ctx.fillStyle = BarItems.brush_color.get().toRgbString()
ctx.fill()
} else {
ctx.clip()
/*ctx.beginPath();
ctx.moveTo((Painter.current.x||x)+.5, (Painter.current.y||y)+.5)
ctx.lineTo(x+.5, y+.5)
if (softness) {
ctx.filter = `blur(${ softness*size/2 }px)`;
} else {
ctx.imageSmoothingEnabled = false
}
ctx.lineWidth = size
ctx.lineCap = 'round'
if (brush_mode === 'eraser') {
ctx.globalCompositeOperation = 'destination-out'
ctx.strokeStyle = 'rgba(0,0,0,0)';
} else {
ctx.strokeStyle = color
}
ctx.stroke()*/
if (tool === 'brush_tool') {
Painter.editCircle(ctx, x, y, size, softness, function(pxcolor, opacity) {
var result_color = Painter.combineColors(pxcolor, color, opacity*b_opacity*(noise?Math.random():1));
return result_color;
})
} else if (tool === 'eraser') {
Painter.editCircle(ctx, x, y, size, softness, function(pxcolor, opacity) {
return {r: pxcolor.r, g: pxcolor.g, b: pxcolor.b, a: pxcolor.a*(1-b_opacity*opacity*(noise?Math.random():1))};
})
}
ctx.restore();
}
Painter.editing_area = undefined
}, {no_undo: true, use_cache: true, no_update: no_update})
Painter.editing_area = undefined;
}, {method: 'canvas', no_undo: true, use_cache: true, no_update: no_update});
}
}
stopBrush() {
if (Painter.brushChanges) {
Undo.finishEdit('paint')
Painter.brushChanges = false
Undo.finishEdit('paint');
Painter.brushChanges = false;
}
Painter.currentPixel = [-1, -1]
Painter.currentPixel = [-1, -1];
}
combineColors(base, added, opacity) {
if (typeof base === 'number') base = Jimp.intToRGBA(base)
@ -204,6 +259,21 @@ class BBPainter {
added.a = original_a
return mix;
}
scanCanvas(ctx, x, y, w, h, cb) {
var arr = ctx.getImageData(x, y, w, h)
for (var i = 0; i < arr.data.length; i += 4) {
var pixel = arr.data.slice(i, i+4)
var px = (i/4) % w
var py = Math.floor((i/4) / w)
pixel = cb(x+px, y+py, pixel)||pixel
pixel.forEach((p, pi) => {
arr.data[i+pi] = p
})
}
ctx.putImageData(arr, x, y)
}
drawRectangle(image, color, rect) {
var color = Jimp.intToRGBA(color)
image.scan(rect.x, rect.y, rect.w, rect.h, function (x, y, idx) {
@ -252,14 +322,15 @@ class BBPainter {
});
}
editCircle(image, x, y, r, s, editPx) {
editCircle(ctx, x, y, r, s, editPx) {
r = Math.round(r)
image.scan(x-r-1, y-r-1, 2*r+3, 2*r+3, function (px, py, idx) {
Painter.scanCanvas(ctx, x-r-1, y-r-1, 2*r+3, 2*r+3, function (px, py, pixel) {
if (px >= this.bitmap.width ||
if (px >= ctx.canvas.width ||
px < 0 ||
py >= this.bitmap.height ||
py >= ctx.canvas.height ||
py < 0
) {
return;
@ -272,7 +343,7 @@ class BBPainter {
px+0.02 < Math.floor(Painter.editing_area[0]) ||
py+0.02 < Math.floor(Painter.editing_area[1]) ||
px+0.02 >= Painter.editing_area[2] ||
py+0.02 >= Painter.editing_area[3]
py+0.02 >= Painter.editing_area[3]
)
) {
return;
@ -292,15 +363,15 @@ class BBPainter {
if (opacity > 0) {
var result_color = editPx({
r:this.bitmap.data[idx+0],
g:this.bitmap.data[idx+1],
b:this.bitmap.data[idx+2],
a:this.bitmap.data[idx+3]/255
r: pixel[0],
g: pixel[1],
b: pixel[2],
a: pixel[3]/255
}, opacity)
this.bitmap.data[idx+0] = result_color.r
this.bitmap.data[idx+1] = result_color.g
this.bitmap.data[idx+2] = result_color.b
this.bitmap.data[idx+3] = result_color.a*255
pixel[0] = result_color.r
pixel[1] = result_color.g
pixel[2] = result_color.b
pixel[3] = result_color.a*255
}
});
}
@ -399,6 +470,9 @@ class BBPainter {
if (options.color === undefined) {
options.color = new tinycolor().toRgb()
}
if (Blockbench.entity_mode) {
options.texture = textures[0]
}
var texture = new Texture({
mode: 'bitmap',
keep_size: true,
@ -422,19 +496,28 @@ class BBPainter {
return texture;
}
if (options.entity_template === true) {
Painter.generateTemplate(options.res, options.color, makeTexture)
Undo.initEdit({textures: [], cubes: Blockbench.entity_mode ? elements : selected, uv_only: true})
Painter.generateTemplate(options.res, options.color, makeTexture, options.texture)
Undo.finishEdit({textures: [texture], cubes: Blockbench.entity_mode ? elements : selected, uv_only: true})
} else {
Undo.initEdit({textures: []})
Painter.generateBlank(options.res, options.res, options.color, makeTexture)
Undo.finishEdit({textures: [texture]})
}
}
generateBlank(height, width, color, cb) {
new Jimp(height, width, color.toInteger(), function(err, image) {
image.getBase64("image/png", function(a, dataUrl){
cb(dataUrl)
})
})
var canvas = document.createElement('canvas')
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d')
ctx.fillStyle = new tinycolor(color).toRgbString()
ctx.fillRect(0, 0, width, height)
cb(canvas.toDataURL())
}
generateTemplate(res, background_color, cb) {
generateTemplate(res, background_color, cb, texture) {
function cubeTempl(obj) {
var min = Blockbench.entity_mode ? 0 : 1
this.x = obj.size(0, true) || min
@ -448,7 +531,7 @@ class BBPainter {
}
var res_multiple = res / 16
var bone_temps = []
var templates = []
var max_x_pos = 0
var line_y_pos = 0;
var valid_cubes = 0;
@ -467,7 +550,6 @@ class BBPainter {
cubes.splice(i,1)
} else {
obj.template_size = (obj.size(2, true) + obj.size(1, true)) + (obj.size(2, true) + obj.size(0, true))*2
//obj.template_size = (obj.size(2, true) + obj.size(0, true))
avg_size += obj.template_size
}
i--;
@ -479,7 +561,7 @@ class BBPainter {
i = 0
var ox = 0
cubes.forEach(function(obj) {
cubes.forEach(function(obj) {
if (ox >= line_length) {
o = 0
ox = 0
@ -528,9 +610,9 @@ class BBPainter {
}
//size of widest bone
max_x_pos = Math.max(max_x_pos, filled_x_pos)
templates.push(t)
})
line_y_pos += max_height
bone_temps.push(temps)
})
//Cancel if no cubes
if (valid_cubes == 0) {
@ -551,92 +633,112 @@ class BBPainter {
if (background_color.getAlpha() != 0) {
background_color = background_color.toInteger()
}
var canvas = document.createElement('canvas')
canvas.width = canvas.height = max_size*res_multiple;
var ctx = canvas.getContext('2d')
ctx.imageSmoothingEnabled = false;
function drawTemplateRectangle(image, border_color, color, coords) {
function drawTemplateRectangle(border_color, color, coords) {
if (typeof background_color === 'number') {
border_color = background_color
color = undefined
}
Painter.drawRectangle(image, border_color, {
x: coords.x*res_multiple,
y: coords.y*res_multiple,
w: coords.w*res_multiple,
h: coords.h*res_multiple
})
ctx.fillStyle = border_color
ctx.fillRect(
coords.x*res_multiple,
coords.y*res_multiple,
coords.w*res_multiple,
coords.h*res_multiple
)
if (coords.w <= 2 || coords.h <= 2 || !color) return;
Painter.drawRectangle(image, color, {
x: coords.x * res_multiple + 1,
y: coords.y * res_multiple + 1,
w: coords.w * res_multiple - 2,
h: coords.h * res_multiple - 2
})
ctx.fillStyle = color
ctx.fillRect(
coords.x * res_multiple + 1,
coords.y * res_multiple + 1,
coords.w * res_multiple - 2,
coords.h * res_multiple - 2
)
}
function drawTexture(face, coords) {
if (!Blockbench.entity_mode) {
if (face.texture === undefined || face.texture === null) return;
texture = getTextureById(face.texture)
}
if (!texture || !texture.img) return;
var uv = face.uv;
var src = getRectangle(uv[0], uv[1], uv[2], uv[3])
ctx.drawImage(
texture.img,
src.ax/16 * texture.img.naturalWidth,
src.ay/16 * texture.img.naturalHeight,
src.x /16 * texture.img.naturalWidth,
src.y /16 * texture.img.naturalHeight,
coords.x*res_multiple,
coords.y*res_multiple,
coords.w*res_multiple,
coords.h*res_multiple
)
}
var face_data = {
up: {c1: 0xb4d4e1ff, c2: 0xecf8fdff, place: t => {return {x: t.posx+t.z, y: t.posy, w: t.x, h: t.z}}},
down: {c1: 0x536174ff, c2: 0x6e788cff, place: t => {return {x: t.posx+t.z+t.x, y: t.posy, w: t.x, h: t.z}}},
east: {c1: 0x43e88dff, c2: 0x7BFFA3ff, place: t => {return {x: t.posx, y: t.posy+t.z, w: t.z, h: t.y}}},
north: {c1: 0x5bbcf4ff, c2: 0x7BD4FFff, place: t => {return {x: t.posx+t.z, y: t.posy+t.z, w: t.x, h: t.y}}},
west: {c1: 0xf48686ff, c2: 0xFFA7A4ff, place: t => {return {x: t.posx+t.z+t.x, y: t.posy+t.z, w: t.z, h: t.y}}},
south: {c1: 0xf8dd72ff, c2: 0xFFF899ff, place: t => {return {x: t.posx+t.z+t.x+t.z,y: t.posy+t.z, w: t.x, h: t.y}}},
up: {c1: '#b4d4e1', c2: '#ecf8fd', place: t => {return {x: t.posx+t.z, y: t.posy, w: t.x, h: t.z}}},
down: {c1: '#536174', c2: '#6e788c', place: t => {return {x: t.posx+t.z+t.x, y: t.posy, w: t.x, h: t.z}}},
east: {c1: '#43e88d', c2: '#7BFFA3', place: t => {return {x: t.posx, y: t.posy+t.z, w: t.z, h: t.y}}},
north: {c1: '#5bbcf4', c2: '#7BD4FF', place: t => {return {x: t.posx+t.z, y: t.posy+t.z, w: t.x, h: t.y}}},
west: {c1: '#f48686', c2: '#FFA7A4', place: t => {return {x: t.posx+t.z+t.x, y: t.posy+t.z, w: t.z, h: t.y}}},
south: {c1: '#f8dd72', c2: '#FFF899', place: t => {return {x: t.posx+t.z+t.x+t.z,y: t.posy+t.z, w: t.x, h: t.y}}},
}
//Drawing
new Jimp(max_size*res_multiple, max_size*res_multiple, 0, function(err, image) {
bone_temps.forEach(function(bt) {
bt.forEach(function(t) {
for (var face in face_data) {
let d = face_data[face]
if (!options.use_texture || (t.obj.faces[face].texture)) {
//Colored
drawTemplateRectangle(image, d.c1, d.c2, d.place(t))
} else {
//Texture
}
}
let obj = t.obj
obj.uv_offset[0] = t.posx
obj.uv_offset[1] = t.posy
if (!Blockbench.entity_mode) {
var size = obj.size(undefined, true)
var face_list = [
{face: 'north', fIndex: 10, from: [size[2], size[2]], size: [size[0], size[1]]},
{face: 'east', fIndex: 0, from: [0, size[2]], size: [size[2], size[1]]},
{face: 'south', fIndex: 8, from: [size[2]*2 + size[0], size[2]], size: [size[0], size[1]]},
{face: 'west', fIndex: 2, from: [size[2] + size[0], size[2]], size: [size[2], size[1]]},
{face: 'up', fIndex: 4, from: [size[2]+size[0], size[2]], size: [-size[0], -size[2]]},
{face: 'down', fIndex: 6, from: [size[2]+size[0]*2, 0], size: [-size[0], size[2]]}
]
face_list.forEach(function(f) {
obj.faces[f.face].uv[0] = (f.from[0] + Math.floor(obj.uv_offset[0]+0.0000001)) / max_size * 16,
obj.faces[f.face].uv[1] = (f.from[1] + Math.floor(obj.uv_offset[1]+0.0000001)) / max_size * 16,
obj.faces[f.face].uv[2] = (f.from[0] + f.size[0] + Math.floor(obj.uv_offset[0]+0.0000001)) / max_size * 16,
obj.faces[f.face].uv[3] = (f.from[1] + f.size[1] + Math.floor(obj.uv_offset[1]+0.0000001)) / max_size * 16
})
}
})
})
image.getBase64("image/png", function(a, dataUrl){
var texture = cb(dataUrl)
entityMode.setResolution(max_size, max_size, true)
if (texture && !Blockbench.entity_mode) {
bone_temps.forEach(function(bt) {
bt.forEach(function(t) {
t.obj.applyTexture(texture, true)
t.obj.autouv = 0
})
})
templates.forEach(function(t) {
for (var face in face_data) {
let d = face_data[face]
if (options.use_texture || !t.obj.faces[face].texture) {
//Colored
drawTemplateRectangle(d.c1, d.c2, d.place(t))
} else {
//Texture
drawTexture(t.obj.faces[face], d.place(t))
}
})
}
let obj = t.obj
obj.uv_offset[0] = t.posx
obj.uv_offset[1] = t.posy
if (!Blockbench.entity_mode) {
var size = obj.size(undefined, true)
var face_list = [
{face: 'north', fIndex: 10, from: [size[2], size[2]], size: [size[0], size[1]]},
{face: 'east', fIndex: 0, from: [0, size[2]], size: [size[2], size[1]]},
{face: 'south', fIndex: 8, from: [size[2]*2 + size[0], size[2]], size: [size[0], size[1]]},
{face: 'west', fIndex: 2, from: [size[2] + size[0], size[2]], size: [size[2], size[1]]},
{face: 'up', fIndex: 4, from: [size[2]+size[0], size[2]], size: [-size[0], -size[2]]},
{face: 'down', fIndex: 6, from: [size[2]+size[0]*2, 0], size: [-size[0], size[2]]}
]
face_list.forEach(function(f) {
obj.faces[f.face].uv[0] = (f.from[0] + Math.floor(obj.uv_offset[0]+0.0000001)) / max_size * 16,
obj.faces[f.face].uv[1] = (f.from[1] + Math.floor(obj.uv_offset[1]+0.0000001)) / max_size * 16,
obj.faces[f.face].uv[2] = (f.from[0] + f.size[0] + Math.floor(obj.uv_offset[0]+0.0000001)) / max_size * 16,
obj.faces[f.face].uv[3] = (f.from[1] + f.size[1] + Math.floor(obj.uv_offset[1]+0.0000001)) / max_size * 16
})
}
})
var dataUrl = canvas.toDataURL()
var texture = cb(dataUrl)
entityMode.setResolution(max_size, max_size, true)
if (texture && !Blockbench.entity_mode) {
templates.forEach(function(t) {
t.obj.applyTexture(texture, true)
t.obj.autouv = 0
})
}
}
}
var Painter = new BBPainter()
@ -648,11 +750,83 @@ BARS.defineActions(function() {
icon: 'fa-paint-brush',
category: 'tools',
toolbar: 'brush',
alt_tool: 'color_picker',
selectFace: true,
transformerMode: 'hidden',
paintTool: true,
allowWireframe: false,
keybind: new Keybind({key: 66}),
condition: () => Modes.id === 'paint',
onCanvasClick: function(data) {
Painter.startBrushCanvas(data, data.event)
},
onSelect: function() {
BarItems.slider_brush_size.update()
BarItems.slider_brush_softness.update()
BarItems.slider_brush_opacity.update()
$('.UVEditor').find('#uv_size').hide()
},
onUnselect: function() {
$('.UVEditor').find('#uv_size').show()
}
})
new Tool({
id: 'fill_tool',
icon: 'format_color_fill',
category: 'tools',
toolbar: 'brush',
alt_tool: 'color_picker',
selectFace: true,
transformerMode: 'hidden',
paintTool: true,
allowWireframe: false,
condition: () => Modes.id === 'paint',
onCanvasClick: function(data) {
Painter.startBrushCanvas(data, data.event)
},
onSelect: function() {
BarItems.slider_brush_size.update()
BarItems.slider_brush_softness.update()
BarItems.slider_brush_opacity.update()
$('.UVEditor').find('#uv_size').hide()
},
onUnselect: function() {
$('.UVEditor').find('#uv_size').show()
}
})
new Tool({
id: 'eraser',
icon: 'fa-eraser',
category: 'tools',
toolbar: 'brush',
selectFace: true,
transformerMode: 'hidden',
paintTool: true,
allowWireframe: false,
condition: () => Modes.id === 'paint',
onCanvasClick: function(data) {
Painter.startBrushCanvas(data, data.event)
},
onSelect: function() {
BarItems.slider_brush_size.update()
BarItems.slider_brush_softness.update()
BarItems.slider_brush_opacity.update()
$('.UVEditor').find('#uv_size').hide()
},
onUnselect: function() {
$('.UVEditor').find('#uv_size').show()
}
})
new Tool({
id: 'color_picker',
icon: 'colorize',
category: 'tools',
toolbar: 'brush',
selectFace: true,
transformerMode: 'hidden',
paintTool: true,
allowWireframe: false,
condition: () => Modes.id === 'paint',
onCanvasClick: function(data) {
Painter.startBrushCanvas(data, data.event)
},
@ -666,33 +840,31 @@ BARS.defineActions(function() {
$('.UVEditor').find('#uv_size').show()
}
})
//Noise ? grain
//Color Picker colorize
//Eraser fa-eraser
//Fill format_color_fill
new ColorPicker({
id: 'brush_color',
condition: () => (Toolbox && ['brush_tool', 'color_picker', 'fill_tool'].includes(Toolbox.selected.id)),
palette: true
})
new BarSelect({
id: 'brush_mode',
condition: () => Toolbox && (Toolbox.selected.id === 'brush_tool' || Toolbox.selected.id === 'eraser'),
options: {
brush: true,
noise: true,
eraser: true,
fill: true
noise: true
}
})
new NumSlider({
id: 'slider_brush_size',
condition: () => (Toolbox && ['brush_tool', 'eraser'].includes(Toolbox.selected.id)),
settings: {
min: 1, max: 20, step: 1, default: 1,
}
})
new NumSlider({
id: 'slider_brush_softness',
condition: () => (Toolbox && ['brush_tool', 'eraser'].includes(Toolbox.selected.id)),
settings: {
min: 0, max: 100, default: 0,
interval: function(event) {
@ -710,6 +882,7 @@ BARS.defineActions(function() {
})
new NumSlider({
id: 'slider_brush_opacity',
condition: () => (Toolbox && ['brush_tool', 'eraser'].includes(Toolbox.selected.id)),
settings: {
min: 0, max: 100, default: 100,
interval: function(event) {

View File

@ -350,6 +350,15 @@ function switchPluginTabs(installed) {
}
BARS.defineActions(function() {
new Action({
id: 'plugins_window',
icon: 'extension',
category: 'blockbench',
click: function () {
showDialog('plugins')
$('#plugin_list').css('max-height', limitNumber($(window).height()-300, 80, 600)+'px')
}
})
new Action({
id: 'load_plugin',
icon: 'fa-file-code-o',

View File

@ -7,11 +7,10 @@ var scene, main_preview, previews,
display_scene, display_area, display_base;
var framespersecond = 0;
var display_mode = false;
var cubes = new THREE.Group();
var doRender = false;
var quad_previews = {};
var three_grid = new THREE.Object3D();
var rot_origin = new THREE.Object3D();
const three_grid = new THREE.Object3D();
const rot_origin = new THREE.Object3D();
var gizmo_colors = {
r: new THREE.Color(0xfd3043),
g: new THREE.Color(0x26ec45),
@ -45,6 +44,7 @@ class Preview {
this.controls.maxDistance = 320;
this.controls.target.set(0,-3,0);
this.controls.enableKeys = false;
this.controls.zoomSpeed = 1.5
//Keybinds
this.controls.mouseButtons.ZOOM = undefined;
@ -69,7 +69,7 @@ class Preview {
this.mouse = new THREE.Vector2();
this.canvas.addEventListener('mousedown', function(event) { scope.click(event)}, false)
this.canvas.addEventListener('mousemove', function(event) { scope.static_rclick = false}, false)
this.canvas.addEventListener('contextmenu', function(event) { scope.showContextMenu(event)}, false)
this.canvas.addEventListener('mouseup', function(event) { scope.showContextMenu(event)}, false)
this.canvas.addEventListener('dblclick', function() {Toolbox.toggleTransforms()}, false)
this.canvas.addEventListener('touchstart', function() { scope.onTouchStart()}, false)
this.canvas.addEventListener('mouseenter', function() { scope.occupyTransformer()}, false)
@ -301,12 +301,18 @@ class Preview {
var data = this.raycast(event)
if (data) {
this.static_rclick = false
if (Toolbox.selected.selectCubes && data.type === 'cube') {
if (Toolbox.selected.selectCubes && Modes.selected.selectCubes && data.type === 'cube') {
if (Toolbox.selected.selectFace) {
main_uv.setFace(data.face)
}
Blockbench.dispatchEvent( 'canvas_select', data )
data.cube.select(event)
if (Animator.open || (Toolbox.selected.id === 'rotate_tool' && Blockbench.entity_mode)) {
if (data.cube.parent.type === 'group') {
data.cube.parent.select()
}
} else {
data.cube.select(event)
}
}
if (typeof Toolbox.selected.onCanvasClick === 'function') {
Toolbox.selected.onCanvasClick(data)
@ -345,7 +351,7 @@ class Preview {
return this;
}
showContextMenu(event) {
if (this.static_rclick) {
if (this.static_rclick && event.which === 3) {
var data = this.raycast()
if (data && data.cube) {
data.cube.showContextMenu(event)
@ -597,6 +603,10 @@ class Preview {
obj.was_visible = obj.visible
obj.visible = false
})
var ground_anim_before = ground_animation
if (display_mode && ground_animation) {
ground_animation = false
}
setTimeout(function() {
@ -619,6 +629,9 @@ class Preview {
obj.visible = obj.was_visible
delete obj.was_visible
})
if (display_mode && ground_anim_before) {
ground_animation = ground_anim_before
}
}, 40)
}
@ -650,7 +663,7 @@ class Preview {
changeDisplaySkin()
}},
{icon: 'wallpaper', name: 'menu.preview.background', children: function(preview) {
var has_background = !!main_preview.background.image
var has_background = !!preview.background.image
return [
{icon: 'folder', name: 'menu.preview.background.load', click: function(preview) {
Blockbench.import({
@ -672,7 +685,7 @@ class Preview {
}},
{
name: 'menu.preview.background.lock',
condition: has_background && preview.background.lock !== null,
condition: (has_background && preview.background.lock !== null && preview.isOrtho),
icon: preview.background.lock?'check_box':'check_box_outline_blank',
click: function(preview) {
preview.background.lock = !preview.background.lock
@ -747,9 +760,16 @@ function initCanvas() {
display_scene = new THREE.Scene();
display_area = new THREE.Object3D();
display_base = new THREE.Object3D();
display_scene.add(display_area)
display_area.add(display_base)
display_base.add(scene)
scene.name = 'scene'
display_base.name = 'display_base'
display_area.name = 'display_area'
display_scene.name = 'display_scene'
scene.position.set(-8,-8,-8)
scene.add(Vertexsnap.vertexes)
@ -813,7 +833,6 @@ function initCanvas() {
//TransformControls
Transformer = new THREE.TransformControls(main_preview.camPers, main_preview.canvas)
Transformer.setSize(0.5)
Transformer.setTranslationSnap(canvasGridSize())
scene.add(Transformer)
main_preview.occupyTransformer()
@ -917,7 +936,7 @@ function animate() {
prev.render()
})
framespersecond++;
if (display_mode === true && ground_animation === true) {
if (display_mode === true && ground_animation === true && !Transformer.hoverAxis) {
DisplayMode.groundAnimation()
}
}
@ -937,22 +956,7 @@ function resizeWindow(event) {
if (Animator.open) {
Timeline.updateSize()
}
if (!Toolbars || !Toolbars[Toolbox.selected.toolbar]) return;
Toolbars[Toolbox.selected.toolbar].children.forEach(function(action) {
if (action.type === 'numslider') {
action.setWidth(40)
}
})
if ($('div.tool_options .toolbar').length > 0) {
var sliders = $('header .tool.nslide_tool').length
var space = $(window).width() - $('div.tool_options .toolbar').offset().left - $('div.tool_options .toolbar').width()
var width = limitNumber(37 + space / sliders, 40, 80)
Toolbars[Toolbox.selected.toolbar].children.forEach(function(action) {
if (action.type === 'numslider') {
action.setWidth(width)
}
})
}
BARS.updateToolToolbar()
}
$(window).resize(resizeWindow)
@ -975,55 +979,54 @@ function buildGrid() {
if (display_mode === true && settings.display_grid.value === false) return;
three_grid.name = 'grid_group'
var size, step;
var grid_color = new THREE.Color(parseInt('0x'+app_colors.grid.hex.replace('#', ''), 16))
var line_material = new THREE.LineBasicMaterial({color: grid_color});
gizmo_colors.grid = new THREE.Color(parseInt('0x'+app_colors.grid.hex.replace('#', ''), 16))
var material;
northMarkMaterial.color = grid_color
northMarkMaterial.color = gizmo_colors.grid
function setupAxisLine(origin, length, axis) {
var color = 'rgb'[getAxisNumber(axis)]
var geometry = new THREE.Geometry();
var material = new THREE.LineBasicMaterial({color: gizmo_colors[color]});
var dest = new THREE.Vector3().copy(origin)
dest[axis] += length
geometry.vertices.push(origin)
geometry.vertices.push(dest)
var line = new THREE.Line( geometry, material);
line.name = 'axis_line_'+axis;
three_grid.add(line)
}
//Axis Lines
if (settings.base_grid.value || settings.full_grid.value)
if (Blockbench.entity_mode || !settings.full_grid.value) {
var length = Blockbench.entity_mode
? (settings.full_grid.value ? 24 : 8)
: 16
setupAxisLine(new THREE.Vector3( 0, 0.001, 0), length, 'x')
setupAxisLine(new THREE.Vector3( 0, 0.001, 0), length, 'z')
} else {
setupAxisLine(new THREE.Vector3( -16, 0.001, -16), 48, 'x')
setupAxisLine(new THREE.Vector3( -16, 0.001, -16), 48, 'z')
}
if (settings.full_grid.value === true) {
size = 24
step = canvasGridSize();
var geometry = new THREE.Geometry();
for ( var i = - size; i <= size; i += step) {
geometry.vertices.push(new THREE.Vector3( -size, 0, i))
geometry.vertices.push(new THREE.Vector3( size, 0, i))
geometry.vertices.push(new THREE.Vector3(i, 0, -size))
geometry.vertices.push(new THREE.Vector3(i, 0, size))
}
var line = new THREE.Line( geometry, line_material, THREE.LinePieces);
//Grid
var grid = new THREE.GridHelper(48, 48/canvasGridSize(), gizmo_colors.grid, gizmo_colors.grid)
if (Blockbench.entity_mode === true) {
line.position.set(0,0,0)
grid.position.set(0,0,0)
} else {
line.position.set(8,0,8)
grid.position.set(8,0,8)
}
three_grid.add(line)
line.name = 'grid'
//Axis Helpers
geometry = new THREE.Geometry();
material = new THREE.LineBasicMaterial({color: gizmo_colors.r});
geometry.vertices.push(new THREE.Vector3( -16, 0.001, -16))
geometry.vertices.push(new THREE.Vector3( 32, 0.001, -16))
x_axis = new THREE.Line( geometry, material, THREE.LinePieces);
three_grid.add(x_axis)
geometry = new THREE.Geometry();
material = new THREE.LineBasicMaterial({color: gizmo_colors.b});
geometry.vertices.push(new THREE.Vector3( -16, 0.001, -16))
geometry.vertices.push(new THREE.Vector3( -16, 0.001, 32))
z_axis = new THREE.Line( geometry, material, THREE.LinePieces);
three_grid.add(z_axis)
three_grid.add(grid)
grid.name = 'grid'
//North
geometry = new THREE.PlaneGeometry(5, 5)
var north_mark = new THREE.Mesh(geometry, northMarkMaterial)
if (Blockbench.entity_mode === true) {
north_mark.position.set(0,0,-27)
} else {
@ -1034,65 +1037,28 @@ function buildGrid() {
} else {
if (settings.large_grid.value === true) {
var geometry_big = new THREE.Geometry();
size = 24
step = 16;
for ( var i = - size; i <= size; i += step) {
geometry_big.vertices.push(new THREE.Vector3( -size, 0, i))
geometry_big.vertices.push(new THREE.Vector3( size, 0, i))
geometry_big.vertices.push(new THREE.Vector3(i, 0, -size))
geometry_big.vertices.push(new THREE.Vector3(i, 0, size))
}
var line_big = new THREE.Line( geometry_big, line_material, THREE.LinePieces);
//Grid
var grid = new THREE.GridHelper(48, 3, gizmo_colors.grid, gizmo_colors.grid)
if (Blockbench.entity_mode === true) {
line_big.position.set(0,0,0)
grid.position.set(0,0,0)
} else {
line_big.position.set(8,0,8)
grid.position.set(8,0,8)
}
line_big.name = 'grid'
three_grid.add(line_big)
grid.name = 'grid'
three_grid.add(grid)
}
if (settings.base_grid.value === true) {
size = 8
step = canvasGridSize();
//Grid
var grid = new THREE.GridHelper(16, 16/canvasGridSize(), gizmo_colors.grid, gizmo_colors.grid)
var geometry = new THREE.Geometry();
for ( var i = - size; i <= size; i += step) {
geometry.vertices.push(new THREE.Vector3( -size, 0, i))
geometry.vertices.push(new THREE.Vector3( size, 0, i))
geometry.vertices.push(new THREE.Vector3(i, 0, -size))
geometry.vertices.push(new THREE.Vector3(i, 0, size))
}
var line = new THREE.Line( geometry, line_material, THREE.LinePieces);
if (Blockbench.entity_mode === true) {
line.position.set(0,0,0)
grid.position.set(0,0,0)
} else {
line.position.set(8,0,8)
grid.position.set(8,0,8)
}
three_grid.add(line)
line.name = 'grid'
//Axis Helpers
geometry = new THREE.Geometry();
material = new THREE.LineBasicMaterial({color: '#EE4040'});
geometry.vertices.push(new THREE.Vector3( 0, 0.001, 0))
geometry.vertices.push(new THREE.Vector3( (Blockbench.entity_mode ? 8 : 16), 0.001, 0))
x_axis = new THREE.Line( geometry, material, THREE.LinePieces);
three_grid.add(x_axis)
geometry = new THREE.Geometry();
material = new THREE.LineBasicMaterial({color: '#547CEA'});
geometry.vertices.push(new THREE.Vector3( 0, 0.001, 0))
geometry.vertices.push(new THREE.Vector3( 0, 0.001, (Blockbench.entity_mode ? 8 : 16)))
z_axis = new THREE.Line( geometry, material, THREE.LinePieces);
three_grid.add(z_axis)
grid.name = 'grid'
three_grid.add(grid)
//North
geometry = new THREE.PlaneGeometry(2.4, 2.4)
@ -1109,82 +1075,100 @@ function buildGrid() {
if (settings.large_box.value === true) {
var geometry_box = new THREE.EdgesGeometry(new THREE.BoxBufferGeometry(48, 48, 48));
var line_material = new THREE.LineBasicMaterial({color: gizmo_colors.grid});
var large_box = new THREE.LineSegments( geometry_box, line_material);
if (Blockbench.entity_mode === true) {
large_box.position.set(0,8,0)
} else {
large_box.position.set(8,8,8)
}
large_box.name = 'peter'
large_box.name = 'grid'
three_grid.add(large_box)
}
scene.add(three_grid)
}
function centerTransformer(offset) {
if (selected.length === 0) return;
var first_obj
var rotate_tool = Toolbox.selected.transformerMode === 'rotate'
//Getting Center
if (Animator.open && selected_group) {
var g_mesh = selected_group.getMesh()
var center = [0, 0, 0]
var i = 0;
selected.forEach(function(obj) {
var m = obj.getMesh()
if (obj.visibility && m) {
var pos = new THREE.Vector3(
obj.from[0] + obj.size(0)/2,
obj.from[1] + obj.size(1)/2,
obj.from[2] + obj.size(2)/2
)
if (!Blockbench.entity_mode) {
g_mesh.getWorldPosition(Transformer.position)
Transformer.position.x += 8;
Transformer.position.y += 8;
Transformer.position.z += 8;
Transformer.rotation.set(0, 0, 0)
Transformer.update()
pos.x -= obj.origin[0]
pos.y -= obj.origin[1]
pos.z -= obj.origin[2]
var r = m.getWorldQuaternion(new THREE.Quaternion())
pos.applyQuaternion(r)
pos.x += obj.origin[0]
pos.y += obj.origin[1]
pos.z += obj.origin[2]
} else {
TreeElements.forEach((obj) => {
if (obj.type === 'group') {
let mesh = obj.getMesh()
if (obj.visibility && mesh) {
mesh.updateMatrixWorld()
}
}
})
var r = m.getWorldQuaternion(new THREE.Quaternion())
pos.applyQuaternion(r)
pos.add(m.getWorldPosition(new THREE.Vector3()))
pos.x += 8
pos.y += 8
pos.z += 8
}
center[0] += pos.x
center[1] += pos.y
center[2] += pos.z
if (!first_obj) {
first_obj = obj
}
}
})
if (!first_obj) {
//if (!rotate_tool) {
// var quat = new THREE.Quaternion()
// g_mesh.getWorldQuaternion(quat)
// Transformer.rotation.setFromQuaternion(quat, 'ZYX')
//} else {
//}
return;
}
i = 0;
while (i < 3) {
center[i] = center[i] / selected.length
i++;
//Getting Center
if (Blockbench.entity_mode) {
Canvas.updateAllBones()
}
if (!rotate_tool) {
var first_obj
var center = [0, 0, 0]
var i = 0;
selected.forEach(function(obj) {
var m = obj.getMesh()
if (obj.visibility && m) {
var pos = new THREE.Vector3(
obj.from[0] + obj.size(0)/2,
obj.from[1] + obj.size(1)/2,
obj.from[2] + obj.size(2)/2
)
if (!Blockbench.entity_mode) {
pos.x -= obj.origin[0]
pos.y -= obj.origin[1]
pos.z -= obj.origin[2]
var r = m.getWorldQuaternion(new THREE.Quaternion())
pos.applyQuaternion(r)
pos.x += obj.origin[0]
pos.y += obj.origin[1]
pos.z += obj.origin[2]
} else {
var r = m.getWorldQuaternion(new THREE.Quaternion())
pos.applyQuaternion(r)
pos.add(m.getWorldPosition(new THREE.Vector3()))
pos.x += 8
pos.y += 8
pos.z += 8
}
center[0] += pos.x
center[1] += pos.y
center[2] += pos.z
if (!first_obj) {
first_obj = obj
}
}
})
if (!first_obj) {
return;
}
i = 0;
while (i < 3) {
center[i] = center[i] / selected.length
i++;
}
} else {
var first_obj = selected[0]
var center = first_obj.origin
}
var vec = new THREE.Vector3(center[0], center[1], center[2])
//Position + Rotation
if (Blockbench.entity_mode === false) {
@ -1193,13 +1177,25 @@ function centerTransformer(offset) {
Transformer.position.copy(vec)
var mesh = first_obj.getMesh()
if (mesh && Blockbench.globalMovement === false) {
if (mesh && Blockbench.globalMovement === false && !rotate_tool) {
Transformer.rotation.copy(mesh.rotation)
}
} else {
//Entity Mode
if (selected_group && rotate_tool) {
var mesh = selected_group.getMesh()
if (mesh) {
mesh.getWorldPosition(Transformer.position)
}
Transformer.position.x += 8
Transformer.position.y += 8
Transformer.position.z += 8
Transformer.rotation.set(0, 0, 0)
return;
}
var group;
if (selected_group) {
group = selected_group
@ -1225,7 +1221,7 @@ function centerTransformer(offset) {
vec.z += group.origin[2]
}
Transformer.position.copy(vec)
if (Blockbench.globalMovement === false) {
if (Blockbench.globalMovement === false && !rotate_tool) {
var rotation = new THREE.Quaternion()
first_obj.getMesh().getWorldQuaternion(rotation)
Transformer.rotation.setFromQuaternion( rotation )
@ -1233,10 +1229,7 @@ function centerTransformer(offset) {
Transformer.rotation.set(0, 0, 0)
}
}
if (offset !== undefined) {
//Transformer.position.add(offset)
}
Transformer.update()
}
//Display
function getRescalingFactor(angle) {
@ -1334,6 +1327,7 @@ class CanvasController {
updateAll() {
updateNslideValues()
Canvas.clear()
Canvas.updateAllBones()
elements.forEach(function(s) {
if (s.visibility == true) {
Canvas.addCube(s)
@ -1343,11 +1337,7 @@ class CanvasController {
}
updateAllPositions(leave_selection) {
updateNslideValues()
elements.forEach(function(obj) {
if (obj.visibility == true) {
Canvas.adaptObjectPosition(obj)
}
})
elements.forEach(Canvas.adaptObjectPosition)
if (leave_selection !== true) {
updateSelection()
}
@ -1432,15 +1422,13 @@ class CanvasController {
updateNslideValues()
var arr = selected.slice()
if (Blockbench.entity_mode && selected_group) {
selected_group.children.forEach(function(s) {
if (s.type === 'cube') {
if (!arr.includes(s)) {
arr.push(s)
}
selected_group.forEachChild(obj => {
if (obj.type === 'cube') {
arr.safePush(obj)
}
})
if (arr.length === selected.length) {
Canvas.ascendElementPosition(selected_group)
Canvas.updateAllBones()
}
}
arr.forEach(function(obj) {
@ -1487,6 +1475,37 @@ class CanvasController {
outlines.add(line)
})
}
updateAllBones() {
getAllOutlinerGroups().forEach((obj) => {
let mesh = obj.getMesh()
if (obj.visibility && mesh) {
mesh.rotation.reorder('ZYX')
obj.rotation.forEach(function(n, i) {
mesh.rotation[getAxisLetter(i)] = Math.PI / (180 / n) * (i == 2 ? -1 : 1)
})
mesh.position.fromArray(obj.origin)
mesh.scale.x = mesh.scale.y = mesh.scale.z = 1
if (obj.parent.type === 'group') {
mesh.position.x -= obj.parent.origin[0]
mesh.position.y -= obj.parent.origin[1]
mesh.position.z -= obj.parent.origin[2]
var parent_mesh = obj.parent.getMesh()
parent_mesh.add(mesh)
} else {
scene.add(mesh)
}
mesh.updateMatrixWorld()
mesh.fix_position = mesh.position.clone()
mesh.fix_rotation = mesh.rotation.clone()
}
})
}
//Object handlers
addCube(obj) {
//This does NOT remove old cubes
@ -1505,7 +1524,9 @@ class CanvasController {
Canvas.buildOutline(obj)
}
adaptObjectPosition(obj, mesh, parent) {
if (!mesh) mesh = obj.getMesh()
if (!obj.visibility) return;
if (!mesh || mesh > 0) mesh = obj.getMesh()
function setSize(geo) {
if (Blockbench.entity_mode && obj.inflate !== undefined) {
@ -1527,8 +1548,14 @@ class CanvasController {
if (Blockbench.entity_mode) {
mesh.position.set(0, 0, 0)
mesh.rotation.reorder('YZX')
Canvas.ascendElementPosition(obj, mesh)
if (obj.parent.type === 'group') {
obj.parent.getMesh().add(mesh)
mesh.position.x -= obj.parent.origin[0]
mesh.position.y -= obj.parent.origin[1]
mesh.position.z -= obj.parent.origin[2]
} else {
scene.add(mesh)
}
} else {
if (obj.rotation !== undefined) {
@ -1561,8 +1588,6 @@ class CanvasController {
if (!mesh) {
mesh = obj.getMesh()
}
if (!mesh) {
}
if (obj.type === 'group') {
mesh.rotation.reorder('ZYX')
obj.rotation.forEach(function(n, i) {
@ -1595,23 +1620,9 @@ class CanvasController {
}
iterate(el, elmesh)
}
getOutlineMesh(mesh) {
var vs = mesh.geometry.vertices
var geometry = new THREE.Geometry()
geometry.vertices = [
vs[2], vs[3],
vs[6], vs[7],
vs[2], vs[0],
vs[1], vs[4],
vs[5], vs[0],
vs[5], vs[7],
vs[6], vs[4],
vs[1], vs[3]
]
return new THREE.Line(geometry, Canvas.outlineMaterial)
}
adaptObjectFaces(obj, mesh) {
if (!mesh) mesh = obj.getMesh()
if (!mesh) return;
if (!Prop.wireframe) {
var materials = []
this.face_order.forEach(function(face) {
@ -1753,6 +1764,22 @@ class CanvasController {
mesh.geometry.elementsNeedUpdate = true;
return mesh.geometry
}
//Outline
getOutlineMesh(mesh) {
var vs = mesh.geometry.vertices
var geometry = new THREE.Geometry()
geometry.vertices = [
vs[2], vs[3],
vs[6], vs[7],
vs[2], vs[0],
vs[1], vs[4],
vs[5], vs[0],
vs[5], vs[7],
vs[6], vs[4],
vs[1], vs[3]
]
return new THREE.Line(geometry, Canvas.outlineMaterial)
}
buildOutline(obj) {
if (obj.visibility == false) return;
var mesh = obj.getMesh();
@ -1768,6 +1795,7 @@ class CanvasController {
line.name = obj.uuid+'_outline';
line.visible = obj.selected;
line.renderOrder = 2;
line.frustumCulled = false;
mesh.outline = line;
mesh.add(line);
}
@ -1800,7 +1828,7 @@ BARS.defineActions(function() {
category: 'view',
click: function () {
var lines = [
{label: 'dialog.create_gif.length', node: '<input class="dark_bordered half" type="number" value="10" id="gif_length">'},
{label: 'dialog.create_gif.length', node: '<input class="dark_bordered half" type="number" value="10" step="0.25" id="gif_length">'},
{label: 'dialog.create_gif.fps', node: '<input class="dark_bordered half" type="number" value="10" id="gif_fps">'},
{label: 'dialog.create_gif.compression', node: '<input class="dark_bordered half" type="number" value="4" id="gif_quality">'},
]
@ -1814,7 +1842,7 @@ BARS.defineActions(function() {
lines: lines,
onConfirm: function() {
var jq = $(dialog.object)
var length = parseInt( jq.find('#gif_length').val() )
var length = parseFloat( jq.find('#gif_length').val() )
var fps = parseInt( jq.find('#gif_fps').val() )
var quality = parseInt( jq.find('#gif_quality').val() )
if (jq.find('#gif_play_animation').is(':checked')) {
@ -1823,7 +1851,7 @@ BARS.defineActions(function() {
Screencam.createGif({
length: limitNumber(length, 0.1, 240)*1000,
fps: limitNumber(fps, 0.5, 30),
quality: limitNumber(fps, 0, 30),
quality: limitNumber(quality, 0, 30),
}, Screencam.returnScreenshot)
dialog.hide()
}

View File

@ -7,31 +7,32 @@ function settingSetup() {
settings_old = {}
settings = {
//General
language: {value: 'en', type: 'select', options: Language.options},
show_actions: {value: false},
backup_interval: {value: 10, type: 'number'},
language: {value: 'en', type: 'select', options: Language.options},
backup_interval: {value: 10, type: 'number', condition: isApp},
backup_retain: {value: 30, type: 'number', condition: isApp},
//Preview
origin_size: {category: 'preview', value: 10, type: 'number'},
control_size: {category: 'preview', value: 10, type: 'number'},
//focal_length: {category: 'preview', value: 70, type: 'number'},
display_skin: {category: 'preview', value: false, type: 'click', condition: isApp, icon: 'icon-player', click: function() { changeDisplaySkin() }},
seethrough_outline: {category: 'preview', value: false},
shading: {category: 'preview', value: true},
transparency: {category: 'preview', value: true},
texture_fps: {category: 'preview', value: 2, type: 'number'},
//Grid
base_grid: {category: 'grid', value: true,},
large_grid: {category: 'grid', value: false},
full_grid: {category: 'grid', value: false},
large_box: {category: 'grid', value: false},
display_grid: {category: 'grid', value: false},
//Edit
undo_limit: {category: 'edit', value: 80, type: 'number'},
undo_limit: {category: 'edit', value: 128, type: 'number'},
restricted_canvas: {category: 'edit', value: true},
limited_rotation: {category: 'edit', value: true},
local_move: {category: 'edit', value: true},
canvas_unselect: {category: 'edit', value: false},
paint_side_restrict:{category: 'edit', value: true},
image_editor: {category: 'edit', value: false, type: 'click', condition: isApp, icon: 'fa-pencil-square', click: function() {changeImageEditor() }},
//Grid
base_grid: {category: 'grid', value: true,},
large_grid: {category: 'grid', value: false},
full_grid: {category: 'grid', value: false},
large_box: {category: 'grid', value: false},
display_grid: {category: 'grid', value: false},
//Snapping
edit_size: {category: 'snapping', value: 16, type: 'number'},
shift_size: {category: 'snapping', value: 64, type: 'number'},
@ -247,6 +248,12 @@ function saveSettings(force_update) {
if (hasSettingChanged('texture_fps')) {
TextureAnimator.updateSpeed()
}
/*
if (hasSettingChanged('focal_length')) {
previews.forEach(p => {
p.camPers.setFocalLength(2000/limitNumber(settings.focal_length.value, 10, 200))
})
}*/
if (hasSettingChanged('restricted_canvas') && settings.restricted_canvas.value && Blockbench.entity_mode === false) {
moveIntoBox(undefined, false)
}

View File

@ -29,16 +29,15 @@ class Texture {
var c = 0
var duplicates = false;
while (c < textures.length) {
if (textures[c].id === i) {
if (textures[c].id == i) {
duplicates = true;
}
c++;
}
//var matches = $.grep(textures, function(e) {return e.id == i})
if (duplicates === true) {
i++;
} else {
this.id = i;
this.id = i.toString();
return;
}
}
@ -193,13 +192,19 @@ class Texture {
}
fromJavaLink(link, path_array) {
if (typeof link !== 'string' || (link.substr(0, 1) === '#' && !link.includes('/'))) {
this.load()
this.load();
return this;
}
if (link.substr(0, 22) === 'data:image/png;base64,') {
this.fromDataURL(link)
return this;
}
if (isApp && (link.substr(1, 2) === ':\\' || link.substr(1, 2) === ':/')) {
var path = link.replace(/\\|\//g, osfs).replace(/\?\d+/g, '')
this.fromPath(path)
return this;
}
var can_load = !!path_array.length
var spaces = link.split(':')
if (spaces.length > 1) {
this.namespace = spaces[0]
@ -208,8 +213,16 @@ class Texture {
}
path_array.push('textures', link.replace(/\//g, osfs))
var path = path_array.join(osfs)+'.png'
if (path) {
if (path && can_load) {
this.fromPath(path)
} else {
this.path = path
this.folder = link.replace(/\\/g, '/').split('/')
this.folder = this.folder.splice(0, this.folder.length-1).join('/')
this.name = pathToName(path, true)
this.mode = 'link'
this.saved = true
this.load()
}
return this;
}
@ -296,7 +309,7 @@ class Texture {
delete this.isDefault
}
} else {
var path = settings.default_path.value + osfs + this.folder + osfs + this.name
var path = settings.default_path.value + osfs + this.folder.replace(/\//g, osfs) + osfs + this.name
if (fs.existsSync(path)) {
this.fromPath(path)
return true;
@ -333,7 +346,8 @@ class Texture {
img.tex = tex;
img.tex.magFilter = THREE.NearestFilter
img.tex.minFilter = THREE.NearestFilter
this.tex.needsUpdate = true;
img.tex.needsUpdate = true;
scope.img = img
Canvas.materials[scope.uuid].map = tex
}
return this;
@ -390,7 +404,7 @@ class Texture {
this.refresh(true)
}
startWatcher() {
if (this.mode !== 'link' || !isApp || !fs.existsSync(this.path)) {
if (this.mode !== 'link' || !isApp || !this.path.match(/\.[a-zA-Z]+$/) || !fs.existsSync(this.path)) {
return;
}
var scope = this;
@ -438,11 +452,13 @@ class Texture {
return this;
}
//Management
select() {
textures.forEach(function(s) {
s.selected = false;
select(event) {
textures.forEach(s => {
if (s.selected) s.selected = false;
})
Prop.active_panel = 'textures'
if (event) {
Prop.active_panel = 'textures'
}
this.selected = true
textures.selected = this
return this;
@ -480,14 +496,20 @@ class Texture {
}
return this;
}
remove() {
remove(no_update) {
if (!no_update) {
Undo.initEdit({textures: [this]})
}
this.stopWatcher()
textures.splice(textures.indexOf(this), 1)
Canvas.updateAllFaces()
$('#uv_frame').css('background', 'transparent')
TextureAnimator.updateButton()
hideDialog()
BARS.updateConditions()
if (!no_update) {
Canvas.updateAllFaces()
$('#uv_frame').css('background', 'transparent')
TextureAnimator.updateButton()
hideDialog()
BARS.updateConditions()
Undo.finishEdit('remove_textures', {textures: []})
}
}
//Use
enableParticle() {
@ -656,18 +678,17 @@ class Texture {
return this;
}
toBitmap(cb) {
//Converts texture to bitmap
//Unsaves it
var scope = this;
if (isApp && scope.mode === 'link') {
Jimp.read(scope.source).then(function (image) {
image.getBase64(Jimp.MIME_PNG, function(err, dataUrl) {
scope.mode = 'bitmap'
scope.saved = false
scope.source = dataUrl
cb()
})
})
var canvas = document.createElement('canvas')
canvas.width = scope.img.naturalWidth;
canvas.height = scope.img.naturalHeight;
var ctx = canvas.getContext('2d');
ctx.drawImage(scope.img, 0, 0)
scope.mode = 'bitmap'
scope.saved = false
scope.source = canvas.toDataURL('image/png')
cb()
}
}
edit(cb, options) {

View File

@ -158,37 +158,36 @@ function moveIntoBox(list, value_before) {
Undo.finishEdit('restrict', {cubes: selected, settings: {restricted_canvas: true}})
}
//Movement
function moveCube(obj, val, axis) {
function moveCube(obj, val, axis, move_origin) {
//Obj = Direct - val = Total - Axis = Number
val = limitToBox(val)
val = limitToBox(val + obj.size(axis))
var size = obj.size(axis)
var difference = val - obj.to[axis]
if (!Blockbench.entity_mode || !Blockbench.globalMovement) {
//Move
if (Blockbench.globalMovement && Blockbench.entity_mode && !move_origin) {
var m = new THREE.Vector3()
m[getAxisLetter(axis)] = difference
var rotation = new THREE.Quaternion()
obj.getMesh().getWorldQuaternion(rotation)
m.applyQuaternion(rotation.inverse())
obj.from[0] += m.x;
obj.from[1] += m.y;
obj.from[2] += m.z;
obj.to[0] += m.x;
obj.to[1] += m.y;
obj.to[2] += m.z;
} else {
obj.to[axis] = val
obj.from[axis] = val - size
}
if (Blockbench.globalMovement) {
if (!Blockbench.entity_mode) {
obj.origin[axis] += difference
} else {
var m = new THREE.Vector3()
m[getAxisLetter(axis)] = difference
var rotation = new THREE.Quaternion()
obj.getMesh().getWorldQuaternion(rotation)
m.applyQuaternion(rotation.inverse())
obj.from[0] += m.x;
obj.from[1] += m.y;
obj.from[2] += m.z;
obj.to[0] += m.x;
obj.to[1] += m.y;
obj.to[2] += m.z;
}
//Origin
if (Blockbench.globalMovement && !Blockbench.entity_mode) {
obj.origin[axis] += difference
}
obj.mapAutoUV()
}
@ -404,6 +403,92 @@ function centerCubes(axis, update) {
}
}
function getRotationInterval(event) {
if (settings.limited_rotation.value && !Blockbench.entity_mode) {
return 22.5;
} else if (event.shiftKey && event.ctrlKey) {
return 0.25;
} else if (event.shiftKey) {
return 45;
} else if (event.ctrlKey) {
return 1;
} else {
return 5;
}
}
function rotateOnAxis(value, fixed, axis) {
if (Blockbench.entity_mode) {
if (!selected_group) return;
if (!fixed) {
value = value + selected_group.rotation[axis]
}
value = Math.trimDeg(value)
selected_group.rotation[axis] = value
Canvas.updateAllBones()
return;
}
//Warning
if (settings.limited_rotation.value && settings.dialog_rotation_limit.value) {
var i = 0;
while (i < selected.length) {
if (selected[i].rotation[(axis+1)%3] ||
selected[i].rotation[(axis+2)%3]
) {
i = Infinity
Blockbench.showMessageBox({
title: tl('message.rotation_limit.title'),
icon: 'rotate_right',
message: tl('message.rotation_limit.message'),
buttons: [tl('dialog.ok'), tl('dialog.dontshowagain')]
}, function(r) {
if (r === 1) {
settings.dialog_rotation_limit.value = false
saveSettings()
}
})
return;
//Gotta stop the numslider here
}
i++;
}
}
var axis_letter = getAxisLetter(axis)
var origin = selected[0].origin
selected.forEach(function(obj, i) {
if (!obj.rotation.equals([0,0,0])) {
origin = obj.origin
}
})
selected.forEach(function(obj, i) {
if (obj.rotation.equals([0,0,0])) {
obj.origin = origin
}
var obj_val = value;
if (!fixed) {
obj_val += obj.rotation[axis]
}
obj_val = obj_val % 360
if (settings.limited_rotation.value) {
//Limit To 1 Axis
obj.rotation[(axis+1)%3] = 0
obj.rotation[(axis+2)%3] = 0
//Limit Angle
obj_val = Math.round(obj_val/22.5)*22.5
if (obj_val > 45 || obj_val < -45) {
let f = obj_val > 45
obj.roll(axis, f!=(axis==1) ? 1 : 3)
obj_val = f ? -22.5 : 22.5;
}
} else {
obj_val = Math.trimDeg(obj_val)
}
obj.rotation[axis] = obj_val
obj.rotation_axis = axis_letter
})
}
BARS.defineActions(function() {
function moveOnAxis(value, fixed, axis) {
selected.forEach(function(obj, i) {
@ -531,7 +616,7 @@ BARS.defineActions(function() {
Undo.finishEdit('resize')
}
})
//Inflage
new NumSlider({
id: 'slider_inflate',
condition: function() {return Blockbench.entity_mode && selected.length},
@ -555,91 +640,7 @@ BARS.defineActions(function() {
Undo.finishEdit('inflate')
}
})
function rotateOnAxis(value, fixed, axis) {
if (Blockbench.entity_mode) {
if (!selected_group) return;
if (!fixed) {
value = value + selected_group.rotation[axis]
}
value = value % 360
selected_group.rotation[axis] = value
Canvas.updatePositions()
return;
}
//Warning
if (settings.limited_rotation.value && settings.dialog_rotation_limit.value) {
var i = 0;
while (i < selected.length) {
if (selected[i].rotation[(axis+1)%3] ||
selected[i].rotation[(axis+2)%3]
) {
i = Infinity
Blockbench.showMessageBox({
title: tl('message.rotation_limit.title'),
icon: 'rotate_right',
message: tl('message.rotation_limit.message'),
buttons: [tl('dialog.ok'), tl('dialog.dontshowagain')]
}, function(r) {
if (r === 1) {
settings.dialog_rotation_limit.value = false
saveSettings()
}
})
return;
//Gotta stop the numslider here
}
i++;
}
}
var axis_letter = getAxisLetter(axis)
var origin = selected[0].origin
selected.forEach(function(obj, i) {
if (!obj.rotation.equals([0,0,0])) {
origin = obj.origin
}
})
selected.forEach(function(obj, i) {
if (obj.rotation.equals([0,0,0])) {
obj.origin = origin
}
var obj_val = value;
if (!fixed) {
obj_val += obj.rotation[axis]
}
obj_val = obj_val % 360
if (settings.limited_rotation.value) {
//Limit To 1 Axis
obj.rotation[(axis+1)%3] = 0
obj.rotation[(axis+2)%3] = 0
//Limit Angle
obj_val = Math.round(obj_val/22.5)*22.5
if (obj_val > 45 || obj_val < -45) {
let f = obj_val > 45
obj.roll(axis, f!=(axis==1) ? 1 : 3)
obj_val = f ? -22.5 : 22.5;
}
}
obj.rotation[axis] = obj_val
obj.rotation_axis = axis_letter
})
Canvas.updatePositions()
}
function getRotationInterval(event) {
if (settings.limited_rotation.value && !Blockbench.entity_mode) {
return 22.5;
} else if (event.shiftKey && event.ctrlKey) {
return 0.25;
} else if (event.shiftKey) {
return 45;
} else if (event.ctrlKey) {
return 1;
} else {
return 5;
}
}
//Rotation
new NumSlider({
id: 'slider_rotation_x',
condition: function() {return !!(Blockbench.entity_mode ? selected_group : selected.length)},
@ -649,6 +650,7 @@ BARS.defineActions(function() {
},
change: function(value, fixed) {
rotateOnAxis(value, fixed, 0)
Canvas.updatePositions()
},
onBefore: function() {
Undo.initEdit({cubes: selected, group: selected_group})
@ -667,6 +669,7 @@ BARS.defineActions(function() {
},
change: function(value, fixed) {
rotateOnAxis(value, fixed, 1)
Canvas.updatePositions()
},
onBefore: function() {
Undo.initEdit({cubes: selected, group: selected_group})
@ -685,6 +688,7 @@ BARS.defineActions(function() {
},
change: function(value, fixed) {
rotateOnAxis(value, fixed, 2)
Canvas.updatePositions()
},
onBefore: function() {
Undo.initEdit({cubes: selected, group: selected_group})

View File

@ -7,6 +7,7 @@
class="outliner_object" v-on:dblclick="node.rename($event)"
v-on:click="node.select($event, true)" v-on:touchstart="node.select($event)" :title="node.title"
v-bind:class="{ cube: node.type === \'cube\', group: node.type === \'group\', selected: node.selected }"
v-bind:style="{'padding-left': (node.getDepth ? limitNumber(node.getDepth(), 0, (Interface.Panels.outliner.width-124) / 20) * 20 : 0)+'px'}"
>` +
//Opener

View File

@ -142,6 +142,13 @@ var Undo = {
scope.keyframes[kf.uuid] = kf.undoCopy()
})
}
if (aspects.display_slots) {
scope.display_slots = {}
aspects.display_slots.forEach(slot => {
scope.display_slots[slot] = display[slot].copy()
})
}
},
loadSave: function(save, reference) {
if (save.cubes) {
@ -323,6 +330,38 @@ var Undo = {
}
updateKeyframeSelection()
}
if (save.display_slots) {
for (var slot in save.display_slots) {
if (!display[slot]) {
display[slot] = new DisplaySlot()
}
display[slot].extend(save.display_slots[slot]).update()
}
}
updateSelection()
}
}
}
Undo.save.prototype.addTexture = function(texture) {
if (!this.textures) return;
if (this.aspects.textures.safePush(texture)) {
this.textures[texture.uuid] = texture.getUndoCopy(this.aspects.bitmap)
}
}
BARS.defineActions(function() {
new Action({
id: 'undo',
icon: 'undo',
category: 'edit',
keybind: new Keybind({key: 90, ctrl: true}),
click: function () {Undo.undo()}
})
new Action({
id: 'redo',
icon: 'redo',
category: 'edit',
keybind: new Keybind({key: 89, ctrl: true}),
click: function () {Undo.redo()}
})
})

View File

@ -48,6 +48,18 @@ function useBedrockFlipFix(axis) {
return false
}
}
const Condition = function(condition, context) {
if (condition !== undefined && condition !== null && condition.condition !== undefined) {
condition = condition.condition
}
if (condition === undefined) {
return true;
} else if (typeof condition === 'function') {
return condition(context)
} else {
return !!condition
}
}
var cl = console.log
var asyncLoop = function(o){
var i=-1;
@ -85,6 +97,9 @@ Math.lerp = function(a,b,m) {
Math.isBetween = function(n, a, b) {
return (n - a) * (n - b) <= 0
}
Math.trimDeg = function(a) {
return (a+180*15)%360-180
}
function trimFloatNumber(val) {
if (val == '') return val;
var string = val.toFixed(4)
@ -154,8 +169,10 @@ function doRectanglesOverlap(rect1, rect2) {
//Array
Array.prototype.safePush = function(item) {
if (!this.includes(item)) {
this.push(item)
this.push(item);
return true;
}
return false;
}
Array.prototype.equals = function (array) {
if (!array)
@ -342,50 +359,51 @@ tinycolor.prototype.toInt = function() {
var rgba = this.toRgb()
return Jimp.rgbaToInt(rgba.r, rgba.g, rgba.b, rgba.a)
}
function getAverageRGB(imgEl) {
function getAverageRGB(imgEl, blockSize) {
var blockSize = 5, // only visit every 5 pixels
defaultRGB = {r:0,g:0,b:0}, // for non-supporting envs
canvas = document.createElement('canvas'),
context = canvas.getContext && canvas.getContext('2d'),
data, width, height,
i = -4,
length,
rgb = {r:0,g:0,b:0},
count = 0;
if (!context) {
return defaultRGB;
var defaultRGB = {r:0,g:0,b:0}, // for non-supporting envs
canvas = document.createElement('canvas'),
context = canvas.getContext && canvas.getContext('2d'),
data, width, height,
i = -4,
length,
rgb = {r:0,g:0,b:0},
count = 0;
if (!context) {
return defaultRGB;
}
height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
context.drawImage(imgEl, 0, 0);
try {
data = context.getImageData(0, 0, width, height);
} catch(e) {
/* security error, img on diff domain */alert('x');
return defaultRGB;
}
length = data.data.length;
if (!blockSize) blockSize = Math.ceil(length/64)
while ( (i += blockSize * 4) < length ) {
if (data.data[i+3] > 0) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i+1];
rgb.b += data.data[i+2];
}
height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
context.drawImage(imgEl, 0, 0);
try {
data = context.getImageData(0, 0, width, height);
} catch(e) {
/* security error, img on diff domain */alert('x');
return defaultRGB;
}
length = data.data.length;
while ( (i += blockSize * 4) < length ) {
if (data.data[i+3] > 0) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i+1];
rgb.b += data.data[i+2];
}
}
// ~~ used to floor values
rgb.r = ~~(rgb.r/count);
rgb.g = ~~(rgb.g/count);
rgb.b = ~~(rgb.b/count);
return rgb;
}
// ~~ used to floor values
rgb.r = ~~(rgb.r/count);
rgb.g = ~~(rgb.g/count);
rgb.b = ~~(rgb.b/count);
return rgb;
}

View File

@ -1109,7 +1109,7 @@ class UVEditor {
uv: tag.uv.slice(),
face: face
}
if (tag.texture) new_tag.texture = tag.texture
if (tag.texture !== undefined) new_tag.texture = tag.texture
if (tag.cullface) new_tag.cullface = tag.cullface
if (tag.rotation) new_tag.rotation = tag.rotation
if (tag.enabled !== undefined) new_tag.enabled = tag.enabled
@ -1144,7 +1144,7 @@ class UVEditor {
var target = obj.faces[face]
target.uv = tag.uv.slice()
if (tag.texture || target.texture) target.texture = tag.texture
if (tag.texture !== undefined || target.texture !== undefined) target.texture = tag.texture
if (tag.cullface || target.cullface) target.cullface = tag.cullface
if (tag.rotation || target.rotation) target.rotation = tag.rotation
if (tag.enabled !== undefined || target.enabled !== undefined) target.enabled = tag.enabled

View File

@ -2,7 +2,6 @@
$.getScript("lib/file_saver.js");
})()
$(document).ready(function() {
$('.open-in-browser').click((event) => {
event.preventDefault();
@ -10,8 +9,6 @@ $(document).ready(function() {
});
})
function tryLoadPOSTModel() {
if ($('#post_model').text() !== '') {
if ($('#post_textures').text() !== '') {
@ -40,20 +37,7 @@ function tryLoadPOSTModel() {
}
}
//Saver
function writeFileEntity() {
var obj = {}
var model_name = Project.parent
if (model_name == '') model_name = 'geometry.unknown'
obj[model_name] = buildEntityModel({raw: true})
var data = autoStringify(obj)
var blob = new Blob([data], {type: "text/plain;charset=utf-8"});
saveAs(blob, 'mobs.json', {autoBOM: true})
Blockbench.showQuickMessage('Saved as bedrock entity model')
}
function writeFileObj() {
var delay = 40
var content = buildOBJModel('model')
@ -99,9 +83,11 @@ function writeFileObj() {
}
function saveFile() {
var data = buildBlockModel()
var blob = new Blob([data], {type: "text/plain;charset=utf-8"});
saveAs(blob, 'model.json', {autoBOM: true})
if (Blockbench.entity_mode === false) {
BarItems.export_blockmodel.trigger()
} else {
BarItems.export_entity.trigger()
}
}
//Misc

View File

@ -99,7 +99,7 @@
"message.restart_to_update": "Starte Blockbench neu, um die Änderungen wirksam werden zu lassen.",
"message.save_file": "Gespeichert als %0",
"message.save_obj": "Gespeichert als .obj Modell",
"message.save_entity": "Gespeichert als Bedrock TIermodell",
"message.save_entity": "Gespeichert als Bedrock Entitymodell",
"message.rename_cubes": "Elemente umbenennen",
"dialog.project.title": "Projekt",
"dialog.project.name": "Dateiname",
@ -354,8 +354,6 @@
"action.brush_tool.desc": "Werkzeug zum Malen auf Texturen an Elementen oder im UV Fenster",
"action.vertex_snap_tool": "Eckpunktmagnet",
"action.vertex_snap_tool.desc": "Verbindet die Ecken von 2 Elementen indem es das eine verschiebt",
"action.display_mode_tool": "Anzeigemodus",
"action.display_mode_tool.desc": "Verändern, wie das Modell im Spiel positioniert ist",
"action.swap_tools": "Werkzeuge wechseln",
"action.swap_tools.desc": "Wechselt zwischen dem Verschieben- und Größenwerkzeug",
"action.project_window": "Projekt...",
@ -363,7 +361,7 @@
"action.new_block_model": "Neues Modell",
"action.new_block_model.desc": "Erstellt ein neues Block- oder Gegenstandsmodell",
"action.new_entity_model": "Neues Tiermodell",
"action.new_entity_model.desc": "Erstellt ein neues Bedrock Tiermodell",
"action.new_entity_model.desc": "Erstellt ein neues Bedrock Entitymodell",
"action.open_model": "Modell Öffnen",
"action.open_model.desc": "Öffne ein Modell von deinem Computer",
"action.add_model": "Modell hinzufügen",
@ -375,9 +373,9 @@
"action.export_entity": "Bedrock Tier exportieren",
"action.export_entity.desc": "Das aktuelle Modell als Tier zu einer mobs.json Datei hinzufügen",
"action.export_optifine_part": "OptiFine JPM exportieren",
"action.export_optifine_part.desc": "Einen Tier-Komponenten für OptiFine exportieren",
"action.export_optifine_part.desc": "Einen Entity-Komponenten für OptiFine exportieren",
"action.export_optifine_full": "OptiFine JEM exportieren",
"action.export_optifine_full.desc": "Ein vollständiges Tiermodell für OptiFine exportieren",
"action.export_optifine_full.desc": "Ein vollständiges Entitymodell für OptiFine exportieren",
"action.export_obj": "OBJ Modell exportieren",
"action.export_obj.desc": "Ein Wavefront OBJ Modell exportieren zur Weiterverwendung in anderen Programmen oder zum Hochladen auf Sketchfab",
"action.save": "Speichern",
@ -648,10 +646,8 @@
"dialog.update.latest": "Aktuelle Version",
"dialog.update.installed": "Installierte Version",
"dialog.update.update": "Aktualisieren",
"action.brush_mode.brush": "Pinsel",
"action.brush_mode.brush": "Rund",
"action.brush_mode.noise": "Rauschen",
"action.brush_mode.eraser": "Radierer",
"action.brush_mode.fill": "Füllen",
"action.vertex_snap_mode.move": "Verschieben",
"action.vertex_snap_mode.scale": "Größe ändern",
"action.open_model_folder": "Modellordner öffnen",
@ -732,8 +728,6 @@
"category.uv": "UV",
"status_bar.saved": "Modell ist gespeichert",
"status_bar.unsaved": "Es gibt ungespeicherte Änderungen",
"action.animation_mode_tool": "Animation",
"action.animation_mode_tool.desc": "Erstelle eigene Animationen für dieses Modell",
"action.move_up": "Hoch verschieben",
"action.move_up.desc": "Verschiebt die ausgewählten Elemente relativ zur Kameraperspektive nach oben",
"action.move_down": "Runter verschieben",
@ -811,5 +805,23 @@
"action.export_class_entity": "Java Entity exportieren",
"action.export_class_entity.desc": "Exportiert das Modell als Java Class.",
"settings.seethrough_outline": "Durchscheinende Auswahl",
"settings.seethrough_outline.desc": "Zeige Auswahl durch Objekte hindurch an"
"settings.seethrough_outline.desc": "Zeige Auswahl durch Objekte hindurch an",
"mode.edit": "Modellieren",
"mode.paint": "Malen",
"mode.display": "Vorschau",
"mode.animate": "Animieren",
"status_bar.recording_gif": "GIF wird aufgezeichnet",
"status_bar.processing_gif": "GIF wird verarbeitet",
"settings.backup_retain": "Backup Speicherdauer",
"settings.backup_retain.desc": "Festlegen, wie viele Tage Blockbench alte Backups speichert",
"action.rotate_tool": "Drehen",
"action.rotate_tool.desc": "Werkzeug zum Auswählen und Drehen von Elementen",
"action.fill_tool": "Farbeimer",
"action.fill_tool.desc": "Farbeimer zum einfarbigen Ausfüllen von Oberflächen",
"action.eraser": "Radiergummi",
"action.eraser.desc": "Raddiergummi zum Ersetzen der Farben durch Transparenz",
"action.color_picker": "Farbpipette",
"action.color_picker.desc": "Wählt die Farbe eines Pixels der Textur aus.",
"action.open_backup_folder": "Backup-Ordner öffnen",
"action.open_backup_folder.desc": "Öffnet den Backup-Ordner von Blockbench"
}

View File

@ -22,6 +22,11 @@
"generic.delete": "Delete",
"generic.rename": "Rename",
"mode.edit": "Edit",
"mode.paint": "Paint",
"mode.display": "Display",
"mode.animate": "Animate",
"keys.ctrl": "Control",
"keys.shift": "Shift",
"keys.alt": "Alt",
@ -58,6 +63,8 @@
"status_bar.saved":"Model is saved",
"status_bar.unsaved":"There are unsaved changes",
"status_bar.vertex_distance":"Distance: %0",
"status_bar.recording_gif":"Recording GIF",
"status_bar.processing_gif":"Processing GIF",
"message.rotation_limit.title": "Rotation Limits",
"message.rotation_limit.message": "Rotations are limited by Minecraft to one axis and 22.5 degree increments. Rotating on a different axis will clear all rotations on the other axes. Disable the option \"Restricted Rotation\" if you are modeling for other purposes and need free rotations.",
@ -300,11 +307,13 @@
"settings.category.export": "Export",
"settings.language": "Language",
"settings.language.desc": "Interface language. Restart Blockbench to apply changes.",
"settings.language.desc": "Interface language. Restart Blockbench to apply changes",
"settings.show_actions": "Display Actions",
"settings.show_actions.desc": "Display every action in the status bar",
"settings.backup_interval": "Backup Interval",
"settings.backup_interval.desc": "Interval of the automatic backups in minutes",
"settings.backup_retain": "Backup Retain Duration",
"settings.backup_retain.desc": "Set how long Blockbench retains old backups in days",
"settings.origin_size": "Rotation Origin",
"settings.origin_size.desc": "Size of the rotation origin",
@ -428,10 +437,8 @@
"action.brush_mode": "Brush Mode",
"action.brush_mode.desc": "Mode of the brush",
"action.brush_mode.brush": "Brush",
"action.brush_mode.brush": "Round",
"action.brush_mode.noise": "Noise",
"action.brush_mode.eraser": "Eraser",
"action.brush_mode.fill": "Fill",
"action.brush_color": "Color",
"action.brush_color.desc": "Color of the brush",
"action.slider_brush_size": "Size",
@ -461,14 +468,19 @@
"action.move_tool.desc": "Tool to select and move elements",
"action.resize_tool": "Resize",
"action.resize_tool.desc": "Tool to select and resize elements",
"action.rotate_tool": "Rotate",
"action.rotate_tool.desc": "Tool to select and rotate elements",
"action.brush_tool": "Paint Brush",
"action.brush_tool.desc": "Tool to paint on bitmap textures on surfaces or the UV editor.",
"action.brush_tool.desc": "Tool to paint on bitmap textures on surfaces or the UV editor",
"action.fill_tool": "Paint Bucket",
"action.fill_tool.desc": "Paint bucket to fill entire faces with one color",
"action.eraser": "Eraser",
"action.eraser.desc": "Eraser tool to replace colors on a texture with transparency",
"action.color_picker": "Color Picker",
"action.color_picker.desc": "Tool to pick the color of pixels on your texture",
"action.vertex_snap_tool": "Vertex Snap",
"action.vertex_snap_tool.desc": "Move one cube to another cube by connecting two vertices.",
"action.display_mode_tool": "Display",
"action.display_mode_tool.desc": "Change how the model will look when held by players",
"action.animation_mode_tool": "Animation",
"action.animation_mode_tool.desc": "Define custom animations for the model",
"action.vertex_snap_tool.desc": "Move one cube to another cube by connecting two vertices",
"action.swap_tools": "Swap Tools",
"action.swap_tools.desc": "Switch between the move and resize tool",
@ -476,6 +488,8 @@
"action.project_window.desc": "Opens the project window, where you can edit metadata of your model",
"action.open_model_folder": "Open Model Folder",
"action.open_model_folder.desc": "Opens the folder that the model is contained in",
"action.open_backup_folder": "Open Backup Folder",
"action.open_backup_folder.desc": "Opens the Blockbench backup folder",
"action.new_block_model": "New Model",
"action.new_block_model.desc": "Creates a new block/item model",
"action.new_entity_model": "New Entity Model",
@ -492,10 +506,10 @@
"action.export_entity.desc": "Add the current model as an entity to a mobs.json file",
"action.export_class_entity": "Export Java Entity",
"action.export_class_entity.desc": "Export the entity model as a Java class",
"action.export_optifine_part": "Export Optifine JPM",
"action.export_optifine_part.desc": "Export an entity part model for Optifine",
"action.export_optifine_full": "Export Optifine JEM",
"action.export_optifine_full.desc": "Export a full Optifine entity model",
"action.export_optifine_part": "Export OptiFine JPM",
"action.export_optifine_part.desc": "Export an entity part model for OptiFine",
"action.export_optifine_full": "Export OptiFine JEM",
"action.export_optifine_full.desc": "Export a full OptiFine entity model",
"action.export_obj": "Export OBJ Model",
"action.export_obj.desc": "Export a Wavefront OBJ model for use in other programs or to upload to Sketchfab",
"action.save": "Save",

View File

@ -354,8 +354,6 @@
"action.brush_tool.desc": "Herramienta para pintar en texturas bitmap en superficies o en el editor de UV",
"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.display_mode_tool": "Visualización",
"action.display_mode_tool.desc": "Cambiar cómo del modelo se verá cuando esté sujetado por jugadores",
"action.swap_tools": "Cambiar Herramientas",
"action.swap_tools.desc": "Cambiar entre la herramienta para mover y para reescalar",
"action.project_window": "Proyecto...",
@ -650,8 +648,6 @@
"dialog.update.update": "Actualizar",
"action.brush_mode.brush": "Pincel",
"action.brush_mode.noise": "Ruido",
"action.brush_mode.eraser": "Goma",
"action.brush_mode.fill": "Rellenar",
"action.vertex_snap_mode.move": "Mover",
"action.vertex_snap_mode.scale": "Reescalar",
"action.open_model_folder": "Abrir la Carpeta del Modelo",
@ -732,8 +728,6 @@
"category.uv": "UV",
"status_bar.saved": "El modelo está guardado",
"status_bar.unsaved": "Hay cambios sin guardar",
"action.animation_mode_tool": "Animación",
"action.animation_mode_tool.desc": "Define animaciones personalizadas para este modelo",
"action.move_up": "Mover Hacia Arriba",
"action.move_up.desc": "Mueve los cubos seleccionados hacia arriba relativo al ángulo actual de la cámara",
"action.move_down": "Mover Hacia Abajo",
@ -810,6 +804,24 @@
"dialog.toolbar_edit.hidden": "Oculto",
"action.export_class_entity": "Exportar Entidad de Java",
"action.export_class_entity.desc": "Exporta el modelo de entidad como una clase de Java",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
"settings.seethrough_outline": "Bordes Rayos-X",
"settings.seethrough_outline.desc": "Mostrar los bordes a través de los objetos",
"mode.edit": "Editar",
"mode.paint": "Pintar",
"mode.display": "Mostrar",
"mode.animate": "Animar",
"status_bar.recording_gif": "Grabando GIF",
"status_bar.processing_gif": "Procesando GIF",
"settings.backup_retain": "Mantenimiento de Backups",
"settings.backup_retain.desc": "Ajustar cuanto tiempo Blockbench mantiene backups viejos en días",
"action.rotate_tool": "Rotar",
"action.rotate_tool.desc": "Herramienta para seleccionar y rotar elementos",
"action.fill_tool": "Cubo de Pintura",
"action.fill_tool.desc": "Herramienta para rellenar caras enteras con un color",
"action.eraser": "Borrador",
"action.eraser.desc": "Herramienta para reemplazar colores en una textura por transparencia",
"action.color_picker": "Seleccionador de Color",
"action.color_picker.desc": "Herramienta para seleccionar el color de píxeles en tu textura",
"action.open_backup_folder": "Abrir Carpeta de Backups",
"action.open_backup_folder.desc": "Abre la carpeta de backups de Blockbench"
}

View File

@ -354,8 +354,6 @@
"action.brush_tool.desc": "Outil pour peindre sur des textures bitmap, des surfaces ou l'éditeur UV.",
"action.vertex_snap_tool": "Vertex Snap",
"action.vertex_snap_tool.desc": "Déplacez un cube vers un autre en connectant les deux sommets.",
"action.display_mode_tool": "Affichage",
"action.display_mode_tool.desc": "Changer l'apparence du modèle lorsqu'il est tenu par un joueur",
"action.swap_tools": "Outils d'échange",
"action.swap_tools.desc": "Basculer entre le déplacement et l'outil de redimensionnement",
"action.project_window": "Projet...",
@ -650,8 +648,6 @@
"dialog.update.update": "Mettre à jour",
"action.brush_mode.brush": "Brosse",
"action.brush_mode.noise": "Bruit",
"action.brush_mode.eraser": "Gomme",
"action.brush_mode.fill": "Remplir",
"action.vertex_snap_mode.move": "Déplacer",
"action.vertex_snap_mode.scale": "Échelle",
"action.open_model_folder": "Ouvrir le dossier de modèle",
@ -732,8 +728,6 @@
"category.uv": "UV",
"status_bar.saved": "Le modèle est enregistré",
"status_bar.unsaved": "Il y a des modifications non enregistrées",
"action.animation_mode_tool": "Animation",
"action.animation_mode_tool.desc": "Définir des animations personnalisées pour le modèle",
"action.move_up": "Déplacer vers le haut",
"action.move_up.desc": "Déplacer les cubes sélectionnés vers le haut par rapport à l'angle de caméra actuel",
"action.move_down": "Déplacer vers le bas",
@ -811,5 +805,23 @@
"action.export_class_entity": "Export Java Entity",
"action.export_class_entity.desc": "Export the entity model as a Java class",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
"settings.seethrough_outline.desc": "Show outlines through objects",
"mode.edit": "Edit",
"mode.paint": "Paint",
"mode.display": "Display",
"mode.animate": "Animate",
"status_bar.recording_gif": "Recording GIF",
"status_bar.processing_gif": "Processing GIF",
"settings.backup_retain": "Backup Retain Duration",
"settings.backup_retain.desc": "Set how long Blockbench retains old backups in days",
"action.rotate_tool": "Rotate",
"action.rotate_tool.desc": "Tool to select and rotate elements",
"action.fill_tool": "Paint Bucket",
"action.fill_tool.desc": "Paint bucket to fill entire faces with one color",
"action.eraser": "Eraser",
"action.eraser.desc": "Eraser tool to replace colors on a texture with transparency",
"action.color_picker": "Color Picker",
"action.color_picker.desc": "Tool to pick the color of pixels on your texture",
"action.open_backup_folder": "Open Backup Folder",
"action.open_backup_folder.desc": "Opens the Blockbench backup folder"
}

View File

@ -354,8 +354,6 @@
"action.brush_tool.desc": "テクスチャまたはUVエディタにペイントする",
"action.vertex_snap_tool": "頂点スナップ",
"action.vertex_snap_tool.desc": "2つのブロックの頂点を接続する",
"action.display_mode_tool": "表示",
"action.display_mode_tool.desc": "プレイヤーが持ってるときのモデルの変更",
"action.swap_tools": "スワップツール",
"action.swap_tools.desc": "移動ツールとサイズ変更ツールを切り替える",
"action.project_window": "プロジェクト…",
@ -650,8 +648,6 @@
"dialog.update.update": "更新する",
"action.brush_mode.brush": "ブラシ",
"action.brush_mode.noise": "ノイズ",
"action.brush_mode.eraser": "消しゴム",
"action.brush_mode.fill": "塗りつぶす",
"action.vertex_snap_mode.move": "移動",
"action.vertex_snap_mode.scale": "サイズ",
"action.open_model_folder": "モデルフォルダを開く",
@ -732,8 +728,6 @@
"category.uv": "UV",
"status_bar.saved": "モデルが保存されています",
"status_bar.unsaved": "変更が保存されていません",
"action.animation_mode_tool": "アニメーション",
"action.animation_mode_tool.desc": "モデルのカスタムアニメーション",
"action.move_up": "上に移動",
"action.move_up.desc": "選択したキューブを上に移動する",
"action.move_down": "下に移動",
@ -794,7 +788,7 @@
"action.camera_reset.desc": "現在のプレビューをデフォルトのカメラアングルにリセットする",
"panel.variable_placeholders": "可変プレースホルダ",
"panel.variable_placeholders.info": "プレビューする変数を 名前 = 値で表示する",
"status_bar.vertex_distance": "キョリ:%0",
"status_bar.vertex_distance": "間隔:%0",
"dialog.create_gif.title": "レコードGIF",
"dialog.create_gif.length": "長さ(秒)",
"dialog.create_gif.fps": "FPS",
@ -810,6 +804,24 @@
"dialog.toolbar_edit.hidden": "隠す",
"action.export_class_entity": "Java Entityをエクスポート",
"action.export_class_entity.desc": "エンティティモデルをjava としてエクスポートする",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
"settings.seethrough_outline": "X-Rey アウトライン",
"settings.seethrough_outline.desc": "オブジェクトを通してアウトラインを表示する",
"mode.edit": "Edit",
"mode.paint": "Paint",
"mode.display": "Display",
"mode.animate": "Animate",
"status_bar.recording_gif": "Recording GIF",
"status_bar.processing_gif": "Processing GIF",
"settings.backup_retain": "Backup Retain Duration",
"settings.backup_retain.desc": "Set how long Blockbench retains old backups in days",
"action.rotate_tool": "Rotate",
"action.rotate_tool.desc": "Tool to select and rotate elements",
"action.fill_tool": "Paint Bucket",
"action.fill_tool.desc": "Paint bucket to fill entire faces with one color",
"action.eraser": "Eraser",
"action.eraser.desc": "Eraser tool to replace colors on a texture with transparency",
"action.color_picker": "Color Picker",
"action.color_picker.desc": "Tool to pick the color of pixels on your texture",
"action.open_backup_folder": "Open Backup Folder",
"action.open_backup_folder.desc": "Opens the Blockbench backup folder"
}

View File

@ -354,8 +354,6 @@
"action.brush_tool.desc": "Gereedschap om te tekenen op bitmap texturen op oppervlakken of in de UV editor.",
"action.vertex_snap_tool": "Hoeken Snap",
"action.vertex_snap_tool.desc": "Beweeg een kubus naar een ander kubus door twee hoeken te verbinden",
"action.display_mode_tool": "Uitzicht",
"action.display_mode_tool.desc": "Verander hoe het model eruit zal zien wanneer het door spelers wordt vastgehouden",
"action.swap_tools": "Verwissel Gereedschap",
"action.swap_tools.desc": "Verwissel verplaats en vergroot gereedschap",
"action.project_window": "Project...",
@ -650,8 +648,6 @@
"dialog.update.update": "Update",
"action.brush_mode.brush": "Penseel",
"action.brush_mode.noise": "Lawaai ",
"action.brush_mode.eraser": "Gum",
"action.brush_mode.fill": "Vul",
"action.vertex_snap_mode.move": "Beweeg",
"action.vertex_snap_mode.scale": "Schaal",
"action.open_model_folder": "Open Model Map",
@ -732,12 +728,10 @@
"category.uv": "UV",
"status_bar.saved": "Model is opgeslagen",
"status_bar.unsaved": "Er zijn onopgeslagen veranderingen",
"action.animation_mode_tool": "Animatie",
"action.animation_mode_tool.desc": "Defineer custom animaties voor het model",
"action.move_up": "Beweeg omhoog",
"action.move_up.desc": "Move the selected cubes up relative to the current camera angle",
"action.move_up.desc": "Beweeg de geselecteerde kubussen omhoog in opzicht van de huidige camerahoek",
"action.move_down": "Beweeg naar beneden",
"action.move_down.desc": "Move the selected cubes down relative to the current camera angle",
"action.move_down.desc": "Beweeg de geselecteerde kubussen naar beneden ten opzichte van de huidige camerahoek",
"action.move_left": "Beweeg Naar Links",
"action.move_left.desc": "Move the selected cubes left relative to the current camera angle",
"action.move_right": "Beweeg Naar Rechts",
@ -811,5 +805,23 @@
"action.export_class_entity": "Export Java Entity",
"action.export_class_entity.desc": "Export the entity model as a Java class",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
"settings.seethrough_outline.desc": "Show outlines through objects",
"mode.edit": "Edit",
"mode.paint": "Paint",
"mode.display": "Display",
"mode.animate": "Animate",
"status_bar.recording_gif": "Recording GIF",
"status_bar.processing_gif": "Processing GIF",
"settings.backup_retain": "Backup Retain Duration",
"settings.backup_retain.desc": "Set how long Blockbench retains old backups in days",
"action.rotate_tool": "Rotate",
"action.rotate_tool.desc": "Tool to select and rotate elements",
"action.fill_tool": "Paint Bucket",
"action.fill_tool.desc": "Paint bucket to fill entire faces with one color",
"action.eraser": "Eraser",
"action.eraser.desc": "Eraser tool to replace colors on a texture with transparency",
"action.color_picker": "Color Picker",
"action.color_picker.desc": "Tool to pick the color of pixels on your texture",
"action.open_backup_folder": "Open Backup Folder",
"action.open_backup_folder.desc": "Opens the Blockbench backup folder"
}

View File

@ -354,8 +354,6 @@
"action.brush_tool.desc": "Narzędzie do malowania na teksturach bitmapowych na powierzniach lub w edytorze UV.",
"action.vertex_snap_tool": "Przyciąganie wierzchołków",
"action.vertex_snap_tool.desc": "Przesuń jedną kostkę do innej przez połączenie dwóch wierzchołków.",
"action.display_mode_tool": "Wyświetlanie",
"action.display_mode_tool.desc": "Zmień wygląd modelu, kiedy trzyma go gracz",
"action.swap_tools": "Przełącz narzędzia",
"action.swap_tools.desc": "Przełącz się pomiędzy narzędziem przesuwania i zmiany rozmiaru",
"action.project_window": "Projekt...",
@ -650,8 +648,6 @@
"dialog.update.update": "Aktualizacja",
"action.brush_mode.brush": "Szczotka",
"action.brush_mode.noise": "Mieszanie",
"action.brush_mode.eraser": "Gumka",
"action.brush_mode.fill": "Wypełnij",
"action.vertex_snap_mode.move": "Przesuń",
"action.vertex_snap_mode.scale": "Skaluj",
"action.open_model_folder": "Otwórz folder modelu",
@ -732,8 +728,6 @@
"category.uv": "UV",
"status_bar.saved": "Model jest zapisany",
"status_bar.unsaved": "Istnieją niezapisane zmiany",
"action.animation_mode_tool": "Animacja",
"action.animation_mode_tool.desc": "Zdefiniuj własne animacje dla modelu",
"action.move_up": "Przesuń w górę",
"action.move_up.desc": "Przesuń zaznaczone kostki w górę, względem aktualnego kąta kamery",
"action.move_down": "Przesuń w dół",
@ -811,5 +805,23 @@
"action.export_class_entity": "Export Java Entity",
"action.export_class_entity.desc": "Export the entity model as a Java class",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
"settings.seethrough_outline.desc": "Show outlines through objects",
"mode.edit": "Edit",
"mode.paint": "Paint",
"mode.display": "Display",
"mode.animate": "Animate",
"status_bar.recording_gif": "Recording GIF",
"status_bar.processing_gif": "Processing GIF",
"settings.backup_retain": "Backup Retain Duration",
"settings.backup_retain.desc": "Set how long Blockbench retains old backups in days",
"action.rotate_tool": "Rotate",
"action.rotate_tool.desc": "Tool to select and rotate elements",
"action.fill_tool": "Paint Bucket",
"action.fill_tool.desc": "Paint bucket to fill entire faces with one color",
"action.eraser": "Eraser",
"action.eraser.desc": "Eraser tool to replace colors on a texture with transparency",
"action.color_picker": "Color Picker",
"action.color_picker.desc": "Tool to pick the color of pixels on your texture",
"action.open_backup_folder": "Open Backup Folder",
"action.open_backup_folder.desc": "Opens the Blockbench backup folder"
}

View File

@ -354,8 +354,6 @@
"action.brush_tool.desc": "Инструмент для рисования на текстурах, на гранях кубов или в редакторе UV",
"action.vertex_snap_tool": "Вершинная привязка",
"action.vertex_snap_tool.desc": "Перемещение одного куба к другому, соединяя две их вершины",
"action.display_mode_tool": "Отображение",
"action.display_mode_tool.desc": "Изменение вида модели в руках игроков",
"action.swap_tools": "Смена инструмента",
"action.swap_tools.desc": "Переключение между инструментом перемещения и изменения размера",
"action.project_window": "Проект...",
@ -650,8 +648,6 @@
"dialog.update.update": "Обновление",
"action.brush_mode.brush": "Кисть",
"action.brush_mode.noise": "Шум",
"action.brush_mode.eraser": "Ластик",
"action.brush_mode.fill": "Заливка",
"action.vertex_snap_mode.move": "Перемещение",
"action.vertex_snap_mode.scale": "Масштабирование",
"action.open_model_folder": "Открыть расположение модели",
@ -732,8 +728,6 @@
"category.uv": "UV",
"status_bar.saved": "Модель сохранена",
"status_bar.unsaved": "Есть несохранённые изменения",
"action.animation_mode_tool": "Анимация",
"action.animation_mode_tool.desc": "Определить пользовательские анимации для модели",
"action.move_up": "Двигать вверх",
"action.move_up.desc": "Двигать выбранные кубы вверх относительно камеры",
"action.move_down": "Двигать вниз",
@ -810,6 +804,24 @@
"dialog.toolbar_edit.hidden": "Спрятано",
"action.export_class_entity": "Экспортировать сущность Java",
"action.export_class_entity.desc": "Экспортировать модель сущности как класс Java",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
"settings.seethrough_outline": "Рентгенные контуры",
"settings.seethrough_outline.desc": "Показывать контуры через объекты",
"mode.edit": "Изменить",
"mode.paint": "Красить",
"mode.display": "Предпросмотр",
"mode.animate": "Анимировать",
"status_bar.recording_gif": "Recording GIF",
"status_bar.processing_gif": "Processing GIF",
"settings.backup_retain": "Продолжительность хранения автосохранений",
"settings.backup_retain.desc": "Set how long Blockbench retains old backups in days",
"action.rotate_tool": "Вращать",
"action.rotate_tool.desc": "Tool to select and rotate elements",
"action.fill_tool": "Paint Bucket",
"action.fill_tool.desc": "Paint bucket to fill entire faces with one color",
"action.eraser": "Ластик",
"action.eraser.desc": "Eraser tool to replace colors on a texture with transparency",
"action.color_picker": "Color Picker",
"action.color_picker.desc": "Tool to pick the color of pixels on your texture",
"action.open_backup_folder": "Открыть папку",
"action.open_backup_folder.desc": "Opens the Blockbench backup folder"
}

View File

@ -354,8 +354,6 @@
"action.brush_tool.desc": "Verktyg att måla på bitmaptexturer på ytor eller UV-redigeraren.",
"action.vertex_snap_tool": "Vortex Snap",
"action.vertex_snap_tool.desc": "Flytta en kub till en annan kub genom att koppla samman två hörn.",
"action.display_mode_tool": "Visa",
"action.display_mode_tool.desc": "Ändra hur modellen ser ut när den hålls utav spelare",
"action.swap_tools": "Byt verktyg",
"action.swap_tools.desc": "Växla mellan flytt och storleks verktygen",
"action.project_window": "Projekt...",
@ -650,8 +648,6 @@
"dialog.update.update": "Uppdatera",
"action.brush_mode.brush": "Pensel",
"action.brush_mode.noise": "Brus",
"action.brush_mode.eraser": "Suddgummi",
"action.brush_mode.fill": "Fyll",
"action.vertex_snap_mode.move": "Flytta",
"action.vertex_snap_mode.scale": "Skala",
"action.open_model_folder": "Öppna modellmapp",
@ -732,8 +728,6 @@
"category.uv": "UV",
"status_bar.saved": "Modellen är sparad",
"status_bar.unsaved": "Det finns osparade ändringar",
"action.animation_mode_tool": "Animation",
"action.animation_mode_tool.desc": "Definiera anpassade animationer för modellen",
"action.move_up": "Flytta upp",
"action.move_up.desc": "Flytta de valda kuberna upp relativt till den nuvarande kameravinkeln",
"action.move_down": "Flytta ner",
@ -811,5 +805,23 @@
"action.export_class_entity": "Export Java Entity",
"action.export_class_entity.desc": "Export the entity model as a Java class",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
"settings.seethrough_outline.desc": "Show outlines through objects",
"mode.edit": "Edit",
"mode.paint": "Paint",
"mode.display": "Display",
"mode.animate": "Animate",
"status_bar.recording_gif": "Recording GIF",
"status_bar.processing_gif": "Processing GIF",
"settings.backup_retain": "Backup Retain Duration",
"settings.backup_retain.desc": "Set how long Blockbench retains old backups in days",
"action.rotate_tool": "Rotate",
"action.rotate_tool.desc": "Tool to select and rotate elements",
"action.fill_tool": "Paint Bucket",
"action.fill_tool.desc": "Paint bucket to fill entire faces with one color",
"action.eraser": "Eraser",
"action.eraser.desc": "Eraser tool to replace colors on a texture with transparency",
"action.color_picker": "Color Picker",
"action.color_picker.desc": "Tool to pick the color of pixels on your texture",
"action.open_backup_folder": "Open Backup Folder",
"action.open_backup_folder.desc": "Opens the Blockbench backup folder"
}

View File

@ -348,14 +348,12 @@
"action.vertex_snap_mode.desc": "选择“顶点捕捉”将元素移动到所选位置或调整其大小",
"action.move_tool": "移动",
"action.move_tool.desc": "选择和移动元素的工具",
"action.resize_tool": "调整",
"action.resize_tool": "尺寸",
"action.resize_tool.desc": "选择和调整元素大小的工具",
"action.brush_tool": "笔刷",
"action.brush_tool.desc": "在模型表面或UV编辑器中绘制贴图的工具",
"action.vertex_snap_tool": "顶点捕捉",
"action.vertex_snap_tool.desc": "通过连接两个顶点将一个立方体移动到另一个立方体",
"action.display_mode_tool": "显示",
"action.display_mode_tool.desc": "对玩家手持物品时的模型位置调整",
"action.swap_tools": "交换工具",
"action.swap_tools.desc": "在移动和调整工具之间交换",
"action.project_window": "项目...",
@ -516,7 +514,7 @@
"action.reload.desc": "重载 Blockbench这将删除所有未保存的进度",
"menu.file": "文件",
"menu.edit": "编辑",
"menu.transform": "调整",
"menu.transform": "尺寸",
"menu.filter": "插件目录",
"menu.display": "物品显示",
"menu.view": "视图",
@ -650,8 +648,6 @@
"dialog.update.update": "更新",
"action.brush_mode.brush": "笔刷",
"action.brush_mode.noise": "像素点",
"action.brush_mode.eraser": "橡皮擦",
"action.brush_mode.fill": "油漆桶",
"action.vertex_snap_mode.move": "移动",
"action.vertex_snap_mode.scale": "规模",
"action.open_model_folder": "打开模型文件夹",
@ -732,8 +728,6 @@
"category.uv": "UV",
"status_bar.saved": "模型已保存",
"status_bar.unsaved": "有未保存的更改",
"action.animation_mode_tool": "动画",
"action.animation_mode_tool.desc": "为模型定义自定义动画",
"action.move_up": "上移",
"action.move_up.desc": "相对于当前摄像机角度向上移动选定的立方体",
"action.move_down": "下移",
@ -811,5 +805,23 @@
"action.export_class_entity": "导出java实体",
"action.export_class_entity.desc": "作为java class导出模型",
"settings.seethrough_outline": "X-Ray Outlines",
"settings.seethrough_outline.desc": "Show outlines through objects"
"settings.seethrough_outline.desc": "Show outlines through objects",
"mode.edit": "Edit",
"mode.paint": "Paint",
"mode.display": "Display",
"mode.animate": "Animate",
"status_bar.recording_gif": "Recording GIF",
"status_bar.processing_gif": "Processing GIF",
"settings.backup_retain": "Backup Retain Duration",
"settings.backup_retain.desc": "Set how long Blockbench retains old backups in days",
"action.rotate_tool": "Rotate",
"action.rotate_tool.desc": "Tool to select and rotate elements",
"action.fill_tool": "Paint Bucket",
"action.fill_tool.desc": "Paint bucket to fill entire faces with one color",
"action.eraser": "Eraser",
"action.eraser.desc": "Eraser tool to replace colors on a texture with transparency",
"action.color_picker": "Color Picker",
"action.color_picker.desc": "Tool to pick the color of pixels on your texture",
"action.open_backup_folder": "Open Backup Folder",
"action.open_backup_folder.desc": "Opens the Blockbench backup folder"
}

94045
lib/three.js

File diff suppressed because one or more lines are too long

66
lib/three_custom.js Normal file
View File

@ -0,0 +1,66 @@
THREE.BoxGeometry.prototype.from = function(arr) {
/*
vertices[0] //south east up
vertices[1] //north east up
vertices[2] //south east down
vertices[3] //north east down
vertices[4] //north west up
vertices[5] //south west up
vertices[6] //north west down
vertices[7] //south west down
*/
//X
this.vertices[4].setX(arr[0])
this.vertices[5].setX(arr[0])
this.vertices[6].setX(arr[0])
this.vertices[7].setX(arr[0])
//Y
this.vertices[2].setY(arr[1])
this.vertices[3].setY(arr[1])
this.vertices[6].setY(arr[1])
this.vertices[7].setY(arr[1])
//Z
this.vertices[1].setZ(arr[2])
this.vertices[3].setZ(arr[2])
this.vertices[4].setZ(arr[2])
this.vertices[6].setZ(arr[2])
this.verticesNeedUpdate = true
}
THREE.BoxGeometry.prototype.to = function(arr) {
//X
this.vertices[0].setX(arr[0])
this.vertices[1].setX(arr[0])
this.vertices[2].setX(arr[0])
this.vertices[3].setX(arr[0])
//Y
this.vertices[0].setY(arr[1])
this.vertices[1].setY(arr[1])
this.vertices[4].setY(arr[1])
this.vertices[5].setY(arr[1])
//Z
this.vertices[0].setZ(arr[2])
this.vertices[2].setZ(arr[2])
this.vertices[5].setZ(arr[2])
this.vertices[7].setZ(arr[2])
this.verticesNeedUpdate = true
}
Object.assign( THREE.Euler.prototype, {
setFromDegreeArray: function ( arr, invert ) {
this._x = Math.degToRad(arr[0]) * (invert ? -1 : 1);
this._y = Math.degToRad(arr[1]) * (invert ? -1 : 1);
this._z = Math.degToRad(arr[2]) * (invert ? -1 : 1);
this.onChangeCallback();
return this;
}
})
//22138 Init Log
//17264 ProgramLog message
//22319 WebGL Error
//AxesHelper
//44584 Grid Color { color: color1 }

View File

@ -1,7 +1,7 @@
{
"name": "Blockbench",
"description": "Minecraft Block Model Editor",
"version": "2.2.2",
"version": "2.3.0",
"license": "MIT",
"author": {
"name": "JannisX11",