This commit is contained in:
JannisX11 2020-04-25 20:25:07 +02:00
parent b859ba6533
commit 47c38b2036
66 changed files with 3841 additions and 2611 deletions

View File

@ -19,7 +19,7 @@ jobs:
- electron-builder -w --ia32 --publish=always -c.productName='Blockbench_32bit'
deploy:
provider: releases
api_key: GH_TOKEN
api_key: $GH_TOKEN
skip_cleanup: true
file: dist/win-unpacked/resources/app.asar

15
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "dev",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

66
assets/logo_cutout.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

@ -32,7 +32,7 @@
background-color: var(--color-ui);
color: inherit;
border: none;
box-shadow: 0 0px 40px #000;
box-shadow: 0 0px 40px rgba(0, 0, 0, 0.5);
left: unset;
right: unset;
bottom: unset;
@ -69,6 +69,7 @@
margin-top: 4px;
margin-bottom: 4px;
height: auto;
clear: both;
}
.dialog_bar::after {
content: "";
@ -89,6 +90,12 @@
.dialog_bar input[type=checkbox] {
padding: 0 4px;
}
.dialog_vector_group {
display: flex;
}
.dialog_vector_group > input {
min-width: 30px;
}
.tab_bar {
height: 30px;
display: flex;
@ -173,6 +180,9 @@
}
/*Settings Dialog*/
dialog#settings {
width: min(100%, 600px);
}
#settings_tab_bar {
margin: -24px;
margin-bottom: 0;
@ -254,7 +264,7 @@
padding-left: 4px;
border: 1px solid var(--color-border);
}
#settingslist input[type=text] {
#settingslist input[type=text], #settingslist input[type=password] {
padding: 10px;
margin-left: 5px;
}
@ -265,14 +275,22 @@
#settingslist div.bar_select select {
width: 100%;
}
#settingslist li li i {
#settingslist li li .setting_icon i {
font-size: 26pt;
width: 34px;
margin-top: -6px;
}
#settingslist li li:hover i {
#settingslist li li:hover .setting_icon i {
color: var(--color-light);
}
.password_toggle {
display: inline-block;
margin-left: 4px;
margin-top: -1px;
width: 24px;
text-align: center;
vertical-align: text-bottom;
}
/*Keybinds*/
#keybindlist {
@ -356,6 +374,9 @@
background-color: var(--color-back) !important;
height: 56px;
}
#css_editor {
border: 1px solid var(--color-border);
}
/*About*/
#about_page_title {
@ -695,6 +716,47 @@
top: 30px;
}
/*Toolbar Dialog*/
#bar_item_list {
max-height: 400px;
margin-bottom: 20px;
overflow-y: scroll;
min-height: 80px;
border: 1px solid var(--color-border);
border-right: none;
}
#bar_item_list li {
padding: 4px;
}
#bar_item_list li:hover {
color: var(--color-light);
}
#bar_item_list li div.icon_wrapper {
display: inline-block;
height: 26px;
vertical-align: text-top;
}
#bar_item_list li:not(:hover) div.icon_wrapper.add, #bar_item_list li:hover div.icon_wrapper.normal {
display: none;
}
#bar_items_current {
background-color: var(--color-back);
overflow: hidden;
height: auto;
min-height: 34px;
border: 1px solid var(--color-border);
}
#bar_items_current li {
min-width: 20px;
}
#bar_items_current li .toolbar_separator {
width: 12px;
background-color: var(--color-button);
border: 1px solid var(--color-border);
}
/*Action Control*/
#action_selector {
position: absolute;
@ -707,7 +769,7 @@
top: 200px;
width: 360px;
height: 42px;
box-shadow: 0 0 5px black;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
}
#action_selector > input {
width: 100%;
@ -727,7 +789,7 @@
color: var(--color-text);
width: 340px;
margin-left: 8px;
box-shadow: 0 0 5px black;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
}
#action_selector > div > ul {
background-color: var(--color-bright_ui);

View File

@ -99,7 +99,7 @@
background-color: var(--color-dark) !important;
}
/*General*/
/*UI Elements*/
canvas.preview {
background-repeat: no-repeat;
}
@ -139,10 +139,16 @@
.list {
background-color: var(--color-back);
height: calc(100% - 86px);
width: calc(100% - 2px);
width: 100%;
overflow-y: scroll;
flex-grow: 1;
}
#left_bar .list {
width: calc(100% - 2px);
}
.list::-webkit-scrollbar-track {
background: var(--color-back);
}
ul.list_style li {
list-style: initial;
margin-left: 20px;
@ -167,7 +173,7 @@
padding: 0 12px;
background-color: var(--color-bright_ui);
color: var(--color-accent_text);
box-shadow: 0 0 2px black;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);;
text-align: center;
overflow-wrap: break-word;
cursor: default;
@ -190,7 +196,7 @@
max-width: 200px;
background-color: var(--color-bright_ui);
color: var(--color-accent_text);
box-shadow: 0 0 2px black;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);;
text-align: center;
cursor: default;
top: 40px;
@ -263,45 +269,6 @@
@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
/*Menu Bar*/
ul#menu_bar {
height: 100%;
}
li.menu_bar_point {
font-size: 17px;
padding: 0 8px;
padding-top: 2px;
display: inline-block;
height: 29px;
font-weight: normal;
}
li.menu_bar_point.opened {
color: var(--color-light);
background: var(--color-accent);
}
li.menu_bar_point:hover {
color: var(--color-light);
}
#mode_selector {
float: right;
font-size: 1.1em;
height: 30px;
}
#mode_selector li {
display: inline-block;
height: 30px;
margin: 0 5px;
overflow: hidden;
padding-top: 2px;
font-size: 18px;
}
#mode_selector li:hover {
color: var(--color-light);
}
#mode_selector li.selected {
border-bottom: 3px solid var(--color-accent);
}
/*Actions*/
.toolbar {
@ -312,7 +279,7 @@
float: none;
}
.toolbar.narrow, .toolbar_wrapper.narrow > .toolbar {
width: auto;
width: fit-content;
}
.toolbar_wrapper.narrow .toolbar .content {
float: left;
@ -328,14 +295,10 @@
.toolbar.vertical .toolbar_menu {
height: 24px;
padding: 0;
}
.toolbar_wrapper > .toolbar.vertical .tool .tooltip {
}
.toolbar > .tool.toolbar_menu {
float: right;
width: 14px;
margin-left: -4px;
}
.toolbar > .tool.toolbar_menu > i {
width: 16px;
@ -478,7 +441,7 @@
}
.contextMenu li.parent::before {
content: "\f105";
display: inline-block;
display: block;
font-family: 'Font Awesome 5 Free';
font-weight: 900;
font-size: inherit;
@ -520,248 +483,4 @@
padding: 0;
background-color: var(--color-text);
}
@media (max-device-width: 480px) {
.contextMenu li.focused > .contextMenu.sub {
}
}
/*Start Screen*/
#start_screen {
flex-grow: 1;
}
#start_screen h3 {
margin: 0;
}
#start_screen .bar.next_to_title {
margin-top: -40px;
margin-right: -12px;
position: relative;
float: right;
}
#start_screen .recent_project {
margin: 2px 0;
display: flex;
}
#start_screen .recent_project .icon_wrapper {
flex-shrink: 0;
}
#start_screen .recent_project_name {
font-size: 1.1em;
overflow-x: hidden;
flex-shrink: 1;
flex-grow: 1;
margin: 0 4px;
}
#start_screen .recent_project_date {
flex-shrink: 0;
}
span.recent_project_date:before {
content: "";
display: block;
position: absolute;
width: 16px;
height: 26px;
margin-left: -20px;
background: linear-gradient(90deg, transparent, var(--color-ui));
}
#start_screen .recent_project.thumbnail {
width: 242px;
height: 150px;
width: 168px;
height: 128px;
position: relative;
float: left;
background-color: var(--color-back);
margin: 1px;
background-size: 150px;
background-repeat: no-repeat;
}
#start_screen .recent_project.thumbnail:hover {
background-color: var(--color-ui);
}
#start_screen .recent_project.thumbnail .recent_project_name {
font-size: 1em;
overflow-x: hidden;
flex-shrink: 1;
flex-grow: 1;
height: 24px;
right: 6px;
left: 6px;
bottom: 0;
position: absolute;
}
#start_screen > content {
display: block;
margin-top: 40px;
max-width: 900px;
height: auto;
max-height: calc(100% - 80px);
margin-left: auto;
margin-right: auto;
background-color: var(--color-ui);
overflow-y: scroll;
image-rendering: auto;
}
#start_screen > content > section {
width: 100%;
height: auto;
display: flex;
position: relative;
}
#start_screen section left, #start_screen section right {
display: block;
padding: 24px;
max-height: 600px;
}
#start_screen section right > ul {
max-height: 465px;
overflow-y: auto;
padding-right: 5px;
}
#start_screen left {
flex-grow: 0;
background-size: cover;
}
#start_screen left i.graphic_icon {
font-size: 40px;
width: 12px;
margin-top: 6px;
}
#start_screen right {
flex-grow: 1;
}
#start_screen i.start_screen_close_button {
position: absolute;
top: 8px;
right: 8px;
}
#start_screen i.start_screen_close_button:not(:hover) {
opacity: 0.8;
}
@media (max-device-width: 480px) {
#start_screen {
width: calc(100% - 40px);
}
#start_screen > content {
margin-top: 0px;
margin-top: 0px;
margin-left: 0;
margin-right: 0;
max-height: 100%;
}
#start_screen > content > section {
display: block;
}
#start_screen content section right {
width: 100% !important;
float: none;
}
#start_screen content section left {
width: 100% !important;
float: none;
}
#start_screen content section left {
width: 100% !important;
float: none;
}
}
#start-files li:hover {
color: var(--color-light);
}
#start-files left {
width: 36%;
}
#start-files right {
width: 64%;
border-left: 1px solid var(--color-border);
}
#start_screen left > ul {
margin-bottom: 16px;
}
#start_screen right i {
vertical-align: sub;
}
#start-files left li {
padding: 4px 0;
}
#start-files left span.icon_wrapper {
height: 22px;
}
#start-files left i {
font-size: 20pt;
height: 22px;
margin: 2px 12px 0px 0;
display: inline-block;
}
/*Toolbar Dialog*/
#bar_item_list {
max-height: 400px;
margin-bottom: 20px;
overflow-y: scroll;
min-height: 80px;
border: 1px solid var(--color-border);
border-right: none;
}
#bar_item_list li {
padding: 4px;
}
#bar_item_list li:hover {
color: var(--color-light);
}
#bar_item_list li div.icon_wrapper {
display: inline-block;
height: 26px;
vertical-align: text-top;
}
#bar_item_list li:not(:hover) div.icon_wrapper.add, #bar_item_list li:hover div.icon_wrapper.normal {
display: none;
}
#bar_items_current {
background-color: var(--color-back);
overflow: hidden;
height: auto;
min-height: 34px;
border: 1px solid var(--color-border);
}
#bar_items_current li {
min-width: 20px;
}
#bar_items_current li .toolbar_separator {
width: 12px;
background-color: var(--color-button);
border: 1px solid var(--color-border);
}
/*Status Bar*/
#status_bar {
position: relative;
display: block;
background: var(--color-back);
}
#status_bar > div {
float: left;
padding-left: 6px;
padding-right: 6px;
}
#status_bar > div#status_fps {
float: right;
}
#status_bar > div#status_saved {
padding-top: 2px;
}
#status_bar #status_progress {
position: absolute;
height: 4px;
background: var(--color-accent);
bottom: 0;
left: 0;
}

View File

@ -1,307 +1,4 @@
/*Layout*/
#page_wrapper {
display: grid;
grid-template-columns: 332px auto 314px;
grid-template-rows: 30px minmax(200px, 5000px) 26px;
grid-template-areas:
"left_bar toolbar toolbar"
"left_bar center right_bar"
"left_bar status_bar right_bar";
height: calc(100% - 26px);
width: 100%;
border: 2px solid var(--color-border);
border-top: none;
}
#loading_error_message {
height: 100%;
width: 100%;
background-color: var(--color-dark);
border: 2px solid var(--color-accent);
text-align: center;
padding-top: 160px;
position: absolute;
z-index: 250;
}
.sidebar {
background-color: var(--color-ui);;
display: flex;
flex-direction: column;
}
#left_bar {
grid-area: left_bar;
}
#right_bar {
grid-area: right_bar;
}
.panel.grow {
display: flex;
flex-direction: column;
flex-grow: 1;
min-height: 133px;
}
.panel:not(:last-child) {
padding-bottom: 8px;
}
h3.panel_handle {
width: 100%;
height: auto;
padding: 6px 12px;
background: var(--color-ui);
margin: 0;
}
.panel p {
margin-left: 12px;
}
body > h3.panel_handle {
box-shadow: 0 0 16px black;
width: auto;
}
#center {
grid-area: center;
background-color: var(--color-dark);
overflow: hidden;
min-width: 100px;
display: flex;
flex-direction: column;
}
div#center > div {
max-height: 100%;
}
div#preview {
flex-grow: 1;
background-repeat: no-repeat;
background-size: 1000px;
position: relative;
}
#status_bar {
grid-area: status_bar;
}
.single_canvas_wrapper {
height: 100%;
width: 100%;
overflow: hidden;
position: absolute;
cursor: inherit;
}
.quad_canvas_wrapper {
height: 50%;
width: 50%;
position: absolute;
cursor: inherit;
}
.quad_canvas_wrapper.qcw_x {
border-right: 2px solid var(--color-grid);
}
.quad_canvas_wrapper.qcw_y {
border-bottom: 2px solid var(--color-grid);
}
.quad_canvas_wrapper:not(.qcw_x) {
right: 0;
}
.quad_canvas_wrapper:not(.qcw_y) {
bottom: 0;
}
.resizer {
position: absolute !important;
z-index: 12;
}
.resizer.vertical { /* | */
cursor: ew-resize;
width: 6px;
}
.resizer.horizontal { /* __ */
cursor: ns-resize;
height: 6px;
}
.resizer.disabled {
pointer-events: none;
}
/*Head Bars*/
#main_toolbar {
background-color: var(--color-ui);;
grid-area: toolbar;
overflow: hidden;
white-space: nowrap;
display: flex;
}
#main_toolbar > * {
display: inline-block;
}
.toolbar_wrapper.tool_options {
flex-grow: 1;
}
header {
background-color: var(--color-border);;
grid-area: titlebar;
overflow: hidden;
display: flex;
white-space: nowrap;
height: 26px;
}
header > * {
display: inline-block;
height: 100%;
}
header ::-webkit-scrollbar {
height: 0;
}
div#title {
width: auto;
padding-right: 8px;
padding-left: 6px;
margin-left: 4px;
font-size: 1.2em;
font-weight: normal;
font-family: montserrat, arial, sans-serif;
color: var(--color-light);
vertical-align: top;
min-width: 62px;
margin-top: -0.6px;
}
div#title i {
display: none;
padding-top: 1px;
margin-left: 6px;
}
#title span {
min-width: 114px;
display: inline-block;
}
@media (max-width:950px) {
#title span {
display: none;
}
div#title i {
display: block;
}
}
.app-drag-region {
-webkit-app-region: drag;
}
div#header_free_bar.app-drag-region {
flex-grow: 1;
}
div#header_free_bar.app-drag-region.resize_space {
margin-top: 4px;
height: calc(100% - 4px);
}
#web_download_button {
margin-left: auto;
height: 100%;
padding: 0;
}
#web_download_button a {
text-decoration: none !important;
height: 100%;
width: 100%;
padding: 0 12px;
}
#web_download_button:hover a {
color: var(--color-accent_text);
}
#windows_window_menu {
margin-left: auto;
}
#windows_window_menu li {
float: left;
display: inline-block;
width: 42px;
height: 100%;
text-align: center;
}
#windows_window_menu li:hover {
color: var(--color-light);
background-color: var(--color-selected);
}
#windows_window_menu li.wwm_r:hover {
background-color: var(--color-close);
}
#windows_window_menu li i:not(.material-icons) {
font-size: 10pt;
}
#windows_window_menu i.material-icons {
vertical-align: bottom;
}
#mac_window_menu {
width: 68px;
}
/*Mobile*/
@media (max-device-width: 480px) {
#page_wrapper {
display: grid;
grid-template-rows: auto minmax(200px, 5000px) 26px;
grid-template-areas:
"toolbar"
"center"
"status_bar";
grid-template-columns: auto !important;
border: none;
}
#main_toolbar {
display: block;
}
#main_toolbar > * {
display: block;
}
#main_toolbar > div.tools {
position: absolute;
z-index: 2;
bottom: 26px;
right: 0px;
}
#main_toolbar > div.mobile_side {
position: absolute;
z-index: 2;
top: 86px;
right: 0px;
}
#main_toolbar > div.tool_options {
background-color: var(--color-back);
}
.resizer.vertical {
display: none;
}
.sidebar {
overflow-y: auto;
}
#left_bar, #right_bar {
width: calc(100% - 40px);
display: none;
}
/*Left*/
#page_wrapper.show_left {
grid-template-areas: "toolbar" "left_bar" "status_bar";
}
#page_wrapper.show_left #center {
display: none;
}
#page_wrapper.show_left #left_bar {
display: flex;
}
/*Right*/
#page_wrapper.show_right {
grid-template-areas: "toolbar" "right_bar" "status_bar";
}
#page_wrapper.show_right #center {
display: none;
}
#page_wrapper.show_right #right_bar {
display: flex;
}
}
/*Display*/
.tabs_small input[type="radio"]:checked+label {
@ -317,7 +14,6 @@
text-align: center;
font-size: 0.9em;
flex-grow: 1;
float: left;
overflow: hidden;
}
#color .tabs_small label {
@ -347,6 +43,7 @@
.bar.slider_input_combo {
position: relative;
display: flex;
margin-right: 2px;
}
.bar.slider_input_combo input.tool[type="range"] {
float: none;
@ -406,6 +103,9 @@
text-align: center;
width: 21px;
}
.outliner_node .outliner_object i.icon_off {
opacity: 0.56;
}
.outliner_opener_placeholder {
width: 18px;
height: 14px;
@ -416,6 +116,9 @@
padding: 2px;
box-sizing: border-box;
}
.outliner_object:active {
background-color: var(--color-ui);
}
.outliner_object.selected {
background-color: var(--color-selected);
}
@ -436,6 +139,19 @@
position: absolute;
bottom: 0px;
}
#cubes_list ul {
position: relative;
}
#cubes_list .outliner_line_guide {
position: absolute;
top: -4px;
bottom: 4px;
width: 4px;
margin-left: 10px;
border-left: 2px solid var(--color-text);
opacity: 0.2;
pointer-events: none;
}
.drag_hover[order]::before {
content: '';
width: calc(100% - 12px);
@ -482,10 +198,10 @@
font-size: 15px;
float: right;
}
#cubes_list .outliner_object i.icon-open-state {
i.icon-open-state {
opacity: 0.7;
}
#cubes_list .outliner_object i.icon-open-state:hover {
i.icon-open-state:hover {
opacity: 1;
}
@ -735,14 +451,28 @@
#timeline_playhead {
position: absolute;
pointer-events: none;
z-index: 3;
height: 26px;
width: 18px;
top: 0;
margin-left: -8px;
border: 2px solid var(--color-accent);
border-top-width: 5px;
background-color: rgba(0, 0, 0, 0.2);
z-index: 3;
border-right: 9px solid transparent;
border-left: 9px solid transparent;
border-top: 12px solid var(--color-accent);
border-radius: 2px;
}
#timeline_playhead::after {
content: "";
display: block;
position: absolute;
width: 2px;
background-color: var(--color-accent);
pointer-events: none;
margin-left: -1px;
margin-top: -2px;
height: 17px;
}
#timeline_playhead_line {
content: "";
@ -754,6 +484,21 @@
background-color: var(--color-accent);
pointer-events: none;
}
#timeline_endbracket {
position: absolute;
z-index: 3;
cursor: pointer;
height: 26px;
width: 8px;
top: 0;
margin-left: -7px;
border: 1px solid var(--color-accent);
border-left-width: 0;
border-right-width: 2px;
}
#timeline_body .keyframe {
position: absolute;
margin-left: -6px;
@ -797,26 +542,53 @@
padding: 3px;
padding-left: 8px;
overflow: hidden;
background-color: var(--color-back);
z-index: 4;
}
#timeline_time_wrapper {
height: 100%;
position: relative;
background-color: var(--color-button);
overflow: hidden;
background-color: var(--color-back);
}
#timeline_time {
height: 100%;
position: relative;
margin-left: 8px;
border-bottom: 1px solid var(--color-selected);
}
.timeline_timecode {
border-left: 1px solid var(--color-border);
padding-left: 4px;
padding-top: 2px;
height: 100%;
position: absolute;
pointer-events: none;
}
.timeline_timecode > span {
display: block;
margin-top: -4px;
font-size: 0.9em;
margin-left: -6px;
}
.timeline_timecode > .substeps {
width: 100%;
height: 8px;
position: absolute;
bottom: 0;
left: 0;
display: flex;
}
.timeline_timecode > .substeps > div {
border-left: 1px solid var(--color-text);
height: 4px;
flex-grow: 1;
margin-top: 4px;
opacity: 0.3;
}
.timeline_timecode > .substeps > div:first-child {
height: 100%;
margin-top: 0;
opacity: 0.48;
}
#timeline_body_inner {
@ -840,6 +612,7 @@
height: calc(100% + 1px);
background-color: var(--color-ui);
border-right: 1px solid var(--color-border);
border-left: 2px solid transparent;
box-shadow: 1px 8px 10px 0 #00000038;
z-index: 5;
}
@ -849,6 +622,9 @@
#timeline_body li > .animator_channel_bar .channel_head {
padding-left: 16px;
}
.animator.selected .channel_head {
border-left-color: var(--color-accent);
}
.channel_head .text_button {
width: 26px;
height: 24px;
@ -862,12 +638,6 @@
.animator_channel_bar .channel_head .text_button .channel_mute {
font-size: 11pt;
}
.animator.selected .animator_head_bar {
background-color: var(--color-selected);
}
.animator.selected .animator_head_bar .channel_head {
background-color: var(--color-selected);
}
.channel_head span {
flex-grow: 1;
flex-shrink: 1;
@ -895,6 +665,9 @@
.UVEditor {
position: relative;
}
dialog .UVEditor {
z-index: 20;
}
.UVEditor > .toolbar {
margin-top: 3px;
}
@ -909,7 +682,11 @@
margin-left: -8px;
margin-right: -8px;
}
.uv_headline.selected {
#uv_dialog_all .UVEditor.selected {
border-color: var(--color-accent);
z-index: 21;
}
.UVEditor.selected .uv_headline {
background-color: var(--color-button);
}
.uv_headline .tool {
@ -1089,7 +866,7 @@
color: var(--color-accent_text);
}
/*Edit Session UI*/
/*Chat*/
#chat {
z-index: 16;
min-height: 180px;
@ -1149,9 +926,6 @@
}
/*Color*/
.panel#color {
}
#color_panel_head {
display: flex;
width: 100%;
@ -1200,33 +974,28 @@
width: 36px;
}
#palette_list {
padding: 2px 1px;
padding: 2px;
min-height: 160px;
max-height: 232px;
}
#palette_list .color {
display: inline-block;
float: left;
width: 30px;
height: 30px;
padding: 3px;
width: 25px;
height: 25px;
vertical-align: top;
}
#palette_list .color:hover {
background-color: var(--color-selected);
}
#palette_list .color.selected {
padding: 1px;
}
#palette_list .color .color_inner {
width: 24px;
height: 24px;
border-radius: 50%;
#palette_list .color.selected {
padding: 3px;
}
#palette_list .color.selected .color_inner {
border-radius: 4px;
transition: border-radius 20ms ease;
width: 28px;
height: 28px;
#palette_list .color.contrast {
background-color: var(--color-text);
}
#palette_list .color .color_inner {
width: 100%;
height: 100%;
}
.panel#color input.sp-input {
width: calc(100% - 40px);

View File

@ -22,7 +22,7 @@
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: var(--color-ui);
}
@ -138,7 +138,6 @@
[class^="icon-"]:not(.fa), [class*=" icon-"]:not(.fa) {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'icomoon' !important;
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
@ -147,7 +146,6 @@
font-size: 1.4em;
max-width: 24px;
Better Font Rendering ===========
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@ -399,7 +397,7 @@
appearance: none;
border: none;
background: transparent;
color: var(--color-text)
color: var(--color-text);
font-size: 1em;
font-family: inherit;
outline: none;
@ -419,6 +417,7 @@
padding-right: 16px;
padding-left: 16px;
font-weight: normal;
cursor: pointer;
}
button.disabled {
opacity: 0.5;
@ -503,13 +502,16 @@
right: 6px;
top: 3px;
}
input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-inner-spin-button, {
input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-inner-spin-button {
-webkit-appeareance: none;
}
input[type=range] {
background-color: var(--color-back);
height: 30px;
}
input[type=password] {
font-size: 1.2em;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;

View File

@ -150,10 +150,6 @@ License: MIT
height: 28px;
}
.sp-container:not(.sp-alpha-enabled) .sp-top {
/*margin-bottom: -20px;*/
}
/* Don't allow text selection */
.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-clear, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button {
-webkit-user-select:none;
@ -444,12 +440,6 @@ See http://bgrins.github.io/spectrum/themes/ for instructions.
/* Buttons: http://hellohappy.org/css3-buttons/ */
.sp-container button {
}
.sp-container button:hover {
}
.sp-cancel {
font-size: 11px;
margin:0;

561
css/window.css Normal file
View File

@ -0,0 +1,561 @@
/*Layout*/
#page_wrapper {
display: grid;
grid-template-columns: 332px auto 314px;
grid-template-rows: 30px minmax(200px, 5000px) 26px;
grid-template-areas:
"left_bar toolbar toolbar"
"left_bar center right_bar"
"left_bar status_bar right_bar";
height: calc(100% - 26px);
width: 100%;
border: 2px solid var(--color-frame);
border-top: none;
opacity: 1;
transition: opacity 0.1s linear;
}
#page_wrapper.hidden {
opacity: 0;
}
body {
background-image: url('../assets/logo_cutout.svg');
background-repeat: no-repeat;
background-size: 128px;
background-position: center;
}
#loading_error_message {
height: 100%;
width: 100%;
background-color: var(--color-dark);
border: 2px solid var(--color-accent);
text-align: center;
padding-top: 160px;
position: absolute;
z-index: 250;
}
.sidebar {
background-color: var(--color-ui);;
display: flex;
flex-direction: column;
}
#left_bar {
grid-area: left_bar;
}
#right_bar {
grid-area: right_bar;
}
.panel.grow {
display: flex;
flex-direction: column;
flex-grow: 1;
min-height: 133px;
}
.panel:not(:last-child) {
padding-bottom: 8px;
}
h3.panel_handle {
width: 100%;
height: auto;
padding: 6px 12px;
background: var(--color-ui);
margin: 0;
}
.panel p {
margin-left: 12px;
}
body > h3.panel_handle {
box-shadow: 0 0 16px black;
width: auto;
}
#center {
grid-area: center;
background-color: var(--color-dark);
overflow: hidden;
min-width: 100px;
display: flex;
flex-direction: column;
}
div#center > div {
max-height: 100%;
}
div#preview {
flex-grow: 1;
background-repeat: no-repeat;
background-size: 1000px;
position: relative;
}
#status_bar {
grid-area: status_bar;
}
.single_canvas_wrapper {
height: 100%;
width: 100%;
overflow: hidden;
position: absolute;
cursor: inherit;
}
.quad_canvas_wrapper {
height: 50%;
width: 50%;
position: absolute;
cursor: inherit;
}
.quad_canvas_wrapper.qcw_x {
border-right: 2px solid var(--color-grid);
}
.quad_canvas_wrapper.qcw_y {
border-bottom: 2px solid var(--color-grid);
}
.quad_canvas_wrapper:not(.qcw_x) {
right: 0;
}
.quad_canvas_wrapper:not(.qcw_y) {
bottom: 0;
}
.resizer {
position: absolute !important;
z-index: 12;
}
.resizer.vertical { /* | */
cursor: ew-resize;
width: 6px;
margin-left: -4px;
}
.resizer.horizontal { /* __ */
cursor: ns-resize;
height: 6px;
margin-top: -4px;
}
.resizer.disabled {
pointer-events: none;
}
/*
.resizer:hover, .resizer.ui-draggable-dragging {
background-color: var(--color-accent);
opacity: 0.2;
}*/
/*Head Bars*/
#main_toolbar {
background-color: var(--color-ui);;
grid-area: toolbar;
overflow: hidden;
white-space: nowrap;
display: flex;
}
#main_toolbar > * {
display: inline-block;
}
.toolbar_wrapper.tool_options {
flex-grow: 1;
}
header {
background-color: var(--color-frame);
grid-area: titlebar;
overflow: hidden;
display: flex;
white-space: nowrap;
height: 26px;
}
header > * {
display: inline-block;
height: 100%;
}
header ::-webkit-scrollbar {
height: 0;
}
div#title {
width: auto;
padding-right: 8px;
padding-left: 6px;
margin-left: 4px;
font-size: 1.2em;
font-weight: normal;
font-family: montserrat, arial, sans-serif;
color: var(--color-light);
vertical-align: top;
min-width: 62px;
margin-top: -0.6px;
}
div#title i {
display: none;
padding-top: 1px;
margin-left: 6px;
}
#title span {
min-width: 114px;
display: inline-block;
}
@media (max-width:950px) {
#title span {
display: none;
}
div#title i {
display: block;
}
}
.app-drag-region {
-webkit-app-region: drag;
}
div#header_free_bar.app-drag-region {
flex-grow: 1;
}
div#header_free_bar.app-drag-region.resize_space {
margin-top: 4px;
height: calc(100% - 4px);
}
#web_download_button {
margin-left: auto;
height: 100%;
padding: 0;
}
#web_download_button a {
text-decoration: none !important;
height: 100%;
width: 100%;
padding: 0 12px;
}
#web_download_button:hover a {
color: var(--color-accent_text);
}
#windows_window_menu {
margin-left: auto;
}
#windows_window_menu li {
display: inline-block;
width: 42px;
height: 100%;
text-align: center;
}
#windows_window_menu li:hover {
color: var(--color-light);
background-color: var(--color-selected);
}
#windows_window_menu li.wwm_r:hover {
background-color: var(--color-close);
}
#windows_window_menu li i:not(.material-icons) {
font-size: 10pt;
}
#windows_window_menu i.material-icons {
vertical-align: bottom;
}
#mac_window_menu {
width: 68px;
}
/*Mobile*/
@media (max-device-width: 480px) {
#page_wrapper {
display: grid;
grid-template-rows: auto minmax(200px, 5000px) 26px;
grid-template-areas:
"toolbar"
"center"
"status_bar";
grid-template-columns: auto !important;
border: none;
}
#main_toolbar {
display: block;
}
#main_toolbar > * {
display: block;
}
#main_toolbar > div.tools {
position: absolute;
z-index: 2;
bottom: 26px;
right: 0px;
}
#main_toolbar > div.mobile_side {
position: absolute;
z-index: 2;
top: 86px;
right: 0px;
}
#main_toolbar > div.tool_options {
background-color: var(--color-back);
}
.resizer.vertical {
display: none;
}
.sidebar {
overflow-y: auto;
}
#left_bar, #right_bar {
width: calc(100% - 40px);
display: none;
}
/*Left*/
#page_wrapper.show_left {
grid-template-areas: "toolbar" "left_bar" "status_bar";
}
#page_wrapper.show_left #center {
display: none;
}
#page_wrapper.show_left #left_bar {
display: flex;
}
/*Right*/
#page_wrapper.show_right {
grid-template-areas: "toolbar" "right_bar" "status_bar";
}
#page_wrapper.show_right #center {
display: none;
}
#page_wrapper.show_right #right_bar {
display: flex;
}
}
/*Menu Bar*/
ul#menu_bar {
height: 100%;
}
li.menu_bar_point {
font-size: 17px;
padding: 0 8px;
padding-top: 2px;
display: inline-block;
height: 29px;
font-weight: normal;
}
li.menu_bar_point.opened {
color: var(--color-light);
background: var(--color-accent);
}
li.menu_bar_point:hover {
color: var(--color-light);
}
#mode_selector {
float: right;
font-size: 1.1em;
height: 30px;
}
#mode_selector li {
display: inline-block;
height: 30px;
margin: 0 5px;
overflow: hidden;
padding-top: 2px;
font-size: 18px;
}
#mode_selector li:hover {
color: var(--color-light);
}
#mode_selector li.selected {
border-bottom: 3px solid var(--color-accent);
}
/*Start Screen*/
#start_screen {
flex-grow: 1;
}
#start_screen h3 {
margin: 0;
}
#start_screen .bar.next_to_title {
margin-top: -40px;
margin-right: -12px;
position: relative;
float: right;
}
#start_screen .recent_project {
margin: 2px 0;
display: flex;
}
#start_screen .recent_project .icon_wrapper {
flex-shrink: 0;
}
#start_screen .recent_project_name {
font-size: 1.1em;
overflow-x: hidden;
flex-shrink: 1;
flex-grow: 1;
margin: 0 4px;
}
#start_screen .recent_project_date {
flex-shrink: 0;
}
span.recent_project_date:before {
content: "";
display: block;
position: absolute;
width: 16px;
height: 26px;
margin-left: -20px;
background: linear-gradient(90deg, transparent, var(--color-ui));
}
#start_screen .recent_project.thumbnail {
width: 242px;
height: 150px;
width: 168px;
height: 128px;
position: relative;
float: left;
background-color: var(--color-back);
margin: 1px;
background-size: 150px;
background-repeat: no-repeat;
}
#start_screen .recent_project.thumbnail:hover {
background-color: var(--color-ui);
}
#start_screen .recent_project.thumbnail .recent_project_name {
font-size: 1em;
overflow-x: hidden;
flex-shrink: 1;
flex-grow: 1;
height: 24px;
right: 6px;
left: 6px;
bottom: 0;
position: absolute;
}
#start_screen > content {
display: block;
margin-top: 40px;
max-width: 1000px;
height: auto;
max-height: calc(100% - 80px);
margin-left: auto;
margin-right: auto;
background-color: var(--color-ui);
overflow-y: scroll;
image-rendering: auto;
}
#start_screen > content > section {
width: 100%;
height: auto;
display: flex;
position: relative;
}
#start_screen section left, #start_screen section right {
display: block;
padding: 24px;
max-height: 600px;
}
#start_screen section right > ul {
max-height: 465px;
overflow-y: auto;
padding-right: 5px;
}
#start_screen left {
flex-grow: 0;
background-size: cover;
}
#start_screen left i.graphic_icon {
font-size: 40px;
width: 12px;
margin-top: 6px;
}
#start_screen right {
flex-grow: 1;
}
#start_screen i.start_screen_close_button {
position: absolute;
top: 8px;
right: 8px;
}
#start_screen i.start_screen_close_button:not(:hover) {
opacity: 0.8;
}
@media (max-device-width: 480px) {
#start_screen {
width: calc(100% - 40px);
}
#start_screen > content {
margin-top: 0px;
margin-top: 0px;
margin-left: 0;
margin-right: 0;
max-height: 100%;
}
#start_screen > content > section {
display: block;
}
#start_screen content section right {
width: 100% !important;
float: none;
}
#start_screen content section left {
width: 100% !important;
float: none;
}
#start_screen content section left {
width: 100% !important;
float: none;
}
}
#start-files li:hover {
color: var(--color-light);
}
#start-files left {
width: 38%;
}
#start-files right {
border-left: 1px solid var(--color-border);
}
#start_screen left > ul {
margin-bottom: 16px;
}
#start_screen right i {
vertical-align: sub;
}
#start-files left li {
padding: 4px 0;
}
#start-files left span.icon_wrapper {
height: 22px;
}
#start-files left i {
font-size: 20pt;
height: 22px;
margin: 2px 12px 0px 0;
display: inline-block;
}
/*Status Bar*/
#status_bar {
position: relative;
display: block;
background: var(--color-back);
}
#status_bar > div {
float: left;
padding-left: 6px;
padding-right: 6px;
}
#status_bar > div#status_fps {
float: right;
}
#status_bar > div#status_saved {
padding-top: 2px;
}
#status_bar #status_progress {
position: absolute;
height: 4px;
background: var(--color-accent);
bottom: 0;
left: 0;
}

BIN
icon_full.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -2,7 +2,7 @@
<html lang="en">
<head>
<title>Blockbench</title>
<meta charset="utf-8" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#181a1f">
<meta name="robots" content="noindex">
@ -15,6 +15,7 @@
<link rel="stylesheet" href="css/prism.css">
<link rel="stylesheet" href="css/setup.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/window.css">
<link rel="stylesheet" href="css/panels.css">
<link rel="stylesheet" href="css/dialogs.css">
<style type="text/css" id="theme_css"></style>
@ -23,10 +24,11 @@
<script>
if (typeof module === 'object') {window.module = module; module = undefined;}//jQuery Fix
const isApp = typeof require !== 'undefined';
const appVersion = '3.4.2';
const appVersion = '3.5.0';
</script>
<div id="loading_error_message" style="display: none;">
<div>An error occurred while loading Blockbench</div>
<div id="loading_error_detail"></div>
<button onclick="isApp ? Blockbench.reload() : window.location.reload(true)" class="large" style="margin-right: auto; margin-left: auto;">Reload</button>
<button onclick="window.close()" class="large" style="margin-right: auto; margin-left: auto;">Quit</button>
</div>
@ -93,6 +95,7 @@
<script src="js/animations.js"></script>
<script src="js/plugin_loader.js"></script>
<script src="js/io/project.js"></script>
<script src="js/io/io.js"></script>
<script src="js/io/bbmodel.js"></script>
<script src="js/io/java_block.js"></script>
@ -128,7 +131,7 @@
<div class="progress_bar" id="update_bar">
<div class="progress_bar_inner"></div>
</div>
<div class="dialog_bar">
<div class="dialog_bar" hidden>
<button type="button" class="cancel_btn confirm_btn uc_btn tl" onclick="hideDialog()">dialog.close</button>
</div>
<div class="dialog_close_button" onclick="$('.dialog#'+open_dialog).find('.cancel_btn:not([disabled])').click()"><i class="material-icons">clear</i></div>
@ -158,10 +161,10 @@
<i v-else class="material-icons plugin_expand_icon">expand_more</i>
{{ plugin.title }}
</div>
<div class="button_bar" v-if="plugin.isInstallable() == true">
<div class="button_bar" v-if="plugin.installed || plugin.isInstallable() == true">
<button type="button" class="" v-on:click="plugin.uninstall()" v-if="plugin.installed"><i class="material-icons">delete</i><span class="tl">dialog.plugins.uninstall</span></button>
<button type="button" class="" v-on:click="plugin.download(true)" v-else><i class="material-icons">add</i><span class="tl">dialog.plugins.install</span></button>
<button type="button" class="local_only" v-on:click="plugin.reload()" v-if="plugin.installed && plugin.fromFile && isApp"><i class="material-icons">refresh</i><span class="tl">dialog.plugins.reload</span></button>
<button type="button" v-on:click="plugin.reload()" v-if="plugin.installed && plugin.isReloadable()"><i class="material-icons">refresh</i><span class="tl">dialog.plugins.reload</span></button>
</div>
<div class="button_bar tiny tl" v-else>{{ plugin.isInstallable() }}</div>
@ -174,8 +177,8 @@
<div class="no_plugin_message tl" v-if="plugin_search.length < 1 && showAll === true" id="plugin_available_empty">dialog.plugins.none_available</div>
</ul>
<div class="dialog_bar">
<button type="button" class="cancel_btn confirm_btn uc_btn tl" onclick="saveInstalledPlugins();hideDialog();">dialog.close</button>
<div class="dialog_bar" hidden>
<button type="button" class="cancel_btn confirm_btn uc_btn tl" onclick="hideDialog();">dialog.close</button>
</div>
<div class="dialog_close_button" onclick="$('.dialog#'+open_dialog).find('.cancel_btn:not([disabled])').click()"><i class="material-icons">clear</i></div>
</dialog>
@ -238,7 +241,7 @@
</ul>
<div class="dialog_bar">
<button type="button" class="cancel_btn confirm_btn uc_btn tl" onclick="saveInstalledPlugins();hideDialog();">dialog.close</button>
<button type="button" class="cancel_btn confirm_btn uc_btn tl" onclick="hideDialog();">dialog.close</button>
</div>
<div class="dialog_close_button" onclick="$('.dialog#'+open_dialog).find('.cancel_btn:not([disabled])').click()"><i class="material-icons">clear</i></div>
</dialog>
@ -295,46 +298,6 @@
<div class="dialog_close_button" onclick="$('.dialog#'+open_dialog).find('.cancel_btn:not([disabled])').click()"><i class="material-icons">clear</i></div>
</dialog>
<dialog class="dialog draggable paddinged" id="texture_edit">
<div class="dialog_handle tl" id="te_title">data.texture</div>
<div id="texture_menu_thumbnail"></div>
<div class="bar">
<div class="tool link_only" onclick="textures.selected.reopen()"><div class="tooltip tl">menu.texture.change</div><i class="material-icons">file_upload</i></div>
<div class="tool link_only" onclick="textures.selected.refresh(true)"><div class="tooltip tl">menu.texture.refresh</div><i class="material-icons">refresh</i></div>
<div class="tool link_only" onclick="textures.selected.openFolder()"><div class="tooltip tl">menu.texture.folder</div><i class="material-icons">folder</i></div>
<div class="tool" onclick="textures.selected.remove()"><div class="tooltip tl">generic.delete</div><i class="material-icons">delete</i></div>
</div>
<p class="multiline_text" id="te_path">path</p>
<div class="dialog_bar narrow bitmap_only"><label class="tl">generic.name</label> </div>
<div class="dialog_bar bitmap_only">
<input type="text" class="input_wide dark_bordered" id="te_name">
</div>
<div class="dialog_bar narrow"><label class="tl">dialog.texture.variable</label> </div>
<div class="dialog_bar">
<input type="text" class="input_wide dark_bordered" id="te_variable">
</div>
<div class="dialog_bar narrow"><label class="tl">dialog.texture.folder</label> </div>
<div class="dialog_bar">
<input type="text" class="input_wide dark_bordered" id="te_folder">
</div>
<div class="dialog_bar narrow"><label class="tl">dialog.texture.namespace</label> </div>
<div class="dialog_bar">
<input type="text" class="input_wide dark_bordered" id="te_namespace">
</div>
<div class="dialog_bar">
<button type="button" class="confirm_btn cancel_btn" onclick="saveTextureMenu()">Close</button>
</div>
<div class="dialog_close_button" onclick="$('.dialog#'+open_dialog).find('.cancel_btn:not([disabled])').click()"><i class="material-icons">clear</i></div>
</dialog>
<dialog class="dialog draggable paddinged" id="scaling">
<div class="dialog_handle tl">dialog.scale.title</div>
@ -511,6 +474,15 @@
<template v-if="setting.type === 'text'">
<input type="text" class="dark_bordered" style="width: 96%" v-model="setting.value" v-on:input="saveSettings()">
</template>
<template v-if="setting.type === 'password'">
<input :type="setting.hidden ? 'password' : 'text'" class="dark_bordered" style="width: calc(96% - 28px);" v-model="setting.value" v-on:input="saveSettings()">
<div class="password_toggle" @click="setting.hidden = !setting.hidden;">
<i class="fas fa-eye-slash" v-if="setting.hidden"></i>
<i class="fas fa-eye" v-else></i>
</div>
</template>
<template v-else-if="setting.type === 'select'">
<div class="bar_select">
<select v-model="setting.value">
@ -625,7 +597,7 @@
</p>
</div>
<div class="dialog_bar">
<div class="dialog_bar" hidden>
<button type="button" class="confirm_btn cancel_btn tl" onclick="Settings.save()">dialog.close</button>
</div>
<div class="dialog_close_button" onclick="$('.dialog#'+open_dialog).find('.cancel_btn:not([disabled])').click()"><i class="material-icons">clear</i></div>
@ -673,21 +645,6 @@
<div id="plugin_dialog_wrapper"></div>
<dialog id="action_selector" v-if="open">
<input type="text" v-model="search_input" autocomplete="off" autosave="off" autocorrect="off" spellcheck="off" autocapitalize="off">
<i class="material-icons" id="action_search_bar_icon">search</i>
<div>
<ul>
<li v-for="(item, i) in actions" v-on:click="ActionControl.click(item, $event)" v-bind:class="{selected: i === index}" v-on:mouseenter="index = i">
<div class="icon_wrapper normal" v-html="Blockbench.getIconNode(item.icon, item.color).outerHTML"></div>
<div class="name">{{ item.name }}</div>
<label>{{ item.keybind.label }}</label>
</li>
</ul>
<div class="small_text" v-if="actions[index]">{{ Pressing.alt ? actions[index].keybind.label : actions[index].description }}</div>
</div>
</dialog>
<header>
<ul id="mac_window_menu" hidden></ul>
<div id="title" class="app-drag-region">
@ -704,7 +661,22 @@
<button id="web_download_button" hidden><a class="tl" href="https://blockbench.net/downloads">web.download_app</a></button>
</header>
<div id="page_wrapper">
<div id="page_wrapper" class="hidden">
<dialog id="action_selector" v-if="open">
<input type="text" v-model="search_input" autocomplete="off" autosave="off" autocorrect="off" spellcheck="off" autocapitalize="off">
<i class="material-icons" id="action_search_bar_icon">search</i>
<div>
<ul>
<li v-for="(item, i) in actions" v-on:click="ActionControl.click(item, $event)" v-bind:class="{selected: i === index}" v-on:mouseenter="index = i">
<div class="icon_wrapper normal" v-html="Blockbench.getIconNode(item.icon, item.color).outerHTML"></div>
<div class="name">{{ item.name }}</div>
<label>{{ item.keybind.label }}</label>
</li>
</ul>
<div class="small_text" v-if="actions[index]">{{ Pressing.alt ? actions[index].keybind.label : actions[index].description }}</div>
</div>
</dialog>
<div id="blackout" onclick="$('.dialog#'+open_dialog).find('.cancel_btn:not([disabled])').click()"></div>
@ -973,7 +945,7 @@
<li
class="color" v-for="color in palette"
:title="color" :key="color"
:class="{selected: color == main_color}"
:class="{selected: color == main_color, contrast: isDarkColor(color)}"
@click="setColor(color)"
@mouseenter="hover_color = color"
@mouseleave="hover_color = ''"
@ -1017,12 +989,18 @@
<div id="timeline_corner" v-bind:style="{width: head_width+'px'}"></div>
<div id="timeline_time_wrapper">
<div id="timeline_time" v-bind:style="{width: (size*length)+'px', left: -scroll_left+'px'}">
<div v-for="t in timecodes" class="timeline_timecode" v-bind:style="{left: (t.time * size) + 'px'}">
{{ t.text }}
<div v-for="t in timecodes" class="timeline_timecode" v-bind:style="{left: (t.time * size) + 'px', width: (t.width * size) + 'px'}">
<span>{{ t.text }}</span>
<div class="substeps">
<div v-for="n in Math.ceil(t.substeps)"></div>
</div>
</div>
<div id="timeline_playhead"
v-bind:style="{left: (playhead * size) + 'px'}"
></div>
<div id="timeline_endbracket"
v-bind:style="{left: (animation_length * size) + 'px'}"
></div>
<div
v-for="marker in markers"
class="timeline_marker"
@ -1040,9 +1018,9 @@
></div>
<li v-for="animator in animators" class="animator" :class="{selected: animator.selected}" :uuid="animator.uuid" v-on:click="animator.select();">
<div class="animator_head_bar">
<div class="channel_head" v-bind:style="{left: scroll_left+'px', width: head_width+'px'}">
<div class="channel_head" v-bind:style="{left: scroll_left+'px', width: head_width+'px'}" v-on:dblclick.stop="toggleAnimator(animator)">
<div class="text_button" v-on:click.stop="toggleAnimator(animator)">
<i class="icon-open-state fa" v-bind:class="{'fa-caret-right': !animator.expanded, 'fa-caret-down': animator.expanded}"></i>
<i class="icon-open-state fa" v-bind:class="{'fa-angle-right': !animator.expanded, 'fa-angle-down': animator.expanded}"></i>
</div>
<span v-on:click.stop="animator.select();">{{animator.name}}</span>
<div class="text_button" v-on:click.stop="removeAnimator(animator)">
@ -1060,7 +1038,11 @@
</keyframe>
</div>
</div>
<div class="animator_channel_bar" v-bind:style="{width: (size*length + head_width)+'px'}" v-for="channel in animator.channels" v-if="animator.expanded && (!focus_channel || channel == focus_channel)">
<div class="animator_channel_bar"
v-bind:style="{width: (size*length + head_width)+'px'}"
v-for="channel in animator.channels"
v-if="animator.expanded && (!focus_channel || channel == focus_channel || focus_channel == 'used' && animator[channel].length)"
>
<div class="channel_head" v-bind:style="{left: scroll_left+'px', width: head_width+'px'}">
<div class="text_button" v-on:click.stop="animator.toggleMuted(channel)">
<template v-if="channel === 'sound'">
@ -1109,7 +1091,7 @@
<div class="bar next_to_title" id="uv_title_bar">
<div class="tool" onclick="Blockbench.openLink('https://blockbench.net/quickstart/')">
<div class="tooltip tl">menu.help.quickstart</div>
<i class="fa_big fas fa-directions"></i>
<i class="fas fa-question-circle"></i>
</div>
</div>
<ul>

View File

@ -20,6 +20,9 @@ class Animation {
Merge.boolean(this, data, 'override')
Merge.string(this, data, 'anim_time_update')
Merge.number(this, data, 'length')
if (typeof data.length == 'number') {
this.setLength(this.length)
}
if (data.bones && !data.animators) {
data.animators = data.bones;
}
@ -30,9 +33,9 @@ class Animation {
var ba = this.getBoneAnimator(group)
var kfs = data.animators[key]
if (kfs && ba) {
ba.rotation.length = 0;
ba.position.length = 0;
ba.scale.length = 0;
ba.rotation.empty();
ba.position.empty();
ba.scale.empty();
kfs.forEach(kf_data => {
ba.addKeyframe(kf_data, kf_data.uuid);
})
@ -87,6 +90,7 @@ class Animation {
Timeline.animators.purge();
Timeline.selected.empty();
Timeline.vue._data.markers = this.markers;
Timeline.vue._data.animation_length = this.length;
this.selected = true;
this.playing = true;
Animator.selected = this;
@ -103,6 +107,14 @@ class Animation {
Animator.preview();
return this;
}
setLength(len) {
len = limitNumber(len, 0, 1e4)
this.length = len;
if (Animator.selected == this) {
Timeline.vue._data.animation_length = this.length;
BarItems.slider_animation_length.update()
}
}
createUniqueName(arr) {
var scope = this;
var others = Animator.animations;
@ -217,7 +229,7 @@ class Animation {
i++;
}
}
this.length = len
this.setLength(len)
if (this == Animator.selected) {
BarItems.slider_animation_length.update()
}
@ -294,6 +306,7 @@ class GeneralAnimator {
})
}
select() {
if (this.getGroup().locked) return;
var scope = this;
TickUpdates.keyframes = true;
for (var key in Animator.selected.animators) {
@ -339,7 +352,7 @@ class GeneralAnimator {
if (value) {
keyframe.extend(value);
} else if (this.fillValues) {
this.fillValues(keyframe, value);
this.fillValues(keyframe, value, true);
}
keyframe.channel = channel;
keyframe.time = time;
@ -468,7 +481,7 @@ class BoneAnimator extends GeneralAnimator {
}
return this;
}
fillValues(keyframe, values) {
fillValues(keyframe, values, allow_expression) {
if (values instanceof Array) {
keyframe.extend({
@ -486,7 +499,7 @@ class BoneAnimator extends GeneralAnimator {
z: values
})
} else if (values == null) {
var ref = this.interpolate(Timeline.time, keyframe.channel, true)
var ref = this.interpolate(keyframe.channel, allow_expression)
if (ref) {
let e = 1e2
ref.forEach((r, i) => {
@ -551,7 +564,8 @@ class BoneAnimator extends GeneralAnimator {
bone.scale.z *= arr[2] || 0.00001;
return this;
}
interpolate(time, channel, allow_expression) {
interpolate(channel, allow_expression) {
let time = Timeline.time;
var i = 0;
var before = false
var after = false
@ -607,13 +621,13 @@ class BoneAnimator extends GeneralAnimator {
}
return result
}
displayFrame(time) {
displayFrame() {
if (!this.doRender()) return;
this.getGroup()
if (!this.muted.rotation) this.displayRotation(this.interpolate(time, 'rotation'))
if (!this.muted.position) this.displayPosition(this.interpolate(time, 'position'))
if (!this.muted.scale) this.displayScale(this.interpolate(time, 'scale'))
if (!this.muted.rotation) this.displayRotation(this.interpolate('rotation'))
if (!this.muted.position) this.displayPosition(this.interpolate('position'))
if (!this.muted.scale) this.displayScale(this.interpolate('scale'))
}
}
BoneAnimator.prototype.channels = ['rotation', 'position', 'scale']
@ -643,6 +657,7 @@ class EffectAnimator extends GeneralAnimator {
if (diff >= 0 && diff < (1/60) * (Timeline.playback_speed/100)) {
if (kf.file && !kf.cooldown) {
var media = new Audio(kf.file);
window._media = media
media.volume = Math.clamp(settings.volume.value/100, 0, 1);
media.play();
Timeline.playing_sounds.push(media);
@ -810,9 +825,6 @@ class Keyframe {
this.get('y'),
this.get('z'),
]
if (this.channel === 'rotation' && this.isQuaternion) {
arr.push(this.get('w'))
}
return arr;
}
getFixed() {
@ -860,7 +872,7 @@ class Keyframe {
Timeline.selected.forEach(function(kf) {
kf.selected = false
})
Timeline.selected.length = 0
Timeline.selected.empty()
}
if (event && event.shiftKey && Timeline.selected.length) {
var last = Timeline.selected[Timeline.selected.length-1]
@ -1162,7 +1174,7 @@ const Animator = {
join() {
Animator.open = true;
selected.length = 0
selected.empty()
Canvas.updateAllBones()
//if (quad_previews.enabled) {
@ -1182,7 +1194,7 @@ const Animator = {
}
TickUpdates.keyframes = true;
if (outlines.children.length) {
outlines.children.length = 0
outlines.children.empty()
Canvas.updateAllPositions()
}
if (!Animator.selected && Animator.animations.length) {
@ -1222,7 +1234,7 @@ const Animator = {
Group.all.forEach(group => {
Animator.animations.forEach(animation => {
if (animation.playing) {
animation.getBoneAnimator(group).displayFrame(Timeline.time)
animation.getBoneAnimator(group).displayFrame()
}
})
group.mesh.updateMatrixWorld()
@ -1391,7 +1403,7 @@ const Animator = {
ani_tag.timeline[timecode] = kf.instructions.split('\n');
})
} else if (a.animators[uuid].keyframes.length && a.animators[uuid].group) {
} else if (a.animators[uuid].keyframes.length && a.animators[uuid].getGroup()) {
var group = a.animators[uuid].group;
var bone_tag = ani_tag.bones[group.name] = {};
@ -1413,6 +1425,12 @@ const Animator = {
let timecodes = Object.keys(channels[channel])
if (timecodes.length === 1) {
bone_tag[channel] = channels[channel][timecodes[0]]
if (channel == 'scale' &&
channels[channel][timecodes[0]] instanceof Array &&
channels[channel][timecodes[0]].allEqual(channels[channel][timecodes[0]][0])
) {
bone_tag[channel] = channels[channel][timecodes[0]][0];
}
} else {
timecodes.sort().forEach((time) => {
if (!bone_tag[channel]) {
@ -1442,6 +1460,7 @@ const Timeline = {
playback_speed: 100,
time: 0,
get second() {return Timeline.time},
get animation_length() {return Animator.selected ? Animator.selected.length : 0;},
playing: false,
selector: {
start: [0, 0],
@ -1502,7 +1521,7 @@ const Timeline = {
var min_time = (rect.ax-Timeline.vue._data.head_width-8)/Timeline.vue._data.size;
var max_time = (rect.bx-Timeline.vue._data.head_width-8)/Timeline.vue._data.size;
Timeline.selected.length = 0;
Timeline.selected.empty()
for (var animator of Timeline.animators) {
var node = $('#timeline_body_inner .animator[uuid=' + animator.uuid + ']').get(0)
var offset = node && node.offsetTop;
@ -1562,10 +1581,14 @@ const Timeline = {
if (!editing) {
Timeline.setTimecode(seconds)
}
Timeline.updateSize()
//Scroll
if (Timeline.getMaxLength() !== Timeline.vue._data.length) {
Timeline.updateSize()
}
Timeline.revealTime(seconds)
},
revealTime(time) {
var scroll = $('#timeline_body').scrollLeft()
var playhead = Timeline.time * Timeline.vue._data.size + 8
var playhead = time * Timeline.vue._data.size + 8
if (playhead < scroll || playhead > scroll + $('#timeline_body').width() - Timeline.vue._data.head_width) {
$('#timeline_body').scrollLeft(playhead-16)
}
@ -1595,14 +1618,24 @@ const Timeline = {
$('#timeline_time').on('mousedown touchstart', e => {
if (e.which !== 1 && !event.changedTouches) return;
if (e.target.classList.contains('timeline_marker')) return;
convertTouchEvent(e);
Timeline.dragging_playhead = true;
let time = (e.offsetX) / Timeline.vue._data.size
Timeline.setTime(Timeline.snapTime(time))
Animator.preview()
if (e.target.id == 'timeline_endbracket') {
Timeline.dragging_endbracket = true;
Undo.initEdit({animations: [Animator.selected]});
} else {
convertTouchEvent(e);
Timeline.dragging_playhead = true;
let time = (e.offsetX) / Timeline.vue._data.size
Timeline.setTime(Timeline.snapTime(time))
Animator.preview()
}
})
$(document).on('mousemove touchmove', e => {
if (Timeline.dragging_playhead) {
convertTouchEvent(e);
let offset = e.clientX - $('#timeline_time').offset().left;
let time = Timeline.snapTime(offset / Timeline.vue._data.size)
@ -1610,12 +1643,26 @@ const Timeline = {
Timeline.setTime(time)
Animator.preview()
}
} else if (Timeline.dragging_endbracket) {
convertTouchEvent(e);
let offset = e.clientX - $('#timeline_time').offset().left;
let time = Timeline.snapTime(offset / Timeline.vue._data.size)
Animator.selected.setLength(time)
Timeline.revealTime(time)
}
})
.on('mouseup touchend', e => {
if (Timeline.dragging_playhead) {
delete Timeline.dragging_playhead
Timeline.pause();
} else if (Timeline.dragging_endbracket) {
Undo.finishEdit('Change Animation Length')
delete Timeline.dragging_endbracket
}
})
//Keyframe inputs
@ -1679,16 +1726,33 @@ const Timeline = {
}
})
$('#timeline_vue').on('mousewheel', function() {
$('#timeline_vue').on('mousewheel scroll', function(e) {
e.preventDefault()
var body = $('#timeline_body').get(0)
if (event.shiftKey) {
body.scrollLeft += event.deltaY/4
} else if (event.ctrlOrCmd) {
var offset = 1 - event.deltaY/600
Timeline.vue._data.size = limitNumber(Timeline.vue._data.size * offset, 10, 1000)
body.scrollLeft *= offset
let mouse_pos = event.clientX - $(this).offset().left;
var zoom = 1 - event.deltaY/600
let original_size = Timeline.vue._data.size
Timeline.vue._data.size = limitNumber(Timeline.vue._data.size * zoom, 10, 1000)
//let val = ((body.scrollLeft + mouse_pos) * (Timeline.vue._data.size - original_size) ) / 128
let size_ratio = Timeline.vue._data.size / original_size
let offset = mouse_pos - body.scrollLeft - 180
let val = (size_ratio-1) * offset;
// todo: optimize zooming in
body.scrollLeft += val
/*
Timeline.vue._data.size = limitNumber(Timeline.vue._data.size * zoom, 10, 1000)
body.scrollLeft *= zoom
let l = (event.offsetX / body.clientWidth) * 500 * (event.deltaY<0?1:-0.2)
body.scrollLeft += l
*/
} else {
body.scrollTop += event.deltaY/6.25
}
@ -1752,88 +1816,56 @@ const Timeline = {
}
Undo.addKeyframeCasualties(deleted);
Undo.finishEdit('drag keyframes')
}
})
$('#timeline_body .keyframe:not(.ui-draggable)').draggable({
axis: 'x',
distance: 4,
helper: () => $('<div></div>'),
start: function(event, ui) {
var id = $(event.target).attr('id');
var clicked = Timeline.keyframes.findInArray('uuid', id)
if (!$(event.target).hasClass('selected') && !event.shiftKey && Timeline.selected.length != 0) {
clicked.select()
} else if (clicked && !clicked.selected) {
clicked.select({shiftKey: true})
}
Undo.initEdit({keyframes: Timeline.selected})
Timeline.dragging_keyframes = true;
var i = 0;
for (var kf of Timeline.selected) {
kf.time_before = kf.time
}
},
drag: function(event, ui) {
var difference = (ui.position.left - ui.originalPosition.left - 8) / Timeline.vue._data.size;
var id = $(ui.helper).attr('id')
var snap_value = false
var nearest
for (var kf of Timeline.selected) {
var t = limitNumber(kf.time_before + difference, 0, 256)
if (kf.uuid === id) {
ui.position.left = t * Timeline.vue._data.size + 8
}
kf.time = Timeline.snapTime(t);
}
BarItems.slider_keyframe_time.update()
Animator.preview()
},
stop: function(event, ui) {
var deleted = []
for (var kf of Timeline.selected) {
delete kf.time_before;
kf.replaceOthers(deleted);
}
Undo.addKeyframeCasualties(deleted);
Undo.finishEdit('drag keyframes')
setTimeout(() => {
Timeline.dragging_keyframes = false;
}, 20)
}
})
},
updateSize() {
let size = Timeline.vue._data.size
getMaxLength() {
var max_length = ($('#timeline_body').width()-8) / Timeline.vue._data.size;
Timeline.keyframes.forEach((kf) => {
max_length = Math.max(max_length, kf.time)
})
max_length = Math.max(max_length, Timeline.time) + 50/Timeline.vue._data.size
Timeline.vue._data.length = max_length
Timeline.vue._data.timecodes.length = 0
return max_length;
},
updateSize() {
let size = Timeline.vue._data.size
Timeline.vue._data.length = Timeline.getMaxLength()
Timeline.vue._data.timecodes.empty()
var step = 1
if (size < 1) {step = 1}
else if (size < 20) {step = 4}
else if (size < 40) {step = 2}
else if (size < 90) {step = 1}
else if (size < 180) {step = 0.5}
else if (size < 400) {step = 0.2}
else if (size < 800) {step = 0.1}
else if (size < 100) {step = 1}
else if (size < 256) {step = 0.5}
else if (size < 520) {step = 0.25}
else if (size < 660) {step = 0.2}
else if (size < 860) {step = 0.1}
else {step = 0.05}
if (step < 1) {
var FPS = Timeline.getStep();
step = Math.round(step/FPS) * FPS
step = 1/Math.round(1/step)
//step = 1/Math.round(1/step)
}
let substeps = step / Timeline.getStep()
while (substeps > 8) {
substeps /= 2;
}
//substeps = Math.round(substeps)
var i = 0;
while (i < Timeline.vue._data.length) {
Timeline.vue._data.timecodes.push({
time: i,
width: step,
substeps: substeps,
text: Math.round(i*100)/100
})
i += step;
@ -1907,6 +1939,7 @@ const Timeline = {
'_',
'select_all',
'bring_up_all_animations',
'fold_all_animations',
'clear_timeline',
])
}
@ -1954,8 +1987,9 @@ onVueSetup(function() {
data: {
size: 150,
length: 10,
animation_length: 0,
scroll_left: 0,
head_width: 170,
head_width: 180,
timecodes: [],
animators: Timeline.animators,
markers: [],
@ -2006,6 +2040,7 @@ BARS.defineActions(function() {
}
}
Blockbench.import({
resource_id: 'animation',
extensions: ['json'],
type: 'JSON Animation',
startpath: path
@ -2035,6 +2070,7 @@ BARS.defineActions(function() {
}
}
Blockbench.export({
resource_id: 'animation',
type: 'JSON Animation',
extensions: ['json'],
name: (Project.geometry_name||'model')+'.animation',
@ -2075,7 +2111,13 @@ BARS.defineActions(function() {
return Animator.selected.length
},
change: function(modify) {
Animator.selected.length = limitNumber(modify(Animator.selected.length), 0, 1e4)
Animator.selected.setLength(limitNumber(modify(Animator.selected.length), 0, 1e4))
},
onBefore: function() {
Undo.initEdit({animations: [Animator.selected]});
},
onAfter: function() {
Undo.finishEdit('Change Animation Length')
}
})
new NumSlider('slider_animation_speed', {
@ -2169,12 +2211,28 @@ BARS.defineActions(function() {
Animator.preview()
}
})
new Action('resolve_keyframe_expressions', {
icon: 'functions',
category: 'animation',
condition: () => Animator.open && Timeline.selected.length,
click: function () {
Undo.initEdit({keyframes: Timeline.selected})
Timeline.selected.forEach((kf) => {
if (kf.animator.fillValues) {
kf.animator.fillValues(kf, null, false);
}
})
Undo.finishEdit('reset keyframes')
updateKeyframeSelection()
}
})
new Action('change_keyframe_file', {
icon: 'fa-file-audio',
category: 'animation',
condition: () => (Animator.open && Timeline.selected.length && Timeline.selected[0].channel == 'sound' && isApp),
click: function () {
Blockbench.import({
resource_id: 'animation_audio',
extensions: ['ogg'],
type: 'Audio File',
startpath: Timeline.selected[0].file
@ -2365,6 +2423,7 @@ BARS.defineActions(function() {
category: 'animation',
condition: {modes: ['animate']},
click: function () {
if (!Animator.selected) return;
for (var uuid in Animator.selected.animators) {
var ba = Animator.selected.animators[uuid]
if (ba && ba.keyframes.length) {
@ -2374,6 +2433,17 @@ BARS.defineActions(function() {
}
})
new Action('fold_all_animations', {
icon: 'format_indent_decrease',
category: 'animation',
condition: {modes: ['animate']},
click: function () {
for (var animator of Timeline.animators) {
animator.expanded = false;
}
}
})
new Action('clear_timeline', {
icon: 'clear_all',
category: 'animation',
@ -2398,6 +2468,7 @@ BARS.defineActions(function() {
new BarSelect('timeline_focus', {
options: {
all: true,
used: true,
rotation: tl('timeline.rotation'),
position: tl('timeline.position'),
scale: tl('timeline.scale'),

View File

@ -299,6 +299,7 @@ const Blockbench = {
//startpath
//title
//errorbox
//resource_id
if (isApp) {
var properties = []
@ -309,6 +310,9 @@ const Blockbench = {
options.type = 'Images'
options.extensions = ['png', 'jpg', 'jpeg', 'bmp', 'tiff', 'tif', 'gif']
}
if (!options.startpath && options.resource_id) {
options.startpath = StateMemory.dialog_paths[options.resource_id]
}
ElecDialogs.showOpenDialog(
currentwindow,
@ -323,6 +327,11 @@ const Blockbench = {
defaultPath: options.startpath
},
function (fileNames) {
if (!fileNames) return;
if (options.resource_id) {
StateMemory.dialog_paths[options.resource_id] = PathModule.dirname(fileNames[0])
StateMemory.save('dialog_paths')
}
Blockbench.read(fileNames, options, cb)
})
} else {
@ -478,6 +487,7 @@ const Blockbench = {
savetype
project_file
custom_writer
resource_id
*/
if (Blockbench.isWeb) {
var file_name = options.name + (options.extensions ? '.'+options.extensions[0] : '')
@ -504,6 +514,12 @@ const Blockbench = {
cb(file_name)
}
} else {
if (!options.startpath && options.resource_id) {
options.startpath = StateMemory.dialog_paths[options.resource_id]
if (options.name) {
options.startpath += osfs + options.name + (options.extensions ? '.'+options.extensions[0] : '');
}
}
ElecDialogs.showSaveDialog(currentwindow, {
dontAddToRecent: true,
filters: [ {
@ -515,6 +531,10 @@ const Blockbench = {
: options.name
}, function (file_path) {
if (!file_path) return;
if (options.resource_id) {
StateMemory.dialog_paths[options.resource_id] = PathModule.dirname(file_path)
StateMemory.save('dialog_paths')
}
var extension = pathToExtension(file_path);
if (!extension && options.extensions && options.extensions[0]) {
file_path += '.'+options.extensions[0]
@ -635,6 +655,38 @@ if (isApp) {
if (Blockbench.platform.includes('win32') === true) osfs = '\\';
}
const StateMemory = {
init(key, type) {
let saved = localStorage.getItem(`StateMemory.${key}`)
if (typeof saved == 'string') {
try {
saved = JSON.parse(saved)
} catch (err) {
localStorage.clearItem(`StateMemory.${key}`)
}
}
if ( saved !== null && (typeof saved == type || (type == 'array' && saved instanceof Array)) ) {
StateMemory[key] = saved;
} else {
StateMemory[key] = (() => {switch (type) {
case 'string': return ''; break;
case 'number': return 0; break;
case 'boolean': return false; break;
case 'object': return {}; break;
case 'array': return []; break;
}})();
}
},
save(key) {
let serialized = JSON.stringify(StateMemory[key])
localStorage.setItem(`StateMemory.${key}`, serialized)
}
}
document.ondragover = function(event) {
event.preventDefault()
}

View File

@ -29,39 +29,7 @@ var Prop = {
connections : 0,
facing : 'north'
}
const Project = {
name : '',
parent : '',
geometry_name : '',
description : '',
_box_uv : false,
get box_uv() {return Project._box_uv},
set box_uv(v) {
if (Project._box_uv != v) {
Project._box_uv = v;
switchBoxUV(v);
}
},
get texture_width() {return Project._texture_width},
get texture_height() {return Project._texture_height},
set texture_width(n) {
n = parseInt(n)||16
Vue.nextTick(updateProjectResolution)
Project._texture_width = n;
},
set texture_height(n) {
n = parseInt(n)||16
Vue.nextTick(updateProjectResolution)
Project._texture_height = n;
},
_texture_width : 16,
_texture_height : 16,
ambientocclusion: true,
front_gui_light: false,
get optional_box_uv() {
return Format.optional_box_uv;
}
}
const mouse_pos = {x:0,y:0}
const sort_collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
@ -175,12 +143,13 @@ function updateProjectResolution() {
//Selections
function updateSelection() {
elements.forEach(obj => {
if (selected.includes(obj) && !obj.selected) {
if (selected.includes(obj) && !obj.selected && !obj.locked) {
obj.selectLow()
} else if (!selected.includes(obj) && obj.selected) {
} else if ((!selected.includes(obj) || obj.locked) && obj.selected) {
obj.unselect()
}
})
if (Group.selected && Group.selected.locked) Group.selected.unselect()
Cube.all.forEach(cube => {
if (cube.visibility) {
@ -221,7 +190,6 @@ function updateSelection() {
BarItems.cube_counter.update();
updateNslideValues();
Blockbench.globalMovement = isMovementGlobal();
updateCubeHighlights();
Canvas.updateOrigin();
Transformer.updateSelection();
@ -298,7 +266,7 @@ function createSelection() {
setInterval(function() {
if (Outliner.root.length || textures.length) {
try {
var model = Codecs.project.compile({compressed: true});
var model = Codecs.project.compile({compressed: false});
localStorage.setItem('backup_model', model)
} catch (err) {
console.log('Unable to create backup. ', err)

View File

@ -1,6 +1,8 @@
CustomTheme.setup()
StateMemory.init('dialog_paths', 'object')
initCanvas()
animate()
@ -117,4 +119,6 @@ Modes.options.start.select()
loadInstalledPlugins();
document.getElementById('page_wrapper').classList.remove('hidden')
Blockbench.setup_successful = true;

View File

@ -7,6 +7,7 @@ const zlib = require('zlib');
const exec = require('child_process').exec;
const originalFs = require('original-fs');
const https = require('https');
const PathModule = require('path')
const currentwindow = electron.getCurrentWindow();
const ElecDialogs = {};
@ -49,7 +50,9 @@ function initializeDesktopApp() {
shell.openExternal(event.target.href);
return true;
});
if (compareVersions('5.0.0', process.versions.electron)) {
if (currentwindow.webContents.zoomLevel !== undefined) {
Prop.zoom = 100 + currentwindow.webContents.zoomLevel*12
} else if (compareVersions('5.0.0', process.versions.electron)) {
Prop.zoom = 100 + currentwindow.webContents._getZoomLevel()*12
} else {
Prop.zoom = 100 + currentwindow.webContents.getZoomLevel()*12
@ -114,6 +117,7 @@ function addRecentProject(data) {
}
i--;
}
if (data.name.length > 48) data.name = data.name.substr(0, 20) + '...' + data.name.substr(-20);
let project = {
name: data.name,
path: data.path,
@ -214,7 +218,7 @@ function installUpdate() {
var file = originalFs.createWriteStream(asar_path);
var request = https.get("https://blockbench.net/api/app.asar", function(response) {
https.get("https://blockbench.net/api/app.asar", function(response) {
response.pipe(file);
total_bytes = parseInt(response.headers['content-length']);
@ -252,12 +256,12 @@ function changeImageEditor(texture, from_settings) {
var path;
if (Blockbench.platform == 'darwin') {
switch (id) {
case 'ps': path = '/Applications/Adobe Photoshop CC 2019/Adobe Photoshop CC 2019.app'; break;
case 'ps': path = '/Applications/Adobe Photoshop CC 2020/Adobe Photoshop CC 2020.app'; break;
case 'gimp':path = '/Applications/Gimp-2.10.app'; break;
}
} else {
switch (id) {
case 'ps': path = 'C:\\Program Files\\Adobe\\Adobe Photoshop CC 2019\\Photoshop.exe'; break;
case 'ps': path = 'C:\\Program Files\\Adobe\\Adobe Photoshop CC 2020\\Photoshop.exe'; break;
case 'gimp':path = 'C:\\Program Files\\GIMP 2\\bin\\gimp-2.10.exe'; break;
case 'pdn': path = 'C:\\Program Files\\paint.net\\PaintDotNet.exe'; break;
}

View File

@ -1778,6 +1778,7 @@ window.changeDisplaySkin = function() {
}, function(result) {
if (result === 0) {
Blockbench.import({
resource_id: 'minecraft_skin',
extensions: ['png'],
type: 'PNG Player Skin',
readtype: 'image'
@ -1937,6 +1938,51 @@ BARS.defineActions(function() {
condition: () => display_mode,
click: function () {showDialog('create_preset')}
})
new Action('apply_display_preset', {
icon: 'fa-list',
category: 'display',
condition: () => display_mode,
click: function (e) {
new Menu(this.children()).open(e.target)
},
children: function() {
var presets = []
display_presets.forEach(function(p) {
var icon = 'label'
if (p.fixed) {
switch(p.id) {
case 'item': icon = 'filter_vintage'; break;
case 'block': icon = 'fa-cube'; break;
case 'handheld': icon = 'build'; break;
case 'rod': icon = 'remove'; break;
}
}
presets.push({
icon: icon,
name: p.id ? tl('display.preset.'+p.id) : p.name,
children: [
{name: 'action.apply_display_preset.here', icon: 'done', click() {
DisplayMode.applyPreset(p)
}},
{name: 'action.apply_display_preset.everywhere', icon: 'done_all', click() {
DisplayMode.applyPreset(p, true)
}},
{
icon: 'delete',
name: 'generic.delete',
condition: !p.fixed,
click: function() {
display_presets.splice(display_presets.indexOf(p), 1);
localStorage.setItem('display_presets', JSON.stringify(display_presets))
}
}
]
})
})
return presets;
}
})
new BarSelect('gui_light', {
options: {
side: true,

View File

@ -172,6 +172,7 @@ class Action extends BarItem {
this.linked_setting = data.linked_setting
}
if (data.condition) this.condition = data.condition
this.children = data.children;
//Node
this.click = data.click
@ -751,7 +752,7 @@ class BarSelect extends Widget {
}
let menu = new Menu(items);
menu.node.style['min-width'] = this.node.clientWidth+'px';
menu.open(this.node, this);
menu.open(event.target, this);
}
trigger(event) {
if (!event) event = 0;
@ -1518,8 +1519,13 @@ const BARS = {
'export_palette',
'generate_palette',
'sort_palette',
'load_palette',
]
})
//update 3.5
if (!Toolbars.palette.children.includes(BarItems.load_palette)) {
Toolbars.palette.add(BarItems.load_palette)
}
Toolbars.color_picker = new Toolbar({
id: 'color_picker',
children: [
@ -1538,14 +1544,11 @@ const BARS = {
'copy',
'paste',
'add_display_preset',
'apply_display_preset',
'gui_light'
],
default_place: true
})
//update 3.3.1
if (!Toolbars.display.children.includes(BarItems.gui_light)) {
Toolbars.display.add(BarItems.gui_light)
}
//UV
Toolbars.main_uv = new Toolbar({
id: 'main_uv',
@ -1682,6 +1685,7 @@ const BARS = {
BarItems.reset_keybindings.toElement('#keybinds_title_bar')
BarItems.load_plugin.toElement('#plugins_header_bar')
BarItems.load_plugin_from_url.toElement('#plugins_header_bar')
BarItems.uv_dialog.toElement('#uv_title_bar')
BarItems.uv_dialog_full.toElement('#uv_title_bar')
BarItems.toggle_chat.toElement('#chat_title_bar')

View File

@ -72,7 +72,7 @@ function Dialog(settings) {
}
if (scope.form) {
for (var form_id in scope.form) {
var data = scope.form[form_id]
let data = scope.form[form_id]
if (data === '_') {
jq_dialog.append('<hr />')
@ -94,10 +94,25 @@ function Dialog(settings) {
}
bar.append(list)
}
if (data.type == 'password') {
bar.append(`<div class="password_toggle" @click="setting.hidden = !setting.hidden;">
<i class="fas fa-eye-slash"></i>
</div>`)
let input = bar.find('input').attr('type', 'password')
let hidden = true;
let this_bar = bar;
this_bar.find('.password_toggle').click(e => {
hidden = !hidden;
input.attr('type', hidden ? 'password' : 'text');
this_bar.find('.password_toggle i')[0].className = hidden ? 'fas fa-eye-slash' : 'fas fa-eye';
})
}
break;
case 'textarea':
bar.append(`<textarea class="focusable_input" style="height: ${data.height||150}px;" id="${form_id}"></textarea>`)
break;
case 'select':
var el = $(`<div class="bar_select half"><select class="focusable_input" id="${form_id}"></select></div>`)
var sel = el.find('select')
@ -107,6 +122,8 @@ function Dialog(settings) {
}
bar.append(el)
break;
case 'radio':
var el = $(`<div class="half form_part_radio" id="${form_id}"></div>`)
for (var key in data.options) {
@ -118,14 +135,31 @@ function Dialog(settings) {
}
bar.append(el)
break;
case 'text':
case 'info':
data.text = marked(tl(data.text))
bar.append(`<p>${data.text}</p>`)
bar.addClass('small_text')
break;
case 'number':
bar.append(`<input class="dark_bordered half focusable_input" type="number" id="${form_id}" value="${data.value||0}" min="${data.min}" max="${data.max}" step="${data.step||1}">`)
bar.append(`<input class="dark_bordered half focusable_input" type="number" id="${form_id}"
value="${data.value||0}" min="${data.min}" max="${data.max}" step="${data.step||1}">`)
break;
case 'vector':
let group = $(`<div class="dialog_vector_group half"></div>`)
bar.append(group)
for (var i = 0; i < (data.dimensions || 3); i++) {
group.append(`<input class="dark_bordered focusable_input" type="number" id="${form_id}_${i}"
value="${data.value ? data.value[i]: 0}" step="${data.step||1}" min="${data.min}" max="${data.max}">`)
}
break;
case 'color':
if (!data.colorpicker) {
data.colorpicker = new ColorPicker({
@ -137,9 +171,13 @@ function Dialog(settings) {
}
bar.append(data.colorpicker.getNode())
break;
case 'checkbox':
bar.append(`<input type="checkbox" class="focusable_input" id="${form_id}"${data.value ? ' checked' : ''}>`)
break;
case 'file':
case 'folder':
case 'save':
@ -170,6 +208,7 @@ function Dialog(settings) {
switch (data.type) {
case 'file':
Blockbench.import({
resource_id: data.resource_id,
extensions: data.extensions,
type: data.filetype,
startpath: data.value
@ -185,6 +224,7 @@ function Dialog(settings) {
break;
case 'save':
Blockbench.export({
resource_id: data.resource_id,
extensions: data.extensions,
type: data.filetype,
startpath: data.value,
@ -194,7 +234,6 @@ function Dialog(settings) {
}
})
case 'folder':
}
if (data.readonly) {
bar.find('input').attr('readonly', 'readonly').removeClass('focusable_input')
@ -223,7 +262,7 @@ function Dialog(settings) {
} else if (this.singleButton) {
jq_dialog.append('<div class="dialog_bar">' +
jq_dialog.append('<div class="dialog_bar" hidden>' +
'<button type="button" class="cancel_btn confirm_btn"'+ (this.confirmEnabled ? '' : ' disabled') +'>'+tl('dialog.close')+'</button>' +
'</div>')
@ -247,7 +286,7 @@ function Dialog(settings) {
default:
result[form_id] = jq_dialog.find('input#'+form_id).val()
break;
case 'text':
case 'info':
break;
case 'textarea':
result[form_id] = jq_dialog.find('textarea#'+form_id).val()
@ -261,6 +300,13 @@ function Dialog(settings) {
case 'number':
result[form_id] = Math.clamp(parseFloat(jq_dialog.find('input#'+form_id).val())||0, data.min, data.max)
break;
case 'vector':
result[form_id] = [];
for (var i = 0; i < (data.dimensions || 3); i++) {
let num = Math.clamp(parseFloat(jq_dialog.find(`input#${form_id}_${i}`).val())||0, data.min, data.max)
result[form_id].push(num)
}
break;
case 'color':
result[form_id] = data.colorpicker.get();
break;

View File

@ -116,9 +116,10 @@ class ResizeLine {
var jq = $('<div class="resizer '+(data.horizontal ? 'horizontal' : 'vertical')+'"></div>')
this.node = jq.get(0)
jq.draggable({
axis: this.horizontal ? 'y' : 'y',
axis: this.horizontal ? 'y' : 'x',
containment: '#page_wrapper',
revert: true,
revertDuration: 0,
start: function(e, u) {
scope.before = data.get()
},
@ -126,7 +127,7 @@ class ResizeLine {
if (scope.horizontal) {
data.set(scope.before, u.position.top - u.originalPosition.top)
} else {
data.set(scope.before, (e.clientX - u.position.left))
data.set(scope.before, (u.position.left - u.originalPosition.left))
}
updateInterface()
},
@ -189,13 +190,14 @@ var Interface = {
},
get: function() {return Interface.data.left_bar_width},
set: function(o, diff) {
Interface.data.left_bar_width = limitNumber(o + diff, 128, $(window).width()- 240 - Interface.data.right_bar_width)
let calculated = limitNumber(o + diff, 128, $(window).width()- 120 - Interface.data.right_bar_width)
Interface.data.left_bar_width = Math.snapToValues(calculated, [Interface.default_data.left_bar_width], 16);
},
position: function(line) {
line.setPosition({
top: 32,
top: 26,
bottom: 0,
left: Interface.data.left_bar_width-3
left: Interface.data.left_bar_width+2
})
}
}),
@ -210,13 +212,14 @@ var Interface = {
},
get: function() {return Interface.data.right_bar_width},
set: function(o, diff) {
Interface.data.right_bar_width = limitNumber(o - diff, 128, $(window).width()- 240 - Interface.data.left_bar_width)
let calculated = limitNumber(o - diff, 128, $(window).width()- 120 - Interface.data.left_bar_width);
Interface.data.right_bar_width = Math.snapToValues(calculated, [Interface.default_data.right_bar_width], 12);
},
position: function(line) {
line.setPosition({
top: 32,
top: 56,
bottom: 0,
right: Interface.data.right_bar_width-3
right: Interface.data.right_bar_width-2
})
}
}),
@ -307,7 +310,6 @@ function setupInterface() {
$('.edit_session_active').hide()
$('#center').toggleClass('checkerboard', settings.preview_checkerboard.value);
$('#UVEditor_main_uv').toggleClass('checkerboard_trigger', settings.uv_checkerboard.value);
$('.sidebar').droppable({
accept: 'h3',
@ -846,7 +848,7 @@ var documentReady = new Promise((resolve, reject) => {
//Electron
if (isApp && !compareVersions(process.versions.electron, '4.0.0')) {
if (isApp && !compareVersions(process.versions.electron, '6.0.0')) {
addStartScreenSection({
graphic: {type: 'icon', icon: 'fas.fa-atom'},
text: [
@ -869,8 +871,21 @@ var documentReady = new Promise((resolve, reject) => {
last: true
})
}
//Twitter
if (Blockbench.startup_count < 20 && Blockbench.startup_count % 5 === 4) {
addStartScreenSection({
color: '#1da1f2',
text_color: '#ffffff',
graphic: {type: 'icon', icon: 'fab.fa-twitter'},
text: [
{type: 'h1', text: 'Blockbench on Twitter'},
{text: 'Follow Blockbench on Twitter for the latest news as well as cool models from the community! [twitter.com/blockbench](https://twitter.com/blockbench/)'}
],
last: true
})
}
//Donation reminder
if (Blockbench.startup_count % 12 === 11) {
if (Blockbench.startup_count % 20 === 19) {
addStartScreenSection({
graphic: {type: 'icon', icon: 'fas.fa-heart'},
text: [

View File

@ -81,7 +81,7 @@ class Menu {
} else if (index >= MenuBar.keys.length) {
index = 0;
}
MenuBar.menues[MenuBar.keys[index]].open()
MenuBar.menus[MenuBar.keys[index]].open()
}
} else {
obj.find('> li:first-child').addClass('focused')
@ -113,6 +113,30 @@ class Menu {
ctxmenu.children().detach()
function createChildList(object, node) {
if (typeof object.children == 'function') {
var list = object.children(context)
} else {
var list = object.children
}
if (list.length) {
node.addClass('parent')
.find('ul.contextMenu.sub').detach()
var childlist = $('<ul class="contextMenu sub"></ul>')
node.append(childlist)
list.forEach(function(s2, i) {
getEntry(s2, childlist)
})
var last = childlist.children().last()
if (last.length && last.hasClass('menu_separator')) {
last.remove()
}
return childlist.children().length;
}
return 0;
}
function getEntry(s, parent) {
var entry;
@ -129,15 +153,20 @@ class Menu {
if (!s) {
return;
}
entry = s.menu_node
entry = $(s.menu_node)
if (BARS.condition(s.condition)) {
if (!entry.hasMenuEvents) {
entry.hasMenuEvents = true
entry.addEventListener('click', (e) => {s.trigger(e)})
$(entry).on('mouseenter mousedown', function(e) {
scope.hover(this, e)
})
entry.off('click')
entry.off('mouseenter mousedown')
entry.on('mouseenter mousedown', function(e) {
scope.hover(this, e)
})
//Submenu
if (typeof s.children == 'function' || typeof s.children == 'object') {
createChildList(s, entry)
} else {
entry.on('click', (e) => {s.trigger(e)})
//entry[0].addEventListener('click', )
}
parent.append(entry)
}
@ -161,24 +190,7 @@ class Menu {
}
//Submenu
if (typeof s.children == 'function' || typeof s.children == 'object') {
if (typeof s.children == 'function') {
var list = s.children(context)
} else {
var list = s.children
}
if (list.length) {
entry.addClass('parent')
var childlist = $('<ul class="contextMenu sub"></ul>')
entry.append(childlist)
list.forEach(function(s2, i) {
getEntry(s2, childlist)
})
var last = childlist.children().last()
child_count = childlist.children().length;
if (last.length && last.hasClass('menu_separator')) {
last.remove()
}
}
child_count = createChildList(s, entry)
}
if (child_count !== 0 || typeof s.click === 'function') {
parent.append(entry)
@ -204,6 +216,11 @@ class Menu {
if (position && position.clientX !== undefined) {
var offset_left = position.clientX
var offset_top = position.clientY+1
} else if (position == document.body) {
var offset_left = (document.body.clientWidth-el_width)/2
var offset_top = (document.body.clientHeight-el_height)/2
} else {
if (!position && scope.type === 'bar_menu') {
position = scope.label
@ -338,7 +355,7 @@ class BarMenu extends Menu {
constructor(id, structure, condition) {
super()
var scope = this;
MenuBar.menues[id] = this
MenuBar.menus[id] = this
this.type = 'bar_menu'
this.id = id
this.children = [];
@ -367,9 +384,10 @@ class BarMenu extends Menu {
}
}
const MenuBar = {
menues: {},
menus: {},
open: undefined,
setup() {
MenuBar.menues = MenuBar.menus;
new BarMenu('file', [
'project_window',
'_',
@ -470,6 +488,7 @@ const MenuBar = {
'add_cube',
'add_group',
'add_locator',
'unlock_everything',
'duplicate',
'delete',
'_',
@ -500,6 +519,7 @@ const MenuBar = {
]},
{name: 'menu.transform.properties', id: 'properties', icon: 'navigate_next', children: [
'toggle_visibility',
'toggle_locked',
'toggle_export',
'toggle_autouv',
'toggle_shade',
@ -514,66 +534,7 @@ const MenuBar = {
'paste',
'_',
'add_display_preset',
{name: 'menu.display.preset', icon: 'fa-list', children: function() {
var presets = []
display_presets.forEach(function(p) {
var icon = 'label'
if (p.fixed) {
switch(p.id) {
case 'item': icon = 'filter_vintage'; break;
case 'block': icon = 'fa-cube'; break;
case 'handheld': icon = 'build'; break;
case 'rod': icon = 'remove'; break;
}
}
presets.push({
icon: icon,
name: p.id ? tl('display.preset.'+p.id) : p.name,
click: function() {
DisplayMode.applyPreset(p)
}
})
})
return presets;
}},
{name: 'menu.display.preset_all', icon: 'fa-list', children: function() {
var presets = []
display_presets.forEach(function(p) {
var icon = 'label'
if (p.fixed) {
switch(p.id) {
case 'item': icon = 'filter_vintage'; break;
case 'block': icon = 'fa-cube'; break;
case 'handheld': icon = 'build'; break;
case 'rod': icon = 'remove'; break;
}
}
presets.push({
icon: icon,
name: p.id ? tl('display.preset.'+p.id) : p.name,
click: function() {
DisplayMode.applyPreset(p, true)
}
})
})
return presets;
}},
{name: 'menu.display.remove_preset', icon: 'fa-list', children: function() {
var presets = []
display_presets.forEach(function(p) {
if (!p.fixed) {
presets.push({
icon: 'label',
name: p.name,
click: function() {
display_presets.splice(display_presets.indexOf(p), 1);
localStorage.setItem('display_presets', JSON.stringify(display_presets))
}
})
}
})
return presets;
}}
'apply_display_preset'
], () => Modes.display)
new BarMenu('filter', [
@ -650,7 +611,9 @@ const MenuBar = {
{name: 'menu.help.developer.reset_storage', icon: 'fas.fa-hdd', click: () => {
if (confirm(tl('menu.help.developer.reset_storage.confirm'))) {
localStorage.clear()
Blockbench.addFlag('no_localstorage_saving')
console.log('Cleared Local Storage')
window.location.reload(true)
}
}},
{name: 'menu.help.developer.cache_reload', icon: 'cached', condition: !isApp, click: () => {
@ -672,10 +635,10 @@ const MenuBar = {
var bar = $('#menu_bar')
bar.children().detach()
this.keys = []
for (var menu in MenuBar.menues) {
if (MenuBar.menues.hasOwnProperty(menu)) {
if (MenuBar.menues[menu].conditionMet()) {
bar.append(MenuBar.menues[menu].label)
for (var menu in MenuBar.menus) {
if (MenuBar.menus.hasOwnProperty(menu)) {
if (MenuBar.menus[menu].conditionMet()) {
bar.append(MenuBar.menus[menu].label)
this.keys.push(menu)
}
}
@ -686,7 +649,7 @@ const MenuBar = {
addAction(action, path) {
if (path) {
path = path.split('.')
var menu = MenuBar.menues[path.splice(0, 1)[0]]
var menu = MenuBar.menus[path.splice(0, 1)[0]]
if (menu) {
menu.addAction(action, path.join('.'))
}
@ -695,7 +658,7 @@ const MenuBar = {
removeAction(path) {
if (path) {
path = path.split('.')
var menu = MenuBar.menues[path.splice(0, 1)[0]]
var menu = MenuBar.menus[path.splice(0, 1)[0]]
if (menu) {
menu.removeAction(path.join('.'))
}

View File

@ -17,6 +17,7 @@ class Setting {
case 'toggle': this.value = true; break;
case 'number': this.value = 0; break;
case 'text': this.value = ''; break;
case 'password': this.value = ''; break;
case 'select': this.value; break;
case 'click': this.value = false; break;
}
@ -38,6 +39,9 @@ class Setting {
if (this.type == 'select') {
this.options = data.options;
}
if (this.type == 'password') {
this.hidden = true;
}
if (typeof data.onChange == 'function') {
this.onChange = data.onChange
}
@ -88,7 +92,7 @@ const Settings = {
$('#center').toggleClass('checkerboard', settings.preview_checkerboard.value);
}});
new Setting('uv_checkerboard', {category: 'interface', value: false, onChange() {
$('#UVEditor_main_uv').toggleClass('checkerboard_trigger', settings.uv_checkerboard.value);
$('.UVEditor').toggleClass('checkerboard_trigger', settings.uv_checkerboard.value);
}});
//Preview
@ -111,12 +115,13 @@ const Settings = {
new Setting('deactivate_size_limit',{category: 'edit', value: false});
//Grid
new Setting('base_grid', {category: 'grid', value: true,});
new Setting('large_grid', {category: 'grid', value: false});
new Setting('full_grid', {category: 'grid', value: false});
new Setting('large_box', {category: 'grid', value: false});
new Setting('display_grid', {category: 'grid', value: false});
new Setting('painting_grid',{category: 'grid', value: true, onChange() {
new Setting('base_grid', {category: 'grid', value: true,});
new Setting('large_grid', {category: 'grid', value: false});
new Setting('full_grid', {category: 'grid', value: false});
new Setting('large_box', {category: 'grid', value: false});
new Setting('large_grid_size', {category: 'grid', value: 3, type: 'number'});
new Setting('display_grid', {category: 'grid', value: false});
new Setting('painting_grid', {category: 'grid', value: true, onChange() {
Cube.all.forEach(cube => {
Canvas.buildGridBox(cube)
})
@ -130,7 +135,8 @@ const Settings = {
new Setting('animation_snap',{category: 'snapping', value: 25, type: 'number'});
//Paint
new Setting('paint_side_restrict', {category: 'paint', value: true});
new Setting('paint_side_restrict', {category: 'paint', value: true});
//new Setting('layered_textures', {category: 'paint', value: false});
new Setting('brush_opacity_modifier', {category: 'paint', value: 'pressure', type: 'select', options: {
'pressure': tl('settings.brush_modifier.pressure'),
'tilt': tl('settings.brush_modifier.tilt'),
@ -149,18 +155,13 @@ const Settings = {
new Setting('default_path', {category: 'defaults', value: false, type: 'click', condition: isApp, icon: 'burst_mode', click: function() { openDefaultTexturePath() }});
//Dialogs
new Setting('dialog_unsaved_textures', {category: 'dialogs', value: true});
new Setting('dialog_larger_cubes', {category: 'dialogs', value: true});
new Setting('dialog_rotation_limit', {category: 'dialogs', value: true});
//Export
new Setting('minifiedout', {category: 'export', value: false});
new Setting('export_groups', {category: 'export', value: true});
new Setting('class_export_version', {category: 'export', value: '1.12', type: 'select', options: {
'1.12': '1.12',
'1.14': '1.14',
}});
new Setting('sketchfab_token', {category: 'export', value: '', type: 'text'});
new Setting('sketchfab_token', {category: 'export', value: '', type: 'password'});
new Setting('credit', {category: 'export', value: 'Made with Blockbench', type: 'text'});
},
addCategory(id, data) {
@ -181,18 +182,20 @@ const Settings = {
setSettingsTab('setting')
},
saveLocalStorages() {
localStorage.setItem('canvas_scenes', JSON.stringify(canvas_scenes))
var settings_copy = {}
for (var key in settings) {
settings_copy[key] = {value: settings[key].value}
}
localStorage.setItem('settings', JSON.stringify(settings_copy) )
localStorage.setItem('canvas_scenes', JSON.stringify(canvas_scenes))
localStorage.setItem('colors', JSON.stringify({
palette: ColorPanel.vue._data.palette,
history: ColorPanel.vue._data.history,
}))
},
save() {
Settings.saveLocalStorages()
function hasSettingChanged(id) {
return (settings[id].value !== Settings.old[id])
}
@ -205,7 +208,7 @@ const Settings = {
action.toggleLinkedSetting(false)
}
}
if (hasSettingChanged('base_grid') || hasSettingChanged('large_grid') || hasSettingChanged('full_grid')
if (hasSettingChanged('base_grid') || hasSettingChanged('large_grid') || hasSettingChanged('full_grid') || hasSettingChanged('large_grid_size')
||hasSettingChanged('large_box') || hasSettingChanged('display_grid') || hasSettingChanged('edit_size')) {
buildGrid()
}
@ -264,9 +267,14 @@ const Settings = {
},
old: {}
}
$(window).on('unload', Settings.saveLocalStorages)
Settings.setup()
window.onunload = function() {
if (!Blockbench.hasFlag('no_localstorage_saving')) {
Settings.saveLocalStorages()
}
}
onVueSetup(function() {
Settings.structure.search_results = {
name: tl('dialog.settings.search_results'),

View File

@ -15,6 +15,7 @@ const CustomTheme = {
button: '#3a3f4b',
bright_ui: '#f4f3ff',
accent: '#3e90ff',
frame: '#181a1f',
text: '#cacad4',
light: '#f4f3ff',
accent_text: '#000006',
@ -61,7 +62,7 @@ const CustomTheme = {
var hex = CustomTheme.data.colors[key];
document.body.style.setProperty('--color-'+key, hex);
}
$('meta[name=theme-color]').attr('content', CustomTheme.data.colors.border);
$('meta[name=theme-color]').attr('content', CustomTheme.data.colors.frame);
var c_outline = parseInt('0x'+CustomTheme.data.colors.accent.replace('#', ''))
if (c_outline !== gizmo_colors.outline.getHex()) {
@ -197,6 +198,7 @@ BARS.defineActions(function() {
category: 'blockbench',
click: function () {
Blockbench.import({
resource_id: 'theme',
extensions: ['bbstyle', 'bbtheme'],
type: 'Blockbench Theme'
}, function(files) {
@ -209,6 +211,7 @@ BARS.defineActions(function() {
category: 'blockbench',
click: function () {
Blockbench.export({
resource_id: 'theme',
type: 'Blockbench Theme',
extensions: ['bbtheme'],
content: autoStringify(CustomTheme.data)

View File

@ -38,6 +38,12 @@ var codec = new Codec('project', {
model.ambientocclusion = Project.ambientocclusion
model.front_gui_light = Project.front_gui_light;
}
if (Format.id == 'bedrock' || Format.id == 'bedrock_legacy') {
model.visible_box = Project.visible_box
}
if (Format.id == 'modded_entity') {
model.modded_entity_version = Project.modded_entity_version
}
model.resolution = {
width: Project.texture_width || 16,
height: Project.texture_height || 16,
@ -156,6 +162,12 @@ var codec = new Codec('project', {
if (model.front_gui_light !== undefined) {
Project.front_gui_light = !!model.front_gui_light;
}
if (model.visible_box) {
Project.visible_box.splice(0, Infinity, ...model.visible_box)
}
if (model.modded_entity_version) {
Project.modded_entity_version = model.modded_entity_version
}
if (model.resolution !== undefined) {
Project.texture_width = model.resolution.width;
Project.texture_height = model.resolution.height;
@ -179,12 +191,12 @@ var codec = new Codec('project', {
var copy = NonGroup.fromSave(element, true)
for (var face in copy.faces) {
if (!Format.single_texture) {
if (!Format.single_texture && element.faces) {
var texture = element.faces[face].texture !== null && textures[element.faces[face].texture]
if (texture) {
copy.faces[face].texture = texture.uuid
}
} else if (textures[0] && copy.faces[face].texture !== null) {
} else if (textures[0] && copy.faces && copy.faces[face].texture !== null) {
copy.faces[face].texture = textures[0].uuid
}
}

View File

@ -207,6 +207,46 @@ window.BedrockEntityManager = {
}
}
function calculateVisibleBox() {
var visible_box = new THREE.Box3()
Cube.all.forEach(cube => {
if (cube.export && cube.mesh) {
visible_box.expandByObject(cube.mesh);
}
})
var offset = new THREE.Vector3(8,8,8);
visible_box.max.add(offset);
visible_box.min.add(offset);
// Width
var radius = Math.max(
visible_box.max.x,
visible_box.max.z,
-visible_box.min.x,
-visible_box.min.z
)
if (Math.abs(radius) === Infinity) {
radius = 0
}
let width = Math.ceil((radius*2) / 16)
width = Math.max(width, Project.visible_box[0]);
Project.visible_box[0] = width;
// Height
let height = Math.ceil(Math.abs(visible_box.max.y - visible_box.min.y) / 16)
if (height === Infinity) height = 0;
height = Math.max(height, Project.visible_box[1]);
// Y
let y = height/2 + Math.floor(visible_box.min.y / 16)
if (y === Infinity) y = 0;
y = Math.min(y, Project.visible_box[2]);
Project.visible_box.replace([width, height, y])
return Project.visible_box;
}
(function() {
function parseGeometry(data) {
@ -221,16 +261,25 @@ function parseGeometry(data) {
}
}
codec.dispatchEvent('parse', {model: data.object});
let {description} = data.object;
Project.geometry_name = (data.object.description.identifier && data.object.description.identifier.replace(/^geometry\./, '')) || '';
Project.geometry_name = (description.identifier && description.identifier.replace(/^geometry\./, '')) || '';
Project.texture_width = 16;
Project.texture_height = 16;
if (data.object.description.texture_width !== undefined) {
Project.texture_width = data.object.description.texture_width;
if (typeof description.visible_bounds_width == 'number' && typeof description.visible_bounds_height == 'number') {
Project.visible_box[0] = Math.max(Project.visible_box[0], description.visible_bounds_width);
Project.visible_box[1] = Math.max(Project.visible_box[1], description.visible_bounds_height);
if (description.visible_bounds_offset && typeof description.visible_bounds_offset[1] == 'number') {
Project.visible_box[2] = Math.min(Project.visible_box[2], description.visible_bounds_offset[1]);
}
}
if (data.object.description.texture_height !== undefined) {
Project.texture_height = data.object.description.texture_height;
if (description.texture_width !== undefined) {
Project.texture_width = description.texture_width;
}
if (description.texture_height !== undefined) {
Project.texture_height = description.texture_height;
}
var bones = {}
@ -367,6 +416,7 @@ function parseGeometry(data) {
}
var codec = new Codec('bedrock', {
name: 'Bedrock Model',
extension: 'json',
@ -385,7 +435,6 @@ var codec = new Codec('bedrock', {
texture_height: Project.texture_height || 16,
}
var bones = []
var visible_box = new THREE.Box3()
var groups = getAllGroups();
var loose_cubes = [];
@ -485,11 +534,6 @@ var codec = new Codec('bedrock', {
}
}
}
//Visible Bounds
var mesh = obj.mesh
if (mesh) {
visible_box.expandByObject(mesh)
}
cubes.push(template)
} else if (obj instanceof Locator) {
@ -510,26 +554,11 @@ var codec = new Codec('bedrock', {
})
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)
//Width
var radius = Math.max(
visible_box.max.x,
visible_box.max.z,
-visible_box.min.x,
-visible_box.min.z
) * 0.9
if (Math.abs(radius) === Infinity) {
radius = 0
}
entitymodel.description.visible_bounds_width = Math.ceil((radius*2) / 16)
//Height
entitymodel.description.visible_bounds_height = Math.ceil(((visible_box.max.y - visible_box.min.y) * 0.9) / 16)
if (Math.abs(entitymodel.description.visible_bounds_height) === Infinity) {
entitymodel.description.visible_bounds_height = 0;
}
entitymodel.description.visible_bounds_offset = [0, entitymodel.description.visible_bounds_height/2 , 0]
let visible_box = calculateVisibleBox();
entitymodel.description.visible_bounds_width = visible_box[0];
entitymodel.description.visible_bounds_height = visible_box[1];
entitymodel.description.visible_bounds_offset = [0, visible_box[2] , 0]
}
if (bones.length) {
entitymodel.bones = bones
@ -777,6 +806,7 @@ var format = new ModelFormat({
}
})
//Object.defineProperty(format, 'single_texture', {get: _ => !settings.layered_textures.value})
codec.format = format;
BARS.defineActions(function() {

View File

@ -16,6 +16,14 @@ function parseGeometry(data) {
Project.texture_width = data.object.texturewidth || 64;
Project.texture_height = data.object.textureheight || 64;
if (typeof data.object.visible_bounds_width == 'number' && typeof data.object.visible_bounds_height == 'number') {
Project.visible_box[0] = Math.max(Project.visible_box[0], data.object.visible_bounds_width);
Project.visible_box[1] = Math.max(Project.visible_box[1], data.object.visible_bounds_height);
if (data.object.visible_bounds_offset && typeof data.object.visible_bounds_offset[1] == 'number') {
Project.visible_box[2] = Math.min(Project.visible_box[2], data.object.visible_bounds_offset[1]);
}
}
var bones = {}
if (data.object.bones) {
@ -203,26 +211,11 @@ var codec = new Codec('bedrock_old', {
})
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)
//Width
var radius = Math.max(
visible_box.max.x,
visible_box.max.z,
-visible_box.min.x,
-visible_box.min.z
) * 0.9
if (Math.abs(radius) === Infinity) {
radius = 0
}
entitymodel.visible_bounds_width = Math.ceil((radius*2) / 16)
//Height
entitymodel.visible_bounds_height = Math.ceil(((visible_box.max.y - visible_box.min.y) * 0.9) / 16)
if (Math.abs(entitymodel.visible_bounds_height) === Infinity) {
entitymodel.visible_bounds_height = 0;
}
entitymodel.visible_bounds_offset = [0, entitymodel.visible_bounds_height/2 , 0]
let visible_box = calculateVisibleBox();
entitymodel.visible_bounds_width = visible_box[0];
entitymodel.visible_bounds_height = visible_box[1];
entitymodel.visible_bounds_offset = [0, visible_box[2] , 0]
}
if (bones.length) {
entitymodel.bones = bones
@ -258,18 +251,12 @@ var codec = new Codec('bedrock_old', {
pe_list._data.search_text = ''
}
function rotateOriginCoord(pivot, y, z) {
return [
pivot[1] - pivot[2] + z,
pivot[2] - y + pivot[1]
]
}
function create_thumbnail(model_entry, isize) {
var included_bones = []
model_entry.object.bones.forEach(function(b) {
included_bones.push(b.name)
})
var thumbnail = new Jimp(48, 48, 0x00000000, function(err, image) {
new Jimp(48, 48, 0x00000000, function(err, image) {
model_entry.object.bones.forEach(function(b) {
//var rotate_bone = false;
//if (b.name === 'body' &&
@ -400,6 +387,7 @@ var codec = new Codec('bedrock_old', {
export() {
var scope = this;
Blockbench.export({
resource_id: 'model',
type: this.name,
extensions: [this.extension],
name: this.fileName(),
@ -492,6 +480,7 @@ var format = new ModelFormat({
}
})
//Object.defineProperty(format, 'single_texture', {get: _ => !settings.layered_textures.value})
codec.format = format;
BARS.defineActions(function() {

View File

@ -1,6 +1,99 @@
(function() {
function buildAnimationTracks() {
let tracks = [];
Animator.animations.forEach(animation => {
let tracks = [];
for (var uuid in animation.animators) {
let animator = animation.animators[uuid];
if (animator instanceof BoneAnimator && animator.getGroup()) {
for (var channel of animator.channels) {
if (animator[channel] && animator[channel].length) {
let times = [];
let values = [];
let keyframes = animator[channel].slice();
// Sampling calculated (molang) values
let contains_script
for (var kf of keyframes) {
if (isNaN(kf.x) || isNaN(kf.y) || isNaN(kf.z)) {
contains_script = true; break;
}
}
if (contains_script) {
var last_values;
for (var time = 0; time < animation.length; time += 1/24) {
Timeline.time = time;
let values = animator.interpolate(channel, false)
if (!values.equals(last_values) && !keyframes.find(kf => Math.epsilon(kf.time, time, 1/24))) {
let new_keyframe = new Keyframe({
time, channel,
x: values[0], y: values[1], z: values[2],
})
new_keyframe.animator = animator;
keyframes.push(new_keyframe)
}
last_values = values;
}
}
keyframes.sort((a, b) => a.time - b.time)
// Sampling rotation steps that exceed 180 degrees
if (channel === 'rotation' && !contains_script) {
let original_keyframes = keyframes.slice();
original_keyframes.forEach((kf, i) => {
let next = original_keyframes[i+1]
if (!next) return;
let k1 = kf.getArray();
let k2 = next.getArray();
let max_diff = Math.max(Math.abs(k1[0] - k2[0]), Math.abs(k1[1] - k2[1]), Math.abs(k1[2] - k2[2]));
let steps = Math.floor(max_diff / 180 + 1);
for (var step = 1; step < steps; step++) {
Timeline.time = kf.time + (next.time - kf.time) * (step/steps);
let values = animator.interpolate(channel, false)
let new_keyframe = new Keyframe({
time: Timeline.time, channel,
x: values[0], y: values[1], z: values[2],
})
new_keyframe.animator = animator;
keyframes.splice(keyframes.indexOf(kf) + step, 0, new_keyframe);
}
})
}
keyframes.forEach(kf => {
times.push(kf.time);
Timeline.time = kf.time;
kf.getFixed().toArray(values, values.length);
})
let trackType = THREE.VectorKeyframeTrack;
if (channel === 'rotation') {
trackType = THREE.QuaternionKeyframeTrack;
channel = 'quaternion';
}
let track = new trackType(animator.group.mesh.uuid+'.'+channel, times, values, THREE.InterpolateLinear);
tracks.push(track);
}
}
} else if (animator instanceof BoneAnimator) {
console.log(`Skip export of track ${uuid.substr(0, 7)}... - No connected bone`)
}
}
if (tracks.length) {
let clip = new THREE.AnimationClip(animation.name, animation.length, tracks)
tracks.push(clip);
} else {
console.log(`Skip export of animation ${animation.name} - No tracks generated`)
}
})
return tracks;
}
var codec = new Codec('gltf', {
name: 'GLTF Model',
@ -21,45 +114,9 @@ var codec = new Codec('gltf', {
Animator.showDefaultPose();
}
if (options.animations !== false) {
Animator.animations.forEach(animation => {
let tracks = [];
for (var uuid in animation.animators) {
let animator = animation.animators[uuid];
if (animator instanceof BoneAnimator && animator.getGroup()) {
for (var channel of animator.channels) {
if (animator[channel] && animator[channel].length) {
let times = [];
let values = [];
let keyframes = animator[channel].slice();
keyframes.sort((a, b) => a.time - b.time)
keyframes.forEach(kf => {
times.push(kf.time);
Timeline.time = kf.time;
kf.getFixed().toArray(values, values.length);
})
let trackType = THREE.VectorKeyframeTrack;
if (channel === 'rotation') {
trackType = THREE.QuaternionKeyframeTrack;
channel = 'quaternion';
}
let track = new trackType(animator.group.mesh.uuid+'.'+channel, times, values, THREE.InterpolateLinear);
tracks.push(track);
}
}
} else if (animator instanceof BoneAnimator) {
console.log(`Skip export of track ${uuid.substr(0, 7)}... - No connected bone`)
}
}
if (tracks.length) {
let clip = new THREE.AnimationClip(animation.name, animation.length, tracks)
animations.push(clip);
} else {
console.log(`Skip export of animation ${animation.name} - No tracks generated`)
}
})
animations = buildAnimationTracks();
}
exporter.parse(gl_scene, (json) => {
scope.dispatchEvent('compile', {model: json, options});
@ -82,14 +139,17 @@ var codec = new Codec('gltf', {
export() {
var scope = codec;
scope.compile(0, content => {
Blockbench.export({
type: scope.name,
extensions: [scope.extension],
name: scope.fileName(),
startpath: scope.startPath(),
content,
custom_writer: isApp ? (a, b) => scope.write(a, b) : null,
}, path => scope.afterDownload(path))
setTimeout(_ => {
Blockbench.export({
resource_id: 'gltf',
type: scope.name,
extensions: [scope.extension],
name: scope.fileName(),
startpath: scope.startPath(),
content,
custom_writer: isApp ? (a, b) => scope.write(a, b) : null,
}, path => scope.afterDownload(path))
}, 20)
})
}
})

View File

@ -27,6 +27,7 @@ class ModelFormat {
this.box_uv = false;
this.optional_box_uv = false;
this.single_texture = false;
this.animated_textures = false;
this.bone_rig = false;
this.centered_grid = false;
this.rotate_cubes = false;
@ -47,6 +48,7 @@ class ModelFormat {
Merge.boolean(this, data, 'box_uv');
Merge.boolean(this, data, 'optional_box_uv');
Merge.boolean(this, data, 'single_texture');
Merge.boolean(this, data, 'animated_textures');
Merge.boolean(this, data, 'bone_rig');
Merge.boolean(this, data, 'centered_grid');
Merge.boolean(this, data, 'rotate_cubes');
@ -81,6 +83,9 @@ class ModelFormat {
preview.loadAnglePreset(DefaultCameraPresets[preview.angle+1])
}
})
uv_dialog.all_editors.forEach(editor => {
editor.img.style.objectFit = Format.animated_textures ? 'cover' : 'fill';
})
updateSelection()
Modes.vue.$forceUpdate()
Canvas.updateRenderSides()
@ -257,6 +262,7 @@ class Codec {
export() {
var scope = this;
Blockbench.export({
resource_id: 'model',
type: scope.name,
extensions: [scope.extension],
name: scope.fileName(),
@ -324,60 +330,6 @@ class Codec {
}
}
//New
function resetProject() {
Blockbench.dispatchEvent('reset_project');
if (Toolbox.selected.id !== 'move_tool') BarItems.move_tool.select();
Format = 0;
elements.length = 0;
Outliner.root.purge();
Canvas.materials.length = 0;
textures.length = 0;
selected.length = 0;
Screencam.stopTimelapse();
Group.all.empty();
Group.selected = undefined;
Cube.all.empty();
Cube.selected.empty();
Locator.all.empty();
Locator.selected.empty();
Blockbench.display_settings = display = {};
Project.name = Project.parent = Project.geometry_name = Project.description = '';
Project.texture_width = Project.texture_height = 16;
Project.ambientocclusion = true;
Project.front_gui_light = false;
ModelMeta.save_path = ModelMeta.export_path = ModelMeta.animation_path = ModelMeta.name = '';
ModelMeta.saved = true;
Prop.project_saved = true;
Prop.added_models = 0;
Canvas.updateAll();
Outliner.vue.$forceUpdate();
texturelist.$forceUpdate();
Undo.history.length = 0;
Undo.index = 0;
Undo.current_save = null;
Painter.current = {};
Animator.animations.purge();
Timeline.animators.purge();
Animator.selected = undefined;
$('#var_placeholder_area').val('');
}
function newProject(format, force) {
if (force || showSaveDialog()) {
resetProject();
Modes.options.edit.select();
if (format instanceof ModelFormat) {
format.select();
}
Blockbench.dispatchEvent('new_project');
return true;
} else {
return false;
}
}
//Import
function setupDragHandlers() {
@ -399,7 +351,7 @@ function setupDragHandlers() {
'plugin',
{extensions: ['bbplugin', 'js']},
function(files) {
loadPluginFromFile(files[0])
new Plugin().loadFromFile(files[0], true)
}
)
Blockbench.addDragHandler(
@ -661,8 +613,8 @@ function uploadSketchfabModel() {
title: 'dialog.sketchfab_uploader.title',
width: 540,
form: {
token: {label: 'dialog.sketchfab_uploader.token', value: settings.sketchfab_token.value},
about_token: {type: 'text', text: tl('dialog.sketchfab_uploader.about_token', ['[sketchfab.com/settings/password](https://sketchfab.com/settings/password)'])},
token: {label: 'dialog.sketchfab_uploader.token', value: settings.sketchfab_token.value, type: 'password'},
about_token: {type: 'info', text: tl('dialog.sketchfab_uploader.about_token', ['[sketchfab.com/settings/password](https://sketchfab.com/settings/password)'])},
name: {label: 'dialog.sketchfab_uploader.name'},
description: {label: 'dialog.sketchfab_uploader.description', type: 'textarea'},
tags: {label: 'dialog.sketchfab_uploader.tags', placeholder: 'Tag1 Tag2'},
@ -696,24 +648,6 @@ function uploadSketchfabModel() {
settings.sketchfab_token.value = formResult.token
/*
var archive = new JSZip();
var model_data = Codecs.obj.compile({all_files: true})
archive.file('model.obj', model_data.obj)
archive.file('model.mtl', model_data.mtl)
for (var key in model_data.images) {
var tex = model_data.images[key];
if (tex) {
archive.file(pathToName(tex.name) + '.png', tex.getBase64(), {base64: true});
}
}
archive.generateAsync({type: 'blob'}).then(blob => {
var file = new File([blob], 'model.zip', {type: 'application/x-zip-compressed'})
*/
Codecs.gltf.compile({animations: formResult.animations}, (content) => {
var blob = new Blob([content], {type: "text/plain;charset=utf-8"});
@ -870,142 +804,12 @@ BARS.defineActions(function() {
icon: 'icon-format_free',
rotate_cubes: true,
bone_rig: true,
centered_grid: false,
centered_grid: true,
optional_box_uv: true,
uv_rotation: true,
animation_mode: true,
})
//Project
new Action('project_window', {
icon: 'featured_play_list',
category: 'file',
condition: () => Format,
click: function () {
var dialog = new Dialog({
id: 'project',
title: 'dialog.project.title',
width: 540,
form: {
format: {type: 'text', label: 'data.format', text: Format.name||'unknown'},
name: {label: 'dialog.project.name', value: Project.name},
parent: {label: 'dialog.project.parent', value: Project.parent, condition: !Format.bone_rig, list: ['paro', 'foo', 'bar']},
geometry_name: {label: 'dialog.project.geoname', value: Project.geometry_name, condition: Format.bone_rig},
ambientocclusion: {label: 'dialog.project.ao', type: 'checkbox', value: Project.ambientocclusion, condition: Format.id == 'java_block'},
box_uv: {label: 'dialog.project.box_uv', type: 'checkbox', value: Project.box_uv, condition: Format.optional_box_uv},
texture_width: {
label: 'dialog.project.width',
type: 'number',
value: Project.texture_width,
min: 1
},
texture_height: {
label: 'dialog.project.height',
type: 'number',
value: Project.texture_height,
min: 1
},
},
onConfirm: function(formResult) {
var save;
if (Project.box_uv != formResult.box_uv ||
Project.texture_width != formResult.texture_width ||
Project.texture_height != formResult.texture_height
) {
if (!Project.box_uv && !formResult.box_uv
&& (Project.texture_width != formResult.texture_width
|| Project.texture_height != formResult.texture_height)
) {
save = Undo.initEdit({uv_only: true, elements: Cube.all, uv_mode: true})
Cube.all.forEach(cube => {
for (var key in cube.faces) {
var uv = cube.faces[key].uv;
uv[0] *= formResult.texture_width / Project.texture_width;
uv[2] *= formResult.texture_width / Project.texture_width;
uv[1] *= formResult.texture_height / Project.texture_height;
uv[3] *= formResult.texture_height / Project.texture_height;
}
})
} else {
save = Undo.initEdit({uv_mode: true})
}
Project.texture_width = formResult.texture_width;
Project.texture_height = formResult.texture_height;
if (Format.optional_box_uv) Project.box_uv = formResult.box_uv;
Canvas.updateAllUVs()
updateSelection()
}
Project.name = formResult.name;
Project.parent = formResult.parent;
Project.geometry_name = formResult.geometry_name;
Project.ambientocclusion = formResult.ambientocclusion;
if (save) {
Undo.finishEdit('change global UV')
}
BARS.updateConditions()
if (EditSession.active) {
EditSession.sendAll('change_project_meta', JSON.stringify(Project));
}
dialog.hide()
}
})
dialog.show()
}
})
new Action('close_project', {
icon: 'cancel_presentation',
category: 'file',
condition: () => (!EditSession.active || EditSession.hosting) && Format,
click: function () {
if (showSaveDialog()) {
resetProject()
Modes.options.start.select()
Modes.vue.$forceUpdate()
Blockbench.dispatchEvent('close_project');
}
}
})
new Action('convert_project', {
icon: 'fas.fa-file-import',
category: 'file',
condition: () => (!EditSession.active || EditSession.hosting),
click: function () {
var options = {};
for (var key in Formats) {
if (key !== Format.id && key !== 'skin') {
options[key] = Formats[key].name;
}
}
var dialog = new Dialog({
id: 'convert_project',
title: 'dialog.convert_project.title',
width: 540,
form: {
text: {type: 'text', text: 'dialog.convert_project.text'},
format: {
label: 'data.format',
type: 'select',
default: Format.id,
options,
},
},
onConfirm: function(formResult) {
var format = Formats[formResult.format]
if (format && format != Format) {
format.convertTo()
}
dialog.hide()
}
})
dialog.show()
}
})
//Import
new Action('open_model', {
icon: 'assessment',
@ -1023,6 +827,7 @@ BARS.defineActions(function() {
}
}
Blockbench.import({
resource_id: 'model',
extensions: ['json', 'jem', 'jpm', 'java', 'bbmodel'],
type: 'Model',
startpath
@ -1037,6 +842,7 @@ BARS.defineActions(function() {
condition: _ => (Format.id == 'java_block'),
click: function () {
Blockbench.import({
resource_id: 'model',
extensions: ['json'],
type: 'JSON Model',
multiple: true,
@ -1054,6 +860,7 @@ BARS.defineActions(function() {
condition: _ => !Project.box_uv,
click: function () {
Blockbench.import({
resource_id: 'texture',
extensions: ['png'],
type: 'PNG Texture',
readtype: 'image'

View File

@ -9,7 +9,7 @@ var codec = new Codec('java_block', {
var clear_elements = []
var textures_used = []
var element_index_lut = []
var largerCubesNr = 0;
var overflow_cubes = [];
function computeCube(s) {
if (s.export == false) return;
@ -100,7 +100,7 @@ var codec = new Codec('java_block', {
element.faces = e_faces
function inVd(n) {
return n > 32 || n < -16
return n < -16 || n > 32;
}
if (inVd(element.from[0]) ||
inVd(element.from[1]) ||
@ -109,7 +109,7 @@ var codec = new Codec('java_block', {
inVd(element.to[1]) ||
inVd(element.to[2])
) {
largerCubesNr++;
overflow_cubes.push(s);
}
if (Object.keys(element.faces).length) {
clear_elements.push(element)
@ -155,17 +155,17 @@ var codec = new Codec('java_block', {
}
})
//if (options.prevent_dialog !== true && hasUnsavedTextures && settings.dialog_unsaved_textures.value) {
// Blockbench.showMessageBox({
// translateKey: 'unsaved_textures',
// icon: 'broken_image',
// })
//}
if (options.prevent_dialog !== true && largerCubesNr > 0 && settings.dialog_larger_cubes.value) {
if (options.prevent_dialog !== true && overflow_cubes.length > 0 && settings.dialog_larger_cubes.value) {
Blockbench.showMessageBox({
translateKey: 'model_clipping',
icon: 'settings_overscan',
message: tl('message.model_clipping.message', [largerCubesNr])
message: tl('message.model_clipping.message', [overflow_cubes.length]),
buttons: ['dialog.scale.select_overflow', 'dialog.ok']
}, (result) => {
if (result == 0) {
selected.splice(0, Infinity, ...overflow_cubes)
updateSelection();
}
})
}
if (options.prevent_dialog !== true && clear_elements.length && ['item/generated', 'item/handheld'].includes(Project.parent)) {
@ -246,7 +246,6 @@ var codec = new Codec('java_block', {
this.dispatchEvent('parse', {model});
var previous_length = add ? elements.length : 0
var previous_texture_length = add ? textures.length : 0
var new_cubes = [];
var new_textures = [];
@ -445,6 +444,7 @@ var format = new ModelFormat({
rotation_limit: true,
optional_box_uv: true,
uv_rotation: true,
animated_textures: true,
display_mode: true,
codec
})

View File

@ -1,150 +1,313 @@
(function() {
function F(num) {
var s = trimFloatNumber(num) + '';
if (!s.includes('.')) {
s += '.0';
}
return s+'F';
}
function I(num) {
return Math.floor(num)
}
const Templates = {
'1.12': {
name: '1.12',
flip_y: true,
integer_size: true,
file:
`// Made with Blockbench %(bb_version)
// Exported for Minecraft version 1.12
// Paste this class into your mod and generate all required imports
public class %(identifier) extends ModelBase {
%(fields)
public %(identifier)() {
textureWidth = %(texture_width);
textureHeight = %(texture_height);
%(content)
}
@Override
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) {
%(renderers)
}
public void setRotationAngle(ModelRenderer modelRenderer, float x, float y, float z) {
modelRenderer.rotateAngleX = x;
modelRenderer.rotateAngleY = y;
modelRenderer.rotateAngleZ = z;
}
}`,
field: `private final ModelRenderer %(bone);`,
bone:
`%(bone) = new ModelRenderer(this);
%(bone).setRotationPoint(%(x), %(y), %(z));
?(has_parent)%(parent).addChild(%(bone));
?(has_rotation)setRotationAngle(%(bone), %(rx), %(ry), %(rz));
%(cubes)`,
renderer: `%(bone).render(f5);`,
cube: `%(bone).cubeList.add(new ModelBox(%(bone), %(uv_x), %(uv_y), %(x), %(y), %(z), %(dx), %(dy), %(dz), %(inflate), %(mirror)));`,
},
'1.14': {
name: '1.14',
flip_y: true,
integer_size: true,
file:
`// Made with Blockbench %(bb_version)
// Exported for Minecraft version 1.14
// Paste this class into your mod and generate all required imports
public class %(identifier) extends EntityModel {
%(fields)
public %(identifier)() {
textureWidth = %(texture_width);
textureHeight = %(texture_height);
%(content)
}
@Override
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) {
%(renderers)
}
public void setRotationAngle(RendererModel modelRenderer, float x, float y, float z) {
modelRenderer.rotateAngleX = x;
modelRenderer.rotateAngleY = y;
modelRenderer.rotateAngleZ = z;
}
}`,
field: `private final RendererModel %(bone);`,
bone:
`%(bone) = new RendererModel(this);
%(bone).setRotationPoint(%(x), %(y), %(z));
?(has_parent)%(parent).addChild(%(bone));
?(has_rotation)setRotationAngle(%(bone), %(rx), %(ry), %(rz));
%(cubes)`,
renderer: `%(bone).render(f5);`,
cube: `%(bone).cubeList.add(new ModelBox(%(bone), %(uv_x), %(uv_y), %(x), %(y), %(z), %(dx), %(dy), %(dz), %(inflate), %(mirror)));`,
},
'1.15': {
name: '1.15',
flip_y: true,
integer_size: false,
radians: true,
file:
`// Made with Blockbench %(bb_version)
// Exported for Minecraft version 1.15
// Paste this class into your mod and generate all required imports
public class %(identifier) extends EntityModel<Entity> {
%(fields)
public %(identifier)() {
textureWidth = %(texture_width);
textureHeight = %(texture_height);
%(content)
}
@Override
public void setRotationAngles(Entity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch){
//previously the render function, render code was moved to a method below
}
@Override
public void render(MatrixStack matrixStack, IVertexBuilder buffer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha){
%(renderers)
}
public void setRotationAngle(ModelRenderer modelRenderer, float x, float y, float z) {
modelRenderer.rotateAngleX = x;
modelRenderer.rotateAngleY = y;
modelRenderer.rotateAngleZ = z;
}
}`,
field: `private final ModelRenderer %(bone);`,
bone:
`%(bone) = new ModelRenderer(this);
%(bone).setRotationPoint(%(x), %(y), %(z));
?(has_parent)%(parent).addChild(%(bone));
?(has_rotation)setRotationAngle(%(bone), %(rx), %(ry), %(rz));
%(cubes)`,
renderer: `%(bone).render(matrixStack, buffer, packedLight, packedOverlay);`,
cube: `%(bone).setTextureOffset(%(uv_x), %(uv_y)).addBox(%(x), %(y), %(z), %(dx), %(dy), %(dz), %(inflate), %(mirror));`,
},
get(key, version = Project.modded_entity_version) {
let temp = Templates[version][key];
if (typeof temp === 'string') temp = temp.replace(/\t\t\t/g, '');
return temp;
},
keepLine(line) {
return line.replace(/\?\(\w+\)/, '');
},
getVariableRegex(name) {
return new RegExp(`%\\(${name}\\)`, 'g');
}
}
function getIdentifier() {
return Project.geometry_name.replace(/[\s-]+/g, '_') || 'custom_model';
}
var codec = new Codec('modded_entity', {
name: 'Java Class',
extension: 'java',
remember: true,
compile(options) {
function F(num) {
var s = trimFloatNumber(num) + '';
if (!s.includes('.')) {
s += '.0';
}
return s+'F';
}
var bone_nr = 1
var model_id = Project.geometry_name.replace(/[\s-]+/g, '_') || 'custom_model';
var all_groups = getAllGroups();
var renderers = {};
let R = Templates.getVariableRegex;
let identifier = getIdentifier();
var ver = settings.class_export_version.value == '1.14' ? 1 : 0;
var rendererName = ver == 1 ? 'RendererModel' : 'ModelRenderer'
var loose_cubes = []
Outliner.root.forEach(obj => {
if (obj.type === 'cube') {
loose_cubes.push(obj)
}
let all_groups = getAllGroups();
let loose_cubes = [];
Cube.all.forEach(cube => {
if (cube.parent == 'root') loose_cubes.push(cube)
})
if (loose_cubes.length) {
var group = {
all_groups.push({
name: 'bb_main',
rotation: [0, 0, 0],
origin: [0, 0, 0],
parent: 'root',
children: loose_cubes
}
all_groups.splice(0, 0, group)
}
all_groups.forEach((g) => {
//model += `\nthis.bone${bone_nr} = new ModelRenderer`
var id = g.name
bone_nr++;
if (g.export === false) return;
var bone = {
id: id,
rootBone: g.parent instanceof Group == false,
lines: [
`${id} = new ${rendererName}(this);`,//Texture Offset
]
}
var origin = [-g.origin[0], -g.origin[1], g.origin[2]]
//Rotation
if (!g.rotation.allEqual(0)) {
bone.lines.push(
`setRotationAngle(${id}, ${
F(Math.degToRad(-g.rotation[0])) }, ${
F(Math.degToRad(-g.rotation[1])) }, ${
F(Math.degToRad(g.rotation[2])) });`
)
}
//Parent
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;
var values = [
''+id,
Math.floor(obj.uv_offset[0]),
Math.floor(obj.uv_offset[1]),
F(g.origin[0] - obj.to[0]),
F(-obj.from[1] - obj.size(1, true) + g.origin[1]),
F(obj.from[2] - g.origin[2]),
obj.size(0, true),
obj.size(1, true),
obj.size(2, true),
F(obj.inflate),
obj.mirror_uv
]
bone.lines.push(
`${id}.cubeList.add(new ModelBox(${ values.join(', ') }));`
)
})
renderers[id] = bone;
})
var model = (settings.credit.value
? '// '+settings.credit.value+'\n'
: '')+
'// Paste this code into your mod.\n' +
'// Make sure to generate all required imports\n'
if (ver == 1) {
model += '\npublic class '+model_id+' extends EntityModel {';
} else {
model += '\npublic class '+model_id+' extends ModelBase {';
}
for (var r_id in renderers) {
model += `\n private final ${rendererName} ${r_id};`;
}
let model = Templates.get('file');
model += '\n'+
'\n public '+model_id+'() {'+
'\n textureWidth = '+ (Project.texture_width || 32) +';'+
'\n textureHeight = '+ (Project.texture_height|| 32) +';\n';
model = model.replace(R('bb_version'), Blockbench.version);
model = model.replace(R('identifier'), identifier);
model = model.replace(R('texture_width'), Project.texture_width);
model = model.replace(R('texture_height'), Project.texture_height);
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) {'
for (var r_id in renderers) {
if (renderers[r_id].rootBone) {
model += `\n ${r_id}.render(f5);`;
model = model.replace(R('fields'), () => {
let group_snippets = [];
for (var group of all_groups) {
if (group instanceof Group === false || !group.export) continue;
let snippet = Templates.get('field')
.replace(R('bone'), group.name)
group_snippets.push(snippet);
}
}
model +=
'\n }'+
`\n public void setRotationAngle(${rendererName} modelRenderer, float x, float y, float z) {`+
'\n modelRenderer.rotateAngleX = x;'+
'\n modelRenderer.rotateAngleY = y;'+
'\n modelRenderer.rotateAngleZ = z;'+
'\n }'+
'\n}';
return group_snippets.join('\n\t')
});
model = model.replace(R('content'), () => {
let group_snippets = [];
for (var group of all_groups) {
if (group instanceof Group === false || !group.export) continue;
let snippet = Templates.get('bone')
.replace(R('bone'), group.name)
.replace(/\n\?\(has_rotation\).+/, group.rotation.allEqual(0) ? '' : Templates.keepLine)
if (Templates.get('radians')) {
snippet = snippet
.replace(R('rx'), F(Math.degToRad(-group.rotation[0])))
.replace(R('ry'), F(Math.degToRad(-group.rotation[1])))
.replace(R('rz'), F(Math.degToRad(group.rotation[2])))
} else {
snippet = snippet
.replace(R('rx'), F(-group.rotation[0]))
.replace(R('ry'), F(-group.rotation[1]))
.replace(R('rz'), F(group.rotation[2]))
}
var origin = group.origin.slice();
if (group.parent instanceof Group) {
origin.V3_subtract(group.parent.origin)
}
origin[0] *= -1;
if (Templates.get('flip_y')) {
origin[1] *= -1;
if (group.parent instanceof Group === false) {
origin[1] += 24
}
}
snippet = snippet
.replace(R('x'), F(origin[0]))
.replace(R('y'), F(origin[1]))
.replace(R('z'), F(origin[2]))
.replace(/\n\?\(has_parent\).+/, group.parent instanceof Group ? Templates.keepLine : '')
.replace(R('parent'), group.parent.name)
.replace(R('cubes'), () => {
let cube_snippets = [];
for (var cube of group.children) {
if (cube instanceof Cube === false || !cube.export) continue;
let c_snippet = Templates.get('cube')
.replace(R('bone'), group.name)
.replace(R('uv_x'), I(cube.uv_offset[0]))
.replace(R('uv_y'), I(cube.uv_offset[1]))
.replace(R('inflate'), F(cube.inflate))
.replace(R('mirror'), cube.mirror_uv)
if (Templates.get('flip_y')) {
c_snippet = c_snippet
.replace(R('x'), F(group.origin[0] - cube.to[0]) )
.replace(R('y'), F(-cube.from[1] - cube.size(1) + group.origin[1]) )
.replace(R('z'), F(cube.from[2] - group.origin[2]) )
} else {
c_snippet = c_snippet
.replace(R('x'), F(group.origin[0] - cube.to[0]) )
.replace(R('y'), F(cube.from[1] - group.origin[1]) )
.replace(R('z'), F(cube.from[2] - group.origin[2]) )
}
if (Templates.get('integer_size')) {
c_snippet = c_snippet
.replace(R('dx'), I(cube.size(0, true)) )
.replace(R('dy'), I(cube.size(1, true)) )
.replace(R('dz'), I(cube.size(2, true)) )
} else {
c_snippet = c_snippet
.replace(R('dx'), F(cube.size(0)) )
.replace(R('dy'), F(cube.size(1)) )
.replace(R('dz'), F(cube.size(2)) )
}
cube_snippets.push(c_snippet);
}
return cube_snippets.join('\n');
})
.replace(/\n/g, '\n\t\t')
group_snippets.push(snippet);
}
return group_snippets.join('\n\n\t\t')
});
model = model.replace(R('renderers'), () => {
let group_snippets = [];
for (var group of all_groups) {
if (group instanceof Group === false || !group.export) continue;
let snippet = Templates.get('renderer')
.replace(R('bone'), group.name)
group_snippets.push(snippet);
}
return group_snippets.join('\n\t\t')
});
this.dispatchEvent('compile', {model, options});
return model;
@ -160,11 +323,6 @@ var codec = new Codec('modded_entity', {
}
})
var getArgs = function(input) {
var i = input.search('(')
var args = input.substr(i+1).replace(/\)$/, '');
return args.split(/, ?/);
}
function parseScheme(scheme, input) {
scheme = scheme.replace(/\(/g, '\\(').replace(/\)/g, '\\)').replace(/\./g, '\\.');
var parts = scheme.split('$');
@ -269,6 +427,18 @@ var codec = new Codec('modded_entity', {
last_uv = [match[1], match[2]];
} else
if (
parseScheme('$v = new ModelRenderer(this)', line)
) {
// Blockbench for 1.15
if (!bones[match[0]]) {
bones[match[0]] = new Group({
name: match[0],
origin: [0, 0, 0]
}).init();
}
} else
if (parseScheme('$v.setRotationPoint($f, $f, $f)', line)) {
var bone = bones[match[0]]
if (bone) {
@ -288,6 +458,7 @@ var codec = new Codec('modded_entity', {
child.addTo(parent);
child.origin.V3_add(parent.origin)
child.origin[1] -= 24;
child.children.forEach(cube => {
if (cube instanceof Cube) {
cube.from[0] += parent.origin[0]; cube.to[0] += parent.origin[0];
@ -347,6 +518,30 @@ var codec = new Codec('modded_entity', {
cube.addTo(bones[match[0]]).init();
} else
if (parseScheme('$v.setTextureOffset($i, $i).addBox($f, $f, $f, $f, $f, $f, $f, $b)', line)
) {
var group = bones[match[0]];
var cube = new Cube({
name: match[0],
uv_offset: [match[1], match[2]],
from: [
group.origin[0] - match[3] - match[6],
group.origin[1] - match[4] - match[7],
group.origin[2] + match[5]
],
inflate: match[9],
mirror_uv: match[10]
})
cube.extend({
to: [
cube.from[0] + match[6],
cube.from[1] + match[7],
cube.from[2] + match[8],
]
});
cube.addTo(bones[match[0]]).init();
} else
//Rotation
if (parseScheme('setRotationAngle($v, $f, $f, $f)', line)) {
@ -423,8 +618,12 @@ var codec = new Codec('modded_entity', {
}
})
Canvas.updateAll();
},
fileName() {
return getIdentifier();
}
})
codec.templates = Templates;
var format = new ModelFormat({
id: 'modded_entity',
@ -432,12 +631,13 @@ var format = new ModelFormat({
codec,
box_uv: true,
single_texture: true,
integer_size: true,
bone_rig: true,
centered_grid: true,
})
Object.defineProperty(format, 'integer_size', {get: _ => Templates.get('integer_size')})
codec.format = format;
BARS.defineActions(function() {
new Action({
id: 'export_class_entity',

View File

@ -210,6 +210,7 @@ var codec = new Codec('obj', {
var scope = this;
if (isApp) {
Blockbench.export({
resource_id: 'obj',
type: this.name,
extensions: [this.extension],
name: this.fileName(),

View File

@ -259,6 +259,7 @@ var format = new ModelFormat({
centered_grid: true,
codec
})
Object.defineProperty(format, 'integer_size', {get: _ => Format.box_uv})
codec.format = format;

View File

@ -241,6 +241,7 @@ BARS.defineActions(function() {
condition: () => (Format.id == 'optifine_entity' || Format.id == 'optifine_part'),
click: function () {
Blockbench.import({
resource_id: 'model',
extensions: ['jpm'],
type: 'JPM Entity Part Model',
multiple: true,

238
js/io/project.js Normal file
View File

@ -0,0 +1,238 @@
const Project = {
name : '',
parent : '',
geometry_name : '',
description : '',
_box_uv : false,
get box_uv() {return Project._box_uv},
set box_uv(v) {
if (Project._box_uv != v) {
Project._box_uv = v;
switchBoxUV(v);
}
},
get texture_width() {return Project._texture_width},
get texture_height() {return Project._texture_height},
set texture_width(n) {
n = parseInt(n)||16
Vue.nextTick(updateProjectResolution)
Project._texture_width = n;
},
set texture_height(n) {
n = parseInt(n)||16
Vue.nextTick(updateProjectResolution)
Project._texture_height = n;
},
_texture_width : 16,
_texture_height : 16,
ambientocclusion: true,
front_gui_light: false,
visible_box: [1, 1, 0], /*width, height, y*/
modded_entity_version: '1.15',
get optional_box_uv() {
return Format.optional_box_uv;
}
}
//New
function resetProject() {
Blockbench.dispatchEvent('reset_project');
if (Toolbox.selected.id !== 'move_tool') BarItems.move_tool.select();
Format = 0;
elements.length = 0;
Outliner.root.purge();
Canvas.materials.length = 0;
textures.length = 0;
selected.length = 0;
Screencam.stopTimelapse();
Group.all.empty();
Group.selected = undefined;
Cube.all.empty();
Cube.selected.empty();
Locator.all.empty();
Locator.selected.empty();
Blockbench.display_settings = display = {};
Project.name = Project.parent = Project.geometry_name = Project.description = '';
Project.texture_width = Project.texture_height = 16;
Project.ambientocclusion = true;
Project.front_gui_light = false;
Project.modded_entity_version = '1.15';
Project.visible_box.splice(0, Infinity, ...[1, 1, 0])
ModelMeta.save_path = ModelMeta.export_path = ModelMeta.animation_path = ModelMeta.name = '';
ModelMeta.saved = true;
Prop.project_saved = true;
Prop.added_models = 0;
Canvas.updateAll();
Outliner.vue.$forceUpdate();
texturelist.$forceUpdate();
Undo.history.length = 0;
Undo.index = 0;
Undo.current_save = null;
Painter.current = {};
Animator.animations.purge();
Timeline.animators.purge();
Animator.selected = undefined;
$('#var_placeholder_area').val('');
}
function newProject(format, force) {
if (force || showSaveDialog()) {
resetProject();
Modes.options.edit.select();
if (format instanceof ModelFormat) {
format.select();
}
Blockbench.dispatchEvent('new_project');
return true;
} else {
return false;
}
}
BARS.defineActions(function() {
new Action('project_window', {
icon: 'featured_play_list',
category: 'file',
condition: () => Format,
click: function () {
let modded_entity_options = {}
for (var key in Codecs.modded_entity.templates) {
if (Codecs.modded_entity.templates[key] instanceof Function == false) {
modded_entity_options[key] = Codecs.modded_entity.templates[key].name;
}
}
var dialog = new Dialog({
id: 'project',
title: 'dialog.project.title',
width: 540,
form: {
format: {type: 'info', label: 'data.format', text: Format.name||'unknown'},
name: {label: 'dialog.project.name', value: Project.name},
parent: {label: 'dialog.project.parent', value: Project.parent, condition: !Format.bone_rig, list: ['paro', 'foo', 'bar']},
geometry_name: {label: 'dialog.project.geoname', value: Project.geometry_name, condition: Format.bone_rig},
modded_entity_version: {label: 'dialog.project.modded_entity_version', type: 'select', default: Project.modded_entity_version, options: modded_entity_options, condition: Format.id == 'modded_entity'},
ambientocclusion: {label: 'dialog.project.ao', type: 'checkbox', value: Project.ambientocclusion, condition: Format.id == 'java_block'},
box_uv: {label: 'dialog.project.box_uv', type: 'checkbox', value: Project.box_uv, condition: Format.optional_box_uv},
texture_width: {
label: 'dialog.project.width',
type: 'number',
value: Project.texture_width,
min: 1
},
texture_height: {
label: 'dialog.project.height',
type: 'number',
value: Project.texture_height,
min: 1
},
},
onConfirm: function(formResult) {
var save;
if (Project.box_uv != formResult.box_uv ||
Project.texture_width != formResult.texture_width ||
Project.texture_height != formResult.texture_height
) {
if (!Project.box_uv && !formResult.box_uv
&& (Project.texture_width != formResult.texture_width
|| Project.texture_height != formResult.texture_height)
) {
save = Undo.initEdit({uv_only: true, elements: Cube.all, uv_mode: true})
Cube.all.forEach(cube => {
for (var key in cube.faces) {
var uv = cube.faces[key].uv;
uv[0] *= formResult.texture_width / Project.texture_width;
uv[2] *= formResult.texture_width / Project.texture_width;
uv[1] *= formResult.texture_height / Project.texture_height;
uv[3] *= formResult.texture_height / Project.texture_height;
}
})
} else {
save = Undo.initEdit({uv_mode: true})
}
Project.texture_width = formResult.texture_width;
Project.texture_height = formResult.texture_height;
if (Format.optional_box_uv) Project.box_uv = formResult.box_uv;
Canvas.updateAllUVs()
updateSelection()
}
Project.name = formResult.name;
Project.parent = formResult.parent;
Project.geometry_name = formResult.geometry_name;
Project.ambientocclusion = formResult.ambientocclusion;
if (formResult.modded_entity_version) Project.modded_entity_version = formResult.modded_entity_version;
if (save) {
Undo.finishEdit('change global UV')
}
BARS.updateConditions()
if (EditSession.active) {
EditSession.sendAll('change_project_meta', JSON.stringify(Project));
}
dialog.hide()
}
})
dialog.show()
}
})
new Action('close_project', {
icon: 'cancel_presentation',
category: 'file',
condition: () => (!EditSession.active || EditSession.hosting) && Format,
click: function () {
if (showSaveDialog()) {
resetProject()
Modes.options.start.select()
Modes.vue.$forceUpdate()
Blockbench.dispatchEvent('close_project');
}
}
})
new Action('convert_project', {
icon: 'fas.fa-file-import',
category: 'file',
condition: () => (!EditSession.active || EditSession.hosting),
click: function () {
var options = {};
for (var key in Formats) {
if (key !== Format.id && key !== 'skin') {
options[key] = Formats[key].name;
}
}
var dialog = new Dialog({
id: 'convert_project',
title: 'dialog.convert_project.title',
width: 540,
form: {
text: {type: 'info', text: 'dialog.convert_project.text'},
format: {
label: 'data.format',
type: 'select',
default: Format.id,
options,
},
},
onConfirm: function(formResult) {
var format = Formats[formResult.format]
if (format && format != Format) {
format.convertTo()
}
dialog.hide()
}
})
dialog.show()
}
})
})

View File

@ -74,7 +74,7 @@ const codec = new Codec('skin_model', {
this.dispatchEvent('compile', {model: entitymodel, options});
return entitymodel
},
parse(data, resolution, texture_path) {
parse(data, resolution, texture_path, pose = true) {
this.dispatchEvent('parse', {model: data});
Project.geometry_name = data.name;
Project.texture_width = data.texturewidth || 64;
@ -91,7 +91,7 @@ const codec = new Codec('skin_model', {
var group = new Group({
name: b.name,
origin: b.pivot,
rotation: b.rotation
rotation: (pose && b.pose) ? b.pose : b.rotation
}).init()
group.isOpen = true;
bones[b.name] = group
@ -176,7 +176,7 @@ const codec = new Codec('skin_model', {
EditSession.initNewModel()
},
})
codec.compile = null;
const format = new ModelFormat({
@ -211,7 +211,7 @@ function generateTemplate(width = 64, height = 64, name = 'name', eyes) {
canvas.height = height;
Cube.all.forEach(cube => {
TextureGenerator.paintCubeBoxTemplate(cube, texture, canvas);
TextureGenerator.paintCubeBoxTemplate(cube, texture, canvas, null, !!cube.inflate);
})
if (eyes) {
var res_multiple = canvas.width/Project.texture_width;
@ -256,7 +256,8 @@ const skin_dialog = new Dialog({
cod: 'Cod',
cow: 'Cow',
creeper: 'Creeper',
dolphin: 'Dolphin',
dolphin_bedrock: 'Dolphin (Bedrock)',
dolphin_java: 'Dolphin (Java)',
enderdragon: 'Ender Dragon',
enderman: 'Enderman',
endermite: 'Endermite',
@ -293,6 +294,7 @@ const skin_dialog = new Dialog({
snowgolem: 'Snowgolem',
spider: 'Spider',
squid: 'Squid',
strider: 'Strider',
tropicalfish_a: 'Tropicalfish A',
tropicalfish_b: 'Tropicalfish B',
turtle: 'Turtle',
@ -319,13 +321,14 @@ const skin_dialog = new Dialog({
type: 'file',
extensions: ['png'],
filetype: 'PNG',
}
},
pose: {type: 'checkbox', label: 'dialog.skin.pose', value: true}
},
draggable: true,
onConfirm(result) {
if (newProject(format)) {
var model = JSON.parse(skin_presets[result.model]);
codec.parse(model, result.resolution/16, result.texture);
codec.parse(model, result.resolution/16, result.texture, result.pose);
}
this.hide();
},
@ -374,7 +377,7 @@ skin_presets.steve = `{
"name": "Head",
"color": 1,
"pivot": [0, 24, 0],
"rotation": [-6, 5, 0],
"pose": [-6, 5, 0],
"cubes": [
{"name": "Head", "origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]},
{"name": "Hat Layer", "visibility": false, "origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [32, 0], "inflate": 0.5}
@ -393,7 +396,7 @@ skin_presets.steve = `{
"name": "Right Arm",
"color": 5,
"pivot": [-5, 22, 0],
"rotation": [-10, 0, 0],
"pose": [-10, 0, 0],
"cubes": [
{"name": "Right Arm", "origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]},
{"name": "Right Arm Layer", "visibility": false, "origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 32], "inflate": 0.25}
@ -403,7 +406,7 @@ skin_presets.steve = `{
"name": "Left Arm",
"color": 0,
"pivot": [5, 22, 0],
"rotation": [12, 0, 0],
"pose": [12, 0, 0],
"cubes": [
{"name": "Left Arm", "origin": [4, 12, -2], "size": [4, 12, 4], "uv": [32, 48]},
{"name": "Left Arm Layer", "visibility": false, "origin": [4, 12, -2], "size": [4, 12, 4], "uv": [48, 48], "inflate": 0.25}
@ -413,7 +416,7 @@ skin_presets.steve = `{
"name": "Right Leg",
"color": 6,
"pivot": [-1.9, 12, 0],
"rotation": [11, 0, 2],
"pose": [11, 0, 2],
"cubes": [
{"name": "Right Leg", "origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]},
{"name": "Right Leg Layer", "visibility": false, "origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 32], "inflate": 0.25}
@ -423,7 +426,7 @@ skin_presets.steve = `{
"name": "Left Leg",
"color": 7,
"pivot": [1.9, 12, 0],
"rotation": [-10, 0, -2],
"pose": [-10, 0, -2],
"cubes": [
{"name": "Left Leg", "origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [16, 48]},
{"name": "Left Leg Layer", "visibility": false, "origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [0, 48], "inflate": 0.25}
@ -444,7 +447,7 @@ skin_presets.alex = `{
"name": "Head",
"color": 1,
"pivot": [0, 24, 0],
"rotation": [-6, 5, 0],
"pose": [-6, 5, 0],
"cubes": [
{"name": "Head", "origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]},
{"name": "Hat Layer", "visibility": false, "origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [32, 0], "inflate": 0.5}
@ -463,7 +466,7 @@ skin_presets.alex = `{
"name": "Right Arm",
"color": 5,
"pivot": [-5, 22, 0],
"rotation": [-10, 0, 0],
"pose": [-10, 0, 0],
"cubes": [
{"name": "Right Arm", "origin": [-7, 12, -2], "size": [3, 12, 4], "uv": [40, 16]},
{"name": "Right Arm Layer", "visibility": false, "origin": [-7, 12, -2], "size": [3, 12, 4], "uv": [40, 32], "inflate": 0.25}
@ -473,7 +476,7 @@ skin_presets.alex = `{
"name": "Left Arm",
"color": 0,
"pivot": [5, 22, 0],
"rotation": [12, 0, 0],
"pose": [12, 0, 0],
"cubes": [
{"name": "Left Arm", "origin": [4, 12, -2], "size": [3, 12, 4], "uv": [32, 48]},
{"name": "Left Arm Layer", "visibility": false, "origin": [4, 12, -2], "size": [3, 12, 4], "uv": [48, 48], "inflate": 0.25}
@ -483,7 +486,7 @@ skin_presets.alex = `{
"name": "Right Leg",
"color": 6,
"pivot": [-1.9, 12, 0],
"rotation": [11, 0, 2],
"pose": [11, 0, 2],
"cubes": [
{"name": "Right Leg", "origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]},
{"name": "Right Leg Layer", "visibility": false, "origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 32], "inflate": 0.25}
@ -493,7 +496,7 @@ skin_presets.alex = `{
"name": "Left Leg",
"color": 7,
"pivot": [1.9, 12, 0],
"rotation": [-10, 0, -2],
"pose": [-10, 0, -2],
"cubes": [
{"name": "Left Leg", "origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [16, 48]},
{"name": "Left Leg Layer", "visibility": false, "origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [0, 48], "inflate": 0.25}
@ -615,7 +618,7 @@ skin_presets.bat = `{
"name": "rightWing",
"parent": "body",
"pivot": [0, 24, 0],
"rotation": [0, -10, 0],
"pose": [0, -10, 0],
"cubes": [
{"name": "rightWing", "origin": [-12, 7, 1.5], "size": [10, 16, 1], "uv": [42, 0]}
]
@ -624,7 +627,7 @@ skin_presets.bat = `{
"name": "rightWingTip",
"parent": "rightWing",
"pivot": [-12, 23, 1.5],
"rotation": [0, -15, 0],
"pose": [0, -15, 0],
"cubes": [
{"name": "rightWingTip", "origin": [-20, 10, 1.5], "size": [8, 12, 1], "uv": [24, 16]}
]
@ -633,7 +636,7 @@ skin_presets.bat = `{
"name": "leftWing",
"parent": "body",
"pivot": [0, 24, 0],
"rotation": [0, 10, 0],
"pose": [0, 10, 0],
"mirror": true,
"cubes": [
{"name": "leftWing", "origin": [2, 7, 1.5], "size": [10, 16, 1], "uv": [42, 0]}
@ -643,7 +646,7 @@ skin_presets.bat = `{
"name": "leftWingTip",
"parent": "leftWing",
"pivot": [12, 23, 1.5],
"rotation": [0, 15, 0],
"pose": [0, 15, 0],
"mirror": true,
"cubes": [
{"name": "leftWingTip", "origin": [12, 10, 1.5], "size": [8, 12, 1], "uv": [24, 16]}
@ -1284,7 +1287,7 @@ skin_presets.creeper = `{
}
]
}`;
skin_presets.dolphin = `{
skin_presets.dolphin_bedrock = `{
"name": "dolphin",
"texturewidth": 64,
"textureheight": 64,
@ -1316,6 +1319,7 @@ skin_presets.dolphin = `{
"name": "tail",
"parent": "body",
"pivot": [0, 2.5, 11],
"pose": [-5, 0, 0],
"cubes": [
{"name": "tail", "origin": [-2, 0, 10], "size": [4, 5, 11], "uv": [0, 33]}
]
@ -1324,6 +1328,7 @@ skin_presets.dolphin = `{
"name": "tail_fin",
"parent": "tail",
"pivot": [0, 2.5, 20],
"pose": [-8, 0, 0],
"cubes": [
{"name": "tail_fin", "origin": [-5, 2, 19], "size": [10, 1, 6], "uv": [0, 49]}
]
@ -1357,6 +1362,81 @@ skin_presets.dolphin = `{
}
]
}`;
skin_presets.dolphin_java = `{
"name": "dolphin",
"texturewidth": 64,
"textureheight": 64,
"bones": [
{
"name": "body",
"pivot": [0, 0, -3],
"cubes": [
{"name": "body", "origin": [-4, 0, -3], "size": [8, 7, 13], "uv": [22, 0]}
]
},
{
"name": "head",
"parent": "body",
"pivot": [0, 0, -3],
"cubes": [
{"name": "head", "origin": [-4, 0, -9], "size": [8, 7, 6], "uv": [0, 0]}
]
},
{
"name": "nose",
"parent": "head",
"pivot": [0, 0, -13],
"cubes": [
{"name": "nose", "origin": [-1, 0, -13], "size": [2, 2, 4], "uv": [0, 13]}
]
},
{
"name": "tail",
"parent": "body",
"pivot": [0, 2.5, 11],
"pose": [-5, 0, 0],
"cubes": [
{"name": "tail", "origin": [-2, 0, 10], "size": [4, 5, 11], "uv": [0, 19]}
]
},
{
"name": "tail_fin",
"parent": "tail",
"pivot": [0, 2.5, 20],
"pose": [-8, 0, 0],
"cubes": [
{"name": "tail_fin", "origin": [-5, 2, 19], "size": [10, 1, 6], "uv": [19, 20]}
]
},
{
"name": "back_fin",
"parent": "body",
"pivot": [0, 7, 2],
"rotation": [60, 0, 0],
"cubes": [
{"name": "back_fin", "origin": [-0.5, 3.75, 1.5], "size": [1, 4, 5], "uv": [51, 0]}
]
},
{
"name": "left_fin",
"parent": "body",
"pivot": [3, 2, 2],
"rotation": [55, 0, 107],
"cubes": [
{"name": "left_fin", "origin": [3, 2, 0.5], "size": [1, 4, 7], "uv": [48, 20]}
]
},
{
"name": "right_fin",
"parent": "body",
"pivot": [-3, 2, 2],
"rotation": [55, 0, -107],
"cubes": [
{"name": "left_fin", "origin": [-4, 2, 0.5], "size": [1, 4, 7], "uv": [48, 20], "mirror": true}
]
}
]
}`;
skin_presets.enderdragon = `{
"name": "enderdragon",
"texturewidth": 256,
@ -1365,7 +1445,7 @@ skin_presets.enderdragon = `{
{
"name": "neck",
"pivot": [0, 7, -8],
"rotation": [-5, 0, 0],
"pose": [-5, 0, 0],
"cubes": [
{"name": "neck", "origin": [-5, 2, -18], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "neck", "origin": [-1, 12, -16], "size": [2, 4, 6], "uv": [48, 0]}
@ -1375,7 +1455,7 @@ skin_presets.enderdragon = `{
"name": "neck2",
"parent": "neck",
"pivot": [0, 7, -18],
"rotation": [5, 0, 0],
"pose": [5, 0, 0],
"cubes": [
{"name": "neck", "origin": [-5, 2, -28], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "neck", "origin": [-1, 12, -26], "size": [2, 4, 6], "uv": [48, 0]}
@ -1385,7 +1465,7 @@ skin_presets.enderdragon = `{
"name": "neck3",
"parent": "neck2",
"pivot": [0, 7, -28],
"rotation": [5, 0, 0],
"pose": [5, 0, 0],
"cubes": [
{"name": "neck", "origin": [-5, 2, -38], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "neck", "origin": [-1, 12, -36], "size": [2, 4, 6], "uv": [48, 0]}
@ -1395,7 +1475,7 @@ skin_presets.enderdragon = `{
"name": "neck4",
"parent": "neck3",
"pivot": [0, 7, -38],
"rotation": [5, 0, 0],
"pose": [5, 0, 0],
"cubes": [
{"name": "neck", "origin": [-5, 2, -48], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "neck", "origin": [-1, 12, -46], "size": [2, 4, 6], "uv": [48, 0]}
@ -1405,7 +1485,7 @@ skin_presets.enderdragon = `{
"name": "neck5",
"parent": "neck4",
"pivot": [0, 7, -48],
"rotation": [5, 0, 0],
"pose": [5, 0, 0],
"cubes": [
{"name": "neck", "origin": [-5, 2, -58], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "neck", "origin": [-1, 12, -56], "size": [2, 4, 6], "uv": [48, 0]}
@ -1415,7 +1495,7 @@ skin_presets.enderdragon = `{
"name": "head",
"parent": "neck5",
"pivot": [0, 7, -58],
"rotation": [5, 0, 0],
"pose": [5, 0, 0],
"cubes": [
{"name": "head", "origin": [-6, 3, -88], "size": [12, 5, 16], "uv": [176, 44]},
{"name": "head", "origin": [-8, -1, -74], "size": [16, 16, 16], "uv": [112, 30]},
@ -1429,7 +1509,7 @@ skin_presets.enderdragon = `{
"name": "jaw",
"parent": "head",
"pivot": [0, 3, -71],
"rotation": [15, 0, 0],
"pose": [15, 0, 0],
"cubes": [
{"name": "jaw", "origin": [-6, -1, -88], "size": [12, 4, 16], "uv": [176, 65]}
]
@ -1447,41 +1527,41 @@ skin_presets.enderdragon = `{
{
"name": "wing",
"pivot": [-12, 19, 2],
"rotation": [0, 10, 10],
"pose": [0, 10, 10],
"cubes": [
{"name": "wing", "origin": [-68, 15, -2], "size": [56, 8, 8], "uv": [112, 88]},
{"name": "wing", "origin": [-68, 19, 4], "size": [56, 0, 56], "uv": [-56, 88]}
{"name": "wing", "origin": [-68, 19, 4], "size": [56, 0, 56], "uv": [-56, 88], "inflate": 0.01}
]
},
{
"name": "wingtip",
"parent": "wing",
"pivot": [-68, 19, 0],
"rotation": [0, 0, -20],
"pose": [0, 0, -20],
"cubes": [
{"name": "wingtip", "origin": [-124, 17, 0], "size": [56, 4, 4], "uv": [112, 136]},
{"name": "wingtip", "origin": [-124, 19, 4], "size": [56, 0, 56], "uv": [-56, 144]}
{"name": "wingtip", "origin": [-124, 19, 4], "size": [56, 0, 56], "uv": [-56, 144], "inflate": 0.01}
]
},
{
"name": "wing1",
"pivot": [12, 19, 2],
"rotation": [0, -10, -10],
"pose": [0, -10, -10],
"mirror": true,
"cubes": [
{"name": "wing1", "origin": [12, 15, -2], "size": [56, 8, 8], "uv": [112, 88]},
{"name": "wing1", "origin": [12, 19, 4], "size": [56, 0, 56], "uv": [-56, 88]}
{"name": "wing1", "origin": [12, 19, 4], "size": [56, 0, 56], "uv": [-56, 88], "inflate": 0.01}
]
},
{
"name": "wingtip1",
"parent": "wing1",
"pivot": [68, 19, 0],
"rotation": [0, 0, 20],
"pose": [0, 0, 20],
"mirror": true,
"cubes": [
{"name": "wingtip1", "origin": [68, 17, 0], "size": [56, 4, 4], "uv": [112, 136]},
{"name": "wingtip1", "origin": [68, 19, 4], "size": [56, 0, 56], "uv": [-56, 144]}
{"name": "wingtip1", "origin": [68, 19, 4], "size": [56, 0, 56], "uv": [-56, 144], "inflate": 0.01}
]
},
{
@ -1606,7 +1686,7 @@ skin_presets.enderdragon = `{
"name": "tail2",
"parent": "tail",
"pivot": [0, 14, 66],
"rotation": [1, 0, 0],
"pose": [1, 0, 0],
"cubes": [
{"name": "tail", "origin": [-5, 9, 66], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "tail", "origin": [-1, 19, 68], "size": [2, 4, 6], "uv": [48, 0]}
@ -1616,7 +1696,7 @@ skin_presets.enderdragon = `{
"name": "tail3",
"parent": "tail2",
"pivot": [0, 14, 76],
"rotation": [1, 0, 0],
"pose": [1, 0, 0],
"cubes": [
{"name": "tail", "origin": [-5, 9, 76], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "tail", "origin": [-1, 19, 78], "size": [2, 4, 6], "uv": [48, 0]}
@ -1626,7 +1706,7 @@ skin_presets.enderdragon = `{
"name": "tail4",
"parent": "tail3",
"pivot": [0, 14, 86],
"rotation": [1, 0, 0],
"pose": [1, 0, 0],
"cubes": [
{"name": "tail", "origin": [-5, 9, 86], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "tail", "origin": [-1, 19, 88], "size": [2, 4, 6], "uv": [48, 0]}
@ -1636,7 +1716,7 @@ skin_presets.enderdragon = `{
"name": "tail5",
"parent": "tail4",
"pivot": [0, 14, 96],
"rotation": [2, 0, 0],
"pose": [2, 0, 0],
"cubes": [
{"name": "tail", "origin": [-5, 9, 96], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "tail", "origin": [-1, 19, 98], "size": [2, 4, 6], "uv": [48, 0]}
@ -1646,7 +1726,7 @@ skin_presets.enderdragon = `{
"name": "tail6",
"parent": "tail5",
"pivot": [0, 14, 106],
"rotation": [3, 0, 0],
"pose": [3, 0, 0],
"cubes": [
{"name": "tail", "origin": [-5, 9, 106], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "tail", "origin": [-1, 19, 108], "size": [2, 4, 6], "uv": [48, 0]}
@ -1656,7 +1736,7 @@ skin_presets.enderdragon = `{
"name": "tail7",
"parent": "tail6",
"pivot": [0, 14, 116],
"rotation": [3, 0, 0],
"pose": [3, 0, 0],
"cubes": [
{"name": "tail", "origin": [-5, 9, 116], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "tail", "origin": [-1, 19, 118], "size": [2, 4, 6], "uv": [48, 0]}
@ -1666,7 +1746,7 @@ skin_presets.enderdragon = `{
"name": "tail8",
"parent": "tail7",
"pivot": [0, 14, 126],
"rotation": [1, 0, 0],
"pose": [1, 0, 0],
"cubes": [
{"name": "tail", "origin": [-5, 9, 126], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "tail", "origin": [-1, 19, 128], "size": [2, 4, 6], "uv": [48, 0]}
@ -1676,7 +1756,7 @@ skin_presets.enderdragon = `{
"name": "tail9",
"parent": "tail8",
"pivot": [0, 14, 136],
"rotation": [-1, 0, 0],
"pose": [-1, 0, 0],
"cubes": [
{"name": "tail", "origin": [-5, 9, 136], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "tail", "origin": [-1, 19, 138], "size": [2, 4, 6], "uv": [48, 0]}
@ -1686,7 +1766,7 @@ skin_presets.enderdragon = `{
"name": "tail10",
"parent": "tail9",
"pivot": [0, 14, 146],
"rotation": [-2, 0, 0],
"pose": [-2, 0, 0],
"cubes": [
{"name": "tail", "origin": [-5, 9, 146], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "tail", "origin": [-1, 19, 148], "size": [2, 4, 6], "uv": [48, 0]}
@ -1696,7 +1776,7 @@ skin_presets.enderdragon = `{
"name": "tail11",
"parent": "tail10",
"pivot": [0, 14, 156],
"rotation": [-3, 0, 0],
"pose": [-3, 0, 0],
"cubes": [
{"name": "tail", "origin": [-5, 9, 156], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "tail", "origin": [-1, 19, 158], "size": [2, 4, 6], "uv": [48, 0]}
@ -1706,7 +1786,7 @@ skin_presets.enderdragon = `{
"name": "tail12",
"parent": "tail11",
"pivot": [0, 14, 166],
"rotation": [-3, 0, 0],
"pose": [-3, 0, 0],
"cubes": [
{"name": "tail", "origin": [-5, 9, 166], "size": [10, 10, 10], "uv": [192, 104]},
{"name": "tail", "origin": [-1, 19, 168], "size": [2, 4, 6], "uv": [48, 0]}
@ -4310,6 +4390,96 @@ skin_presets.squid = `{
}
]
}`;
skin_presets.strider = `{
"name": "strider",
"texturewidth": 64,
"textureheight": 128,
"eyes": [
[17, 25, 2, 1],
[29, 25, 2, 1]
],
"bones": [
{
"name": "body",
"pivot": [0, 17, 0],
"cubes": [
{"name": "cube", "origin": [-8, 17, -8], "size": [16, 14, 16], "uv": [0, 0]}
]
},
{
"name": "right_bristles_1",
"parent": "body",
"pivot": [-8, 30, 0],
"rotation": [0, 0, -60],
"mirror": true,
"cubes": [
{"name": "cube", "origin": [-20, 30, -8], "size": [12, 0, 16], "uv": [4, 33]}
]
},
{
"name": "left_bristles_1",
"parent": "body",
"pivot": [8, 30, 0],
"rotation": [0, 0, 60],
"cubes": [
{"name": "cube", "origin": [8, 30, -8], "size": [12, 0, 16], "uv": [4, 33]}
]
},
{
"name": "right_bristles_2",
"parent": "body",
"pivot": [-8, 26, 0],
"rotation": [0, 0, -60],
"mirror": true,
"cubes": [
{"name": "cube", "origin": [-20, 26, -8], "size": [12, 0, 16], "uv": [4, 49]}
]
},
{
"name": "left_bristles_2",
"parent": "body",
"pivot": [8, 26, 0],
"rotation": [0, 0, 60],
"cubes": [
{"name": "cube", "origin": [8, 26, -8], "size": [12, 0, 16], "uv": [4, 49]}
]
},
{
"name": "right_bristles_3",
"parent": "body",
"pivot": [-8, 21, 0],
"rotation": [0, 0, -60],
"mirror": true,
"cubes": [
{"name": "cube", "origin": [-20, 21, -8], "size": [12, 0, 16], "uv": [4, 65]}
]
},
{
"name": "left_bristles_3",
"parent": "body",
"pivot": [8, 21, 0],
"rotation": [0, 0, 60],
"cubes": [
{"name": "cube", "origin": [8, 21, -8], "size": [12, 0, 16], "uv": [4, 65]}
]
},
{
"name": "right_leg",
"pivot": [-4, 17, 0],
"cubes": [
{"name": "cube", "origin": [-6, 0, -2], "size": [4, 17, 4], "uv": [0, 32]}
]
},
{
"name": "left_leg",
"pivot": [4, 17, 0],
"mirror": true,
"cubes": [
{"name": "cube", "origin": [2, 0, -2], "size": [4, 17, 4], "uv": [0, 32]}
]
}
]
}`;
skin_presets.tropicalfish_a = `{
"name": "tropicalfish_a",
"texturewidth": 32,

View File

@ -109,7 +109,6 @@ class Cube extends NonGroup {
}
this.visibility = true;
this.autouv = 0
this.export = true;
this.parent = 'root';
this.faces = {
@ -133,6 +132,7 @@ class Cube extends NonGroup {
Merge.number(this, object, 'autouv')
Merge.number(this, object, 'color')
Merge.boolean(this, object, 'export')
Merge.boolean(this, object, 'locked')
Merge.boolean(this, object, 'visibility')
if (object.from) {
Merge.number(this.from, object.from, 0)
@ -292,6 +292,7 @@ class Cube extends NonGroup {
autouv: this.autouv,
color: this.color
}
el.locked = this.locked;
if (!this.visibility) el.visibility = false;
if (!this.export) el.export = false;
if (!this.shade) el.shade = false;
@ -666,40 +667,6 @@ class Cube extends NonGroup {
Canvas.updateUV(scope)
}
}
move(val, axis, move_origin) {
var size = this.size(axis);
val+= this.from[axis];
var in_box = val;
val = limitToBox(limitToBox(val, -this.inflate) + size, this.inflate) - size;
in_box = Math.abs(in_box - val) < 1e-4;
val -= this.from[axis];
//Move
if (Blockbench.globalMovement && Format.bone_rig && !move_origin) {
var m = new THREE.Vector3();
m[getAxisLetter(axis)] = val;
var rotation = new THREE.Quaternion();
this.mesh.getWorldQuaternion(rotation);
m.applyQuaternion(rotation.inverse());
this.from.V3_add(m.x, m.y, m.z);
this.to.V3_add(m.x, m.y, m.z);
} else {
this.to[axis] += val;
this.from[axis] += val;
}
//Origin
if (Blockbench.globalMovement && move_origin) {
this.origin[axis] += val;
}
this.mapAutoUV()
Canvas.adaptObjectPosition(this);
TickUpdates.selection = true;
return in_box;
}
moveVector(arr, axis) {
if (typeof arr == 'number') {
var n = arr;
@ -734,8 +701,8 @@ class Cube extends NonGroup {
if (!negative) {
var pos = limitToBox(this.from[axis] + modify(before), this.inflate);
if (Format.integer_size && Project.box_uv) {
pos = Math.round(pos);
if (Format.integer_size) {
pos = Math.round(pos-this.from[axis])+this.from[axis];
}
if (pos >= this.from[axis] || settings.negative_size.value || allow_negative) {
this.to[axis] = pos;
@ -744,6 +711,9 @@ class Cube extends NonGroup {
}
} else {
var pos = limitToBox(this.to[axis] + modify(-before), this.inflate);
if (Format.integer_size) {
pos = Math.round(pos-this.to[axis])+this.to[axis];
}
if (pos <= this.to[axis] || settings.negative_size.value || allow_negative) {
this.from[axis] = pos;
} else {
@ -811,8 +781,8 @@ class Cube extends NonGroup {
'delete'
]);
Cube.prototype.buttons = [
Outliner.buttons.remove,
Outliner.buttons.visibility,
Outliner.buttons.locked,
Outliner.buttons.export,
Outliner.buttons.shading,
Outliner.buttons.autouv

View File

@ -12,6 +12,7 @@ class Group extends OutlinerElement {
this.reset = false;
this.shade = true;
this.selected = false;
this.locked = false;
this.visibility = true;
this.export = true;
this.autouv = 0;
@ -44,6 +45,7 @@ class Group extends OutlinerElement {
}
Merge.number(this, object, 'autouv')
Merge.boolean(this, object, 'export')
Merge.boolean(this, object, 'locked')
Merge.boolean(this, object, 'visibility')
return this;
}
@ -69,7 +71,7 @@ class Group extends OutlinerElement {
}
select(event) {
var scope = this;
if (Blockbench.hasFlag('renaming')) return this;
if (Blockbench.hasFlag('renaming') || this.locked) return this;
if (!event) event = true
var allSelected = Group.selected === this && selected.length && this.matchesSelection()
@ -223,6 +225,7 @@ class Group extends OutlinerElement {
}
showContextMenu(event) {
Prop.active_panel = 'outliner'
if (this.locked) return this;
this.select(event)
this.menu.open(event, this)
return this;
@ -305,6 +308,7 @@ class Group extends OutlinerElement {
base_group.rotation.V3_set(this.rotation);
base_group.shade = this.shade;
base_group.reset = this.reset;
base_group.locked = this.locked;
base_group.visibility = this.visibility;
base_group.export = this.export;
base_group.autouv = this.autouv;
@ -321,6 +325,7 @@ class Group extends OutlinerElement {
obj.uuid = this.uuid;
obj.export = this.export;
obj.isOpen = this.isOpen === true;
obj.locked = this.locked;
obj.visibility = this.visibility;
obj.autouv = this.autouv;
}
@ -383,10 +388,10 @@ class Group extends OutlinerElement {
Group.prototype.type = 'group';
Group.prototype.icon = 'fa fa-folder';
Group.prototype.isParent = true;
Group.prototype.name_regex = () => Format.bone_rig ? 'a-zA-Z0-9_' : false;
Group.prototype.name_regex = () => Format.bone_rig ? 'a-z0-9_' : false;
Group.prototype.buttons = [
Outliner.buttons.remove,
Outliner.buttons.visibility,
Outliner.buttons.locked,
Outliner.buttons.export,
Outliner.buttons.shading,
Outliner.buttons.autouv

View File

@ -4,7 +4,6 @@ class Locator extends NonGroup {
super(data, uuid);
this.from = new Array().V3_set(0, 0, 0);
this.name = 'locator';
this.export = true;
if (data) {
this.extend(data);
@ -13,6 +12,7 @@ class Locator extends NonGroup {
extend(object) {
Merge.string(this, object, 'name');
this.sanitizeName();
Merge.boolean(this, object, 'locked')
Merge.boolean(this, object, 'export');
Merge.arrayVector(this, object, 'from');
return this;
@ -28,6 +28,7 @@ class Locator extends NonGroup {
var el = {
name: this.name,
export: this.export ? undefined : false,
locked: this.locked,
from: this.from,
uuid: this.uuid,
type: 'locator'
@ -61,32 +62,15 @@ class Locator extends NonGroup {
return pos;
}
move(val, axis) {
if (Blockbench.globalMovement) {
var m = new THREE.Vector3();
m[getAxisLetter(axis)] = val;
if (this.parent instanceof Group) {
var rotation = new THREE.Quaternion();
this.parent.mesh.getWorldQuaternion(rotation);
m.applyQuaternion(rotation.inverse());
}
this.from.V3_add(m);
} else {
this.from[axis] += val
}
TickUpdates.selection = true;
return this;
}
}
Locator.prototype.title = tl('data.locator');
Locator.prototype.type = 'locator';
Locator.prototype.icon = 'fa fa-anchor';
Locator.prototype.name_regex = 'a-zA-Z0-9_'
Locator.prototype.name_regex = 'a-z0-9_'
Locator.prototype.movable = true;
Locator.prototype.visibility = true;
Locator.prototype.buttons = [
Outliner.buttons.remove,
Outliner.buttons.locked,
Outliner.buttons.export
];
Locator.prototype.needsUniqueName = true;

View File

@ -4,6 +4,7 @@ const Outliner = {
elements: elements,
selected: selected,
buttons: {
/*
remove: {
id: 'remove',
title: tl('generic.delete'),
@ -23,6 +24,7 @@ const Outliner = {
Undo.finishEdit('remove', {elements: [], outliner: true, selection: true})
}
},
*/
visibility: {
id: 'visibility',
title: tl('switches.visibility'),
@ -30,9 +32,22 @@ const Outliner = {
icon_off: ' fa fa-eye-slash',
advanced_option: false,
click: function(obj) {
if (obj.locked) return;
obj.toggle('visibility')
}
},
locked: {
id: 'locked',
title: tl('switches.lock'),
icon: ' fas fa-lock',
icon_off: ' fas fa-lock-open',
advanced_option: true,
click: function(obj) {
if (obj.locked && Format.force_lock) return;
obj.toggle('locked')
updateSelection()
}
},
export: {
id: 'export',
title: tl('switches.export'),
@ -40,6 +55,7 @@ const Outliner = {
icon_off: ' far fa-window-close',
advanced_option: true,
click: function(obj) {
if (obj.locked) return;
obj.toggle('export')
}
},
@ -50,8 +66,12 @@ const Outliner = {
get icon_off() {return Project.box_uv ? 'fas fa-star-half-alt' : 'far fa-star'},
advanced_option: true,
click: function(obj) {
if (obj.locked) return;
obj.toggle('shade')
Canvas.updateUVs()
if (obj instanceof Cube && obj.visibility && !obj.selected) {
Canvas.updateUV(obj);
}
}
},
autouv: {
@ -62,6 +82,7 @@ const Outliner = {
icon_alt: ' fa fa-magic',
advanced_option: true,
click: function(obj) {
if (obj.locked) return;
var state = obj.autouv+1
if (state > 2) state = 0
@ -84,6 +105,8 @@ var markerColors = [
class OutlinerElement {
constructor(uuid) {
this.uuid = uuid || guid()
this.export = true;
this.locked = false;
}
init() {
this.constructor.all.safePush(this);
@ -298,6 +321,9 @@ class OutlinerElement {
case 'export':
return this.export
break;
case 'locked':
return this.locked
break;
case 'shading':
return this.shade
break;
@ -352,6 +378,7 @@ class NonGroup extends OutlinerElement {
}
showContextMenu(event) {
Prop.active_panel = 'outliner'
if (this.locked) return this;
if (!this.selected) {
this.select()
}
@ -381,8 +408,8 @@ class NonGroup extends OutlinerElement {
if (val === undefined) {
var val = !this[key]
}
this.forSelected((cube) => {
cube[key] = val
this.forSelected((el) => {
el[key] = val
}, 'toggle '+key)
if (key === 'visibility') {
Canvas.updateVisibility()
@ -640,13 +667,10 @@ function parseGroups(array, importGroup, startIndex) {
}
//Outliner
function loadOutlinerDraggable() {
if (Blockbench.isMobile) {
return;
}
function getOrder(loc, obj) {
if (!obj) {
return;
} else if (obj.type === 'group') {
} else if (obj instanceof Group) {
if (loc < 8) return -1;
if (loc > 24) return 1;
} else {
@ -663,6 +687,12 @@ function loadOutlinerDraggable() {
appendTo: 'body',
zIndex: 19,
cursorAt: {left: 5},
start(event, ui) {
if (event.target && event.target.parentNode) {
var element = Outliner.root.findRecursive('uuid', event.target.parentNode.id)
if (!element || element.locked) return false;
}
},
helper: function() {
var item = Outliner.root.findRecursive('uuid', $(this).attr('id'))
var helper = $(this).clone()
@ -682,7 +712,7 @@ function loadOutlinerDraggable() {
var tar = $('#cubes_list li .drag_hover.outliner_node').last()
var element = Outliner.root.findRecursive('uuid', tar.attr('id'))
if (element) {
var location = event.clientY - tar.position().top
var location = event.clientY - tar.offset().top
var order = getOrder(location, element)
tar.attr('order', order)
}
@ -701,7 +731,7 @@ function loadOutlinerDraggable() {
addClasses: false,
drop: function(event, ui) {
$('.outliner_node[order]').attr('order', null)
var location = event.clientY - $(event.target).position().top
var location = event.clientY - $(event.target).offset().top
$('.drag_hover').removeClass('drag_hover')
var target = Outliner.root.findRecursive('uuid', $(event.target).attr('id'))
@ -954,11 +984,11 @@ BARS.defineActions(function() {
width: 300,
singleButton: true,
form: {
cubes: {type: 'text', label: tl('dialog.model_stats.cubes'), text: ''+Cube.all.length },
locators: {type: 'text', label: tl('dialog.model_stats.locators'), text: ''+Locator.all.length, condition: Format.locators },
groups: {type: 'text', label: tl('dialog.model_stats.groups'), text: ''+Group.all.length },
vertices: {type: 'text', label: tl('dialog.model_stats.vertices'), text: ''+Cube.all.length*8 },
faces: {type: 'text', label: tl('dialog.model_stats.faces'), text: ''+face_count },
cubes: {type: 'info', label: tl('dialog.model_stats.cubes'), text: ''+Cube.all.length },
locators: {type: 'info', label: tl('dialog.model_stats.locators'), text: ''+Locator.all.length, condition: Format.locators },
groups: {type: 'info', label: tl('dialog.model_stats.groups'), text: ''+Group.all.length },
vertices: {type: 'info', label: tl('dialog.model_stats.vertices'), text: ''+Cube.all.length*8 },
faces: {type: 'info', label: tl('dialog.model_stats.faces'), text: ''+face_count },
}
})
dialog.show()
@ -989,6 +1019,21 @@ BARS.defineActions(function() {
Undo.finishEdit('sort_outliner')
}
})
new Action('unlock_everything', {
icon: 'fas.fa-key',
category: 'edit',
click: function () {
let locked = Outliner.elements.filter(el => el.locked);
let locked_groups = Group.all.filter(group => group.locked)
if (locked.length + locked_groups.length == 0) return;
Undo.initEdit({outliner: locked_groups.length > 0, elements: locked});
[...locked, ...locked_groups].forEach(el => {
el.locked = false;
})
Undo.finishEdit('unlock_everything')
}
})
new Action('element_colors', {
icon: 'check_box',
category: 'edit',

View File

@ -6,8 +6,8 @@
`<div v-on:contextmenu.prevent.stop="node.showContextMenu($event)"
class="outliner_object" v-on:dblclick.stop.self="renameOutliner()"
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) / 16) * 16 : 0)+'px'}"
v-bind:class="{ cube: node.type === 'cube', group: node.type === 'group', selected: node.selected }"
v-bind:style="{'padding-left': getIndentation(node) + 'px'}"
>` +
//Opener
@ -16,15 +16,16 @@
//Main
'<i :class="node.icon + (settings.outliner_colors.value ? \' ec_\'+node.color : \'\')" v-on:dblclick.stop="if (node.children && node.children.length) {node.isOpen = !node.isOpen;}"></i>' +
'<input type="text" class="cube_name tab_target" v-model="node.name" disabled>' +
'<a v-for="btn in node.buttons" class="ml5" href="javascript:" :title="btn.title" v-on:click.stop="btnClick(btn, node)" v-bind:class="{advanced_option: btn.advanced_option}">' +
'<a v-for="btn in node.buttons" class="ml5" href="javascript:" :title="btn.title" v-on:click.stop="btnClick(btn, node)" v-bind:class="{advanced_option: btn.advanced_option && (btn.id !== \'locked\' || !node.isIconEnabled(btn))}">' +
'<i v-if="node.isIconEnabled(btn) === true" :class="btn.icon"></i>' +
'<i v-else-if="node.isIconEnabled(btn) === \'alt\'" :class="btn.icon_alt"></i>' +
'<i v-else :class="btn.icon_off"></i>' +
'<i v-else :class="[btn.icon_off, \'icon_off\']"></i>' +
'</a>' +
'</div>' +
//Other Entries
'<ul v-show="node.isOpen">' +
'<vue-tree-item v-for="item in node.children" :node="item" v-key="item.uuid"></vue-tree-item>' +
`<div class="outliner_line_guide" v-if="node == Group.selected" v-bind:style="{left: getIndentation(node) + 'px'}"></div>` +
'</ul>' +
'</li>',
props: {
@ -51,6 +52,9 @@
if (typeof btn.click === 'function') {
btn.click(node);
}
},
getIndentation(node) {
return node.getDepth ? (limitNumber(node.getDepth(), 0, (Interface.Panels.outliner.width-124) / 16) * 16) : 0;
}
},
watch: {

View File

@ -14,7 +14,7 @@ const Plugins = {
devReload() {
var reloads = 0;
for (var i = Plugins.all.length-1; i >= 0; i--) {
if (Plugins.all[i].fromFile) {
if (Plugins.all[i].source == 'file') {
Plugins.all[i].reload()
reloads++;
}
@ -28,6 +28,8 @@ const Plugins = {
});
}
}
StateMemory.init('installed_plugins', 'array')
Plugins.installed = StateMemory.installed_plugins;
class Plugin {
constructor(id, data) {
@ -41,6 +43,7 @@ class Plugin {
this.icon = '';
this.variant = '';
this.min_version = '';
this.source = 'store'
this.extend(data)
@ -79,7 +82,7 @@ class Plugin {
scope.uninstall()
}
})
Plugins.installed.safePush(scope.id)
this.remember()
scope.installed = true;
return scope;
}
@ -127,9 +130,9 @@ class Plugin {
localStorage.setItem('plugin_dev_path', file.path)
Plugins.all.safePush(this)
scope.fromFile = true
scope.source = 'file'
if (isApp) {
$.getScript(file.path, function() {
$.getScript(file.path, () => {
if (window.plugin_data) {
scope.id = (plugin_data && plugin_data.id)||pathToName(file.path)
scope.extend(plugin_data)
@ -137,8 +140,7 @@ class Plugin {
}
scope.installed = true
scope.path = file.path
Plugins.installed.safePush(scope.path)
saveInstalledPlugins()
this.remember()
Plugins.sort()
})
} else {
@ -154,14 +156,52 @@ class Plugin {
scope.bindGlobalData()
}
scope.installed = true
Plugins.installed.safePush(scope.path)
saveInstalledPlugins()
this.remember()
Plugins.sort()
}
return this;
}
loadFromURL(url, first) {
if (first) {
if (isApp) {
if (!confirm(tl('message.load_plugin_app'))) return;
} else {
if (!confirm(tl('message.load_plugin_web'))) return;
}
}
this.id = pathToName(url)
Plugins.registered[this.id] = this;
localStorage.setItem('plugin_dev_path', url)
Plugins.all.safePush(this)
this.source = 'url';
$.getScript(url, () => {
if (window.plugin_data) {
this.id = (plugin_data && plugin_data.id)||pathToName(url)
this.extend(plugin_data)
this.bindGlobalData()
}
this.installed = true
this.path = url
this.remember()
Plugins.sort()
})
return this;
}
remember(id = this.id, path = this.path) {
if (Plugins.installed.find(plugin => plugin.id == this.id)) {
return this;
}
Plugins.installed.push({
id: id,
path: path,
source: this.source
})
StateMemory.save('installed_plugins')
return this;
}
uninstall() {
var scope = this;
try {
this.unload();
if (this.onuninstall) {
@ -171,14 +211,16 @@ class Plugin {
console.log('Error in unload or uninstall method: ', err);
}
delete Plugins.registered[this.id];
Plugins.installed.remove(this.fromFile ? this.path : this.id);
let in_installed = Plugins.installed.find(plugin => plugin.id == this.id);
Plugins.installed.remove(in_installed);
StateMemory.save('installed_plugins')
this.installed = false;
if (isApp && this.fromFile) {
if (isApp && this.source !== 'store') {
Plugins.all.remove(this)
} else if (isApp) {
var filepath = Plugins.path + scope.id + '.js'
var filepath = Plugins.path + this.id + '.js'
if (fs.existsSync(filepath)) {
fs.unlink(filepath, (err) => {
if (err) {
@ -187,7 +229,7 @@ class Plugin {
});
}
}
saveInstalledPlugins()
StateMemory.save('installed_plugins')
return this;
}
unload() {
@ -197,13 +239,22 @@ class Plugin {
return this;
}
reload() {
if (!isApp) return this;
if (!isApp && this.source == 'file') return this;
this.unload()
Plugins.all.remove(this)
//---------------
this.loadFromFile({path: this.path}, false)
if (this.source == 'file') {
this.loadFromFile({path: this.path}, false)
} else if (this.source == 'url') {
this.loadFromURL(this.path, false)
}
return this;
}
isReloadable() {
return (this.source == 'file' && isApp) || (this.source == 'url')
}
isInstallable() {
var scope = this;
var result =
@ -281,26 +332,47 @@ function loadInstalledPlugins() {
Plugins.loadingStep = true
return;
}
var storage_data = localStorage.getItem('installed_plugins')
if (storage_data !== null) {
Plugins.installed = JSON.parse(storage_data)
if (localStorage.getItem('installed_plugins')) {
var legacy_plugins = JSON.parse(localStorage.getItem('installed_plugins'))
if (legacy_plugins instanceof Array) {
legacy_plugins.forEach((string, i) => {
if (typeof string == 'string') {
if (string.match(/\.js$/)) {
Plugins.installed[i] = {
id: string.split(/[\\/]/).last().replace(/\.js$/, ''),
path: string,
source: 'file'
}
} else {
Plugins.installed[i] = {
id: string,
source: 'store'
}
}
}
})
}
StateMemory.save('installed_plugins')
localStorage.removeItem('installed_plugins')
}
if (Plugins.json !== undefined) {
if (Plugins.json instanceof Object) {
//From Store
for (var id in Plugins.json) {
var plugin = new Plugin(id, Plugins.json[id])
if (Plugins.installed.includes(id)) {
if (Plugins.installed.find(plugin => {
return plugin.id == id && plugin.source == 'store'
})) {
plugin.download()
}
}
Plugins.sort();
} else if (Plugins.installed.length > 0 && isApp) {
//Offline
Plugins.installed.forEach(function(id) {
Plugins.installed.forEach(function(plugin) {
if (id.substr(-3) !== '.js') {
//downloaded public plugin
var plugin = new Plugin(id).install(false, function() {
if (plugin.source == 'store') {
var plugin = new Plugin(plugin.id).install(false, function() {
this.extend(window.plugin_data)
Plugins.sort()
})
@ -309,22 +381,28 @@ function loadInstalledPlugins() {
}
if (Plugins.installed.length > 0) {
var loaded = []
Plugins.installed.forEach(function(id) {
Plugins.installed.forEachReverse(function(plugin) {
if (id && id.substr(-3) === '.js') {
if (plugin.source == 'file') {
//Dev Plugins
if (isApp && fs.existsSync(id)) {
var plugin = new Plugin(id).loadFromFile({path: id}, false)
loaded.push(pathToName(id))
if (isApp && fs.existsSync(plugin.path)) {
var plugin = new Plugin(plugin.id).loadFromFile({path: plugin.path}, false)
loaded.push('Local: '+ plugin.id || plugin.path)
} else {
Plugins.installed.remove(id)
Plugins.installed.remove(plugin)
}
} else if (id) {
loaded.push(id)
} else if (plugin.source == 'url') {
var plugin = new Plugin(plugin.id).loadFromFile({path: plugin.path}, false)
loaded.push('URL: '+ plugin.id || plugin.path)
} else {
loaded.push('Store: '+ plugin.id)
}
})
console.log(`Loaded ${loaded.length} plugin${pluralS(loaded.length)}`, loaded)
}
StateMemory.save('installed_plugins')
Plugins.Vue = new Vue({
el: '#plugin_list',
@ -353,12 +431,6 @@ function loadInstalledPlugins() {
}
})
}
function saveInstalledPlugins() {
localStorage.setItem('installed_plugins', JSON.stringify(Plugins.installed))
}
function loadPluginFromFile(file) {
var plugin = new Plugin().loadFromFile(file, true)
}
function switchPluginTabs(installed) {
$('#plugins .tab_bar > .open').removeClass('open')
if (installed) {
@ -391,13 +463,21 @@ BARS.defineActions(function() {
icon: 'fa-file-code',
category: 'blockbench',
click: function () {
var startpath = localStorage.getItem('plugin_dev_path') || undefined;
Blockbench.import({
resource_id: 'dev_plugin',
extensions: ['js'],
type: 'Blockbench Plugin',
startpath
}, function(files) {
loadPluginFromFile(files[0])
new Plugin().loadFromFile(files[0], true)
})
}
})
new Action('load_plugin_from_url', {
icon: 'cloud_download',
category: 'blockbench',
click: function () {
Blockbench.textPrompt('URL', '', url => {
new Plugin().loadFromURL(url, true)
})
}
})

View File

@ -489,10 +489,64 @@ const Canvas = {
}
iterate(el, elmesh)
},
getLayeredMaterial() {
var vertShader = `
varying vec2 vUv;
void main()
{
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}`
var fragShader = `
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D tOne;
uniform sampler2D tSec;
varying vec2 vUv;
void main(void)
{
vec3 c;
vec4 Ca = texture2D(tOne, vUv);
vec4 Cb = texture2D(tSec, vUv);
c = Ca.rgb * Ca.a + Cb.rgb * Cb.a * (1.0 - Ca.a); // blending equation
gl_FragColor= vec4(c, 1.0);
}`
var uniforms = {
tOne: { type: "t", value: textures[1].getMaterial().map },
tSec: { type: "t", value: textures[0].getMaterial().map }
};
var material_shh = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertShader,
fragmentShader: fragShader
});
return material_shh;
/*
todo:
Issues:
Painting is one pixel delayed
Painting doesn't occur on selected texture
needs setting
needs to work with 0-3+ textures
*/
},
adaptObjectFaces(cube, mesh) {
if (!mesh) mesh = cube.mesh
if (!mesh) return;
if (!Prop.wireframe) {
if (Prop.wireframe) {
mesh.material = Canvas.wireframeMaterial
/*} else if (settings.layered_textures.value && Format && Format.id.includes('bedrock')) {
mesh.material = Canvas.getLayeredMaterial();*/
} else {
var materials = []
Canvas.face_order.forEach(function(face) {
@ -509,8 +563,6 @@ const Canvas = {
}
})
mesh.material = materials
} else {
mesh.material = Canvas.wireframeMaterial
}
},
updateUV(obj, animation) {

View File

@ -86,6 +86,22 @@ const DefaultCameraPresets = [
zoom: 0.5,
locked_angle: 5,
default: true
},
{
name: 'camera_angle.isometric_right',
projection: 'orthographic',
position: [-64, 64*0.8165, -64],
target: [0, 0, 0],
zoom: 0.5,
default: true
},
{
name: 'camera_angle.isometric_left',
projection: 'orthographic',
position: [64, 64*0.8165, -64],
target: [0, 0, 0],
zoom: 0.5,
default: true
}
]
@ -155,12 +171,30 @@ class Preview {
this.controls.mouseButtons.ZOOM = undefined;
//Renderer
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas,
antialias: true,
alpha: true,
preserveDrawingBuffer: true
});
try {
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas,
antialias: true,
alpha: true,
preserveDrawingBuffer: true
});
} catch (err) {
document.querySelector('#loading_error_detail').innerHTML = 'Error creating WebGL context. Try to update your graphics drivers.';
if (isApp) {
var {BrowserWindow} = require('electron').remote
new BrowserWindow({
icon:'icon.ico',
backgroundColor: '#ffffff',
title: 'Blockbench GPU Information',
webPreferences: {
webgl: true,
webSecurity: true,
nodeIntegration: true
}
}).loadURL('chrome://gpu')
}
throw err;
}
this.renderer.setClearColor( 0x000000, 0 )
this.renderer.setSize(500, 400);
@ -243,7 +277,18 @@ class Preview {
}
var intersects = this.raycaster.intersectObjects( objects );
if (intersects.length > 0) {
var intersect = intersects[0].object
if (intersects.length > 1 && Toolbox.selected.id == 'vertex_snap_tool') {
var intersect;
for (var sct of intersects) {
if (sct.object.isVertex) {
intersect = sct.object;
break;
}
}
if (!intersect) intersect = intersects[0].object;
} else {
var intersect = intersects[0].object
}
if (intersect.isElement) {
this.controls.hasMoved = true
var obj = elements.findInArray('uuid', intersects[0].object.name)
@ -400,6 +445,14 @@ class Preview {
}
newAnglePreset() {
let scope = this;
let position = scope.camera.position.toArray();
let target = scope.controls.target.toArray();
position.forEach((v, i) => {
position[i] = Math.round(v*100)/100
})
target.forEach((v, i) => {
target[i] = Math.round(v*100)/100
})
let dialog = new Dialog({
id: 'save_angle',
@ -411,7 +464,9 @@ class Preview {
unset: 'generic.unset',
perspective: 'dialog.save_angle.projection.perspective',
orthographic: 'dialog.save_angle.projection.orthographic'
}}
}},
position: {label: 'dialog.save_angle.position', type: 'vector', dimensions: 3, value: position},
target: {label: 'dialog.save_angle.target', type: 'vector', dimensions: 3, value: target},
},
onConfirm: function(formResult) {
@ -420,8 +475,8 @@ class Preview {
let preset = {
name: formResult.name,
projection: formResult.projection,
position: scope.camera.position.toArray(),
target: scope.controls.target.toArray(),
position: formResult.position,
target: formResult.target,
}
if (this.isOrtho) preset.zoom = this.camOrtho.zoom;
@ -488,7 +543,15 @@ class Preview {
var data = this.raycast(event);
if (data) {
//this.static_rclick = false
if (Toolbox.selected.selectCubes && Modes.selected.selectCubes && data.type === 'cube') {
if (data.cube && data.cube.locked) {
$('#preview').css('cursor', 'not-allowed')
function resetCursor() {
$('#preview').css('cursor', (Toolbox.selected.cursor ? Toolbox.selected.cursor : 'default'))
removeEventListeners(document, 'mouseup touchend', resetCursor, false)
}
addEventListeners(document, 'mouseup touchend', resetCursor, false)
} else if (Toolbox.selected.selectCubes && Modes.selected.selectCubes && data.type === 'cube') {
if (Toolbox.selected.selectFace) {
main_uv.setFace(data.face, false)
}
@ -524,8 +587,10 @@ class Preview {
}
}
mousemove(event) {
var data = this.raycast(event);
if (Settings.get('highlight_cubes')) updateCubeHighlights(data && data.cube);
if (Settings.get('highlight_cubes')) {
var data = this.raycast(event);
updateCubeHighlights(data && data.cube);
}
}
raycastMouseCoords(x,y) {
var scope = this;
@ -888,6 +953,7 @@ class Preview {
return [
{icon: 'folder', name: 'menu.preview.background.load', click: function(preview) {
Blockbench.import({
resource_id: 'preview_background',
extensions: ['png', 'jpg', 'jpeg', 'bmp', 'tiff', 'tif', 'gif'],
type: 'Image',
readtype: 'image'
@ -1044,13 +1110,23 @@ const Screencam = {
cancel: 0
}, function(result) {
if (result === 1) {
Blockbench.export()
ElecDialogs.showSaveDialog(currentwindow, {filters: [ {name: tl('data.image'), extensions: [is_gif ? 'gif' : 'png']} ]}, function (fileName) {
if (fileName === undefined) {
return;
}
fs.writeFile(fileName, Buffer(dataUrl.split(',')[1], 'base64'), err => {})
})
if (is_gif) {
Blockbench.export({
resource_id: 'screenshot',
extensions: ['gif'],
type: tl('data.image'),
savetype: 'binary',
content: Buffer(dataUrl.split(',')[1], 'base64')
})
} else {
Blockbench.export({
resource_id: 'screenshot',
extensions: ['png'],
type: tl('data.image'),
savetype: 'image',
content: dataUrl
})
}
} else if (result === 2) {
clipboard.writeImage(screenshot)
}
@ -1318,7 +1394,7 @@ function initCanvas() {
Sun = new THREE.AmbientLight( 0xffffff );
Sun.name = 'sun'
scene.add(Sun);
Sun.intensity = 0.44
Sun.intensity = 0.5
lights = new THREE.Object3D()
lights.name = 'lights'
@ -1328,7 +1404,14 @@ function initCanvas() {
light_top.position.set(8, 100, 8)
lights.add(light_top);
light_top.intensity = 0.66
light_top.intensity = 0.45
var light_bottom = new THREE.DirectionalLight();
light_bottom.name = 'light_bottom'
light_bottom.position.set(8, 100, 8)
lights.add(light_bottom);
light_bottom.intensity = 0.11
var light_north = new THREE.DirectionalLight();
light_north.name = 'light_north'
@ -1340,7 +1423,7 @@ function initCanvas() {
light_south.position.set(8, 8, 100)
lights.add(light_south);
light_north.intensity = light_south.intensity = 0.44
light_north.intensity = light_south.intensity = 0.33
var light_west = new THREE.DirectionalLight();
light_west.name = 'light_west'
@ -1491,7 +1574,6 @@ function buildGrid() {
three_grid.add(line)
}
//Axis Lines
if (settings.base_grid.value || settings.full_grid.value)
if (Format.centered_grid || !settings.full_grid.value) {
var length = Format.centered_grid
? (settings.full_grid.value ? 24 : 8)
@ -1508,7 +1590,8 @@ function buildGrid() {
if (settings.full_grid.value === true) {
//Grid
var grid = new THREE.GridHelper(48, 48/canvasGridSize(), gizmo_colors.grid)
let size = settings.large_grid_size.value*16;
var grid = new THREE.GridHelper(size, size/canvasGridSize(), gizmo_colors.grid)
if (Format.centered_grid) {
grid.position.set(0,0,0)
} else {
@ -1522,9 +1605,9 @@ function buildGrid() {
geometry = new THREE.PlaneGeometry(5, 5)
var north_mark = new THREE.Mesh(geometry, Canvas.northMarkMaterial)
if (Format.centered_grid) {
north_mark.position.set(0,0,-27)
north_mark.position.set(0,0, -3 - size/2)
} else {
north_mark.position.set(8,0,-19)
north_mark.position.set(8, 0, 5 - size/2)
}
north_mark.rotation.x = Math.PI / -2
three_grid.add(north_mark)
@ -1532,7 +1615,8 @@ function buildGrid() {
} else {
if (settings.large_grid.value === true) {
//Grid
var grid = new THREE.GridHelper(48, 3, gizmo_colors.grid)
let size = settings.large_grid_size.value
var grid = new THREE.GridHelper(size*16, size, gizmo_colors.grid)
if (Format.centered_grid) {
grid.position.set(0,0,0)
} else {

View File

@ -917,7 +917,7 @@
Transformer.rotation_ref = rotation_object.mesh.parent;
} else if (space === 2 || Toolbox.selected.id == 'resize_tool') {
Transformer.rotation_ref = selected[0].mesh;
Transformer.rotation_ref = selected[0] && selected[0].mesh;
} else if (space instanceof Group) {
Transformer.rotation_ref = space.mesh;
@ -1273,19 +1273,6 @@
moveElementsInSpace(difference, axisNumber)
/*
if (_has_groups && Blockbench.globalMovement) {
Group.selected.forEachChild(g => {
g.origin[axisNumber] += difference
}, Group, true)
}
selected.forEach(function(obj, i) {
if (obj.movable) {
obj.move(difference, axisNumber, _has_groups||!Format.bone_rig)
}
})
*/
scope.updateSelection()
}
previousValue = point[axis]

View File

@ -5,310 +5,46 @@ function colorDistance(color1, color2) {
Math.pow(color2._b - color1._b, 2)
);
}
onVueSetup(() => {
(function() {
var palettes = {
default: [
'#1a1a1b',
'#353637',
'#464849',
'#5d5f60',
'#757677',
'#868788',
'#979b9d',
'#b8bdbe',
'#dadedf',
'#ffffff',
'#9a080f',
'#b40a1a',
'#d21129',
'#ef2142',
'#ff5774',
'#bb7907',
'#cc9104',
'#edb508',
'#fcd720',
'#fef364',
'#0d7e36',
'#12933d',
'#11aa38',
'#1cc93d',
'#29e64d',
'#044b8f',
'#0955a8',
'#126bc3',
'#1782db',
'#339afc',
'#cd3e00',
'#e65b00',
'#f37800',
'#f89520',
'#fdaf40',
'#02a8c1',
'#0cc3ca',
'#17d1c7',
'#38debd',
'#5be9b7',
'#1a1a1b','#353637','#464849','#5d5f60','#757677','#868788','#979b9d','#b8bdbe','#dadedf','#ffffff',
'#9a080f','#b40a1a','#d21129','#ef2142','#ff5774','#bb7907','#cc9104','#edb508','#fcd720','#fef364',
'#0d7e36','#12933d','#11aa38','#1cc93d','#29e64d','#044b8f','#0955a8','#126bc3','#1782db','#339afc',
'#cd3e00','#e65b00','#f37800','#f89520','#fdaf40','#02a8c1','#0cc3ca','#17d1c7','#38debd','#5be9b7',
],
material: [
'#FFEBEE',
'#FFCDD2',
'#EF9A9A',
'#E57373',
'#EF5350',
'#F44336',
'#E53935',
'#D32F2F',
'#C62828',
'#B71C1C',
'#FCE4EC',
'#F8BBD0',
'#F48FB1',
'#F06292',
'#EC407A',
'#E91E63',
'#D81B60',
'#C2185B',
'#AD1457',
'#880E4F',
'#F3E5F5',
'#E1BEE7',
'#CE93D8',
'#BA68C8',
'#AB47BC',
'#9C27B0',
'#8E24AA',
'#7B1FA2',
'#6A1B9A',
'#4A148C',
'#EDE7F6',
'#D1C4E9',
'#B39DDB',
'#9575CD',
'#7E57C2',
'#673AB7',
'#5E35B1',
'#512DA8',
'#4527A0',
'#311B92',
'#E8EAF6',
'#C5CAE9',
'#9FA8DA',
'#7986CB',
'#5C6BC0',
'#3F51B5',
'#3949AB',
'#303F9F',
'#283593',
'#1A237E',
'#E3F2FD',
'#BBDEFB',
'#90CAF9',
'#64B5F6',
'#42A5F5',
'#2196F3',
'#1E88E5',
'#1976D2',
'#1565C0',
'#0D47A1',
'#E1F5FE',
'#B3E5FC',
'#81D4FA',
'#4FC3F7',
'#29B6F6',
'#03A9F4',
'#039BE5',
'#0288D1',
'#0277BD',
'#01579B',
'#E0F7FA',
'#B2EBF2',
'#80DEEA',
'#4DD0E1',
'#26C6DA',
'#00BCD4',
'#00ACC1',
'#0097A7',
'#00838F',
'#006064',
'#E0F2F1',
'#B2DFDB',
'#80CBC4',
'#4DB6AC',
'#26A69A',
'#009688',
'#00897B',
'#00796B',
'#00695C',
'#004D40',
'#E8F5E9',
'#C8E6C9',
'#A5D6A7',
'#81C784',
'#66BB6A',
'#4CAF50',
'#43A047',
'#388E3C',
'#2E7D32',
'#1B5E20',
'#F1F8E9',
'#DCEDC8',
'#C5E1A5',
'#AED581',
'#9CCC65',
'#8BC34A',
'#7CB342',
'#689F38',
'#558B2F',
'#33691E',
'#F9FBE7',
'#F0F4C3',
'#E6EE9C',
'#DCE775',
'#D4E157',
'#CDDC39',
'#C0CA33',
'#AFB42B',
'#9E9D24',
'#827717',
'#FFFDE7',
'#FFF9C4',
'#FFF59D',
'#FFF176',
'#FFEE58',
'#FFEB3B',
'#FDD835',
'#FBC02D',
'#F9A825',
'#F57F17',
'#FFF8E1',
'#FFECB3',
'#FFE082',
'#FFD54F',
'#FFCA28',
'#FFC107',
'#FFB300',
'#FFA000',
'#FF8F00',
'#FF6F00',
'#FFF3E0',
'#FFE0B2',
'#FFCC80',
'#FFB74D',
'#FFA726',
'#FF9800',
'#FB8C00',
'#F57C00',
'#EF6C00',
'#E65100',
'#FBE9E7',
'#FFCCBC',
'#FFAB91',
'#FF8A65',
'#FF7043',
'#FF5722',
'#F4511E',
'#E64A19',
'#D84315',
'#BF360C',
'#EFEBE9',
'#D7CCC8',
'#BCAAA4',
'#A1887F',
'#8D6E63',
'#795548',
'#6D4C41',
'#5D4037',
'#4E342E',
'#3E2723',
'#FAFAFA',
'#F5F5F5',
'#EEEEEE',
'#E0E0E0',
'#BDBDBD',
'#9E9E9E',
'#757575',
'#616161',
'#424242',
'#212121',
'#ECEFF1',
'#CFD8DC',
'#B0BEC5',
'#90A4AE',
'#78909C',
'#607D8B',
'#546E7A',
'#455A64',
'#37474F',
'#263238',
'#ffebee','#ffcdd2','#ef9a9a','#e57373','#ef5350','#f44336','#e53935','#d32f2f','#c62828','#b71c1c','#ff5252','#ff1744',
'#fce4ec','#f8bbd0','#f48fb1','#f06292','#ec407a','#e91e63','#d81b60','#c2185b','#ad1457','#880e4f','#ff4081','#f50057',
'#f3e5f5','#e1bee7','#ce93d8','#ba68c8','#ab47bc','#9c27b0','#8e24aa','#7b1fa2','#6a1b9a','#4a148c','#e040fb','#d500f9',
'#ede7f6','#d1c4e9','#b39ddb','#9575cd','#7e57c2','#673ab7','#5e35b1','#512da8','#4527a0','#311b92','#7c4dff','#651fff',
'#e8eaf6','#c5cae9','#9fa8da','#7986cb','#5c6bc0','#3f51b5','#3949ab','#303f9f','#283593','#1a237e','#536dfe','#3d5afe',
'#e3f2fd','#bbdefb','#90caf9','#64b5f6','#42a5f5','#2196f3','#1e88e5','#1976d2','#1565c0','#0d47a1','#448aff','#2979ff',
'#e1f5fe','#b3e5fc','#81d4fa','#4fc3f7','#29b6f6','#03a9f4','#039be5','#0288d1','#0277bd','#01579b','#40c4ff','#00b0ff',
'#e0f7fa','#b2ebf2','#80deea','#4dd0e1','#26c6da','#00bcd4','#00acc1','#0097a7','#00838f','#006064','#18ffff','#00e5ff',
'#e0f2f1','#b2dfdb','#80cbc4','#4db6ac','#26a69a','#009688','#00897b','#00796b','#00695c','#004d40','#64ffda','#1de9b6',
'#e8f5e9','#c8e6c9','#a5d6a7','#81c784','#66bb6a','#4caf50','#43a047','#388e3c','#2e7d32','#1b5e20','#69f0ae','#00e676',
'#f1f8e9','#dcedc8','#c5e1a5','#aed581','#9ccc65','#8bc34a','#7cb342','#689f38','#558b2f','#33691e','#b2ff59','#76ff03',
'#f9fbe7','#f0f4c3','#e6ee9c','#dce775','#d4e157','#cddc39','#c0ca33','#afb42b','#9e9d24','#827717','#eeff41','#c6ff00',
'#fffde7','#fff9c4','#fff59d','#fff176','#ffee58','#ffeb3b','#fdd835','#fbc02d','#f9a825','#f57f17','#ffff00','#ffea00',
'#fff8e1','#ffecb3','#ffe082','#ffd54f','#ffca28','#ffc107','#ffb300','#ffa000','#ff8f00','#ff6f00','#ffd740','#ffc400',
'#fff3e0','#ffe0b2','#ffcc80','#ffb74d','#ffa726','#ff9800','#fb8c00','#f57c00','#ef6c00','#e65100','#ffab40','#ff9100',
'#fbe9e7','#ffccbc','#ffab91','#ff8a65','#ff7043','#ff5722','#f4511e','#e64a19','#d84315','#bf360c','#ff6e40','#ff3d00',
'#efebe9','#d7ccc8','#bcaaa4','#a1887f','#8d6e63','#795548','#6d4c41','#5d4037','#4e342e','#3e2723','#6d422d','#593022',
'#fafafa','#f5f5f5','#eeeeee','#e0e0e0','#bdbdbd','#9e9e9e','#757575','#616161','#424242','#212121','#ffffff','#000000',
'#eceff1','#cfd8dc','#b0bec5','#90a4ae','#78909c','#607d8b','#546e7a','#455a64','#37474f','#263238',
],
endesga64: [
'#ff0040',
'#131313',
'#1b1b1b',
'#272727',
'#3d3d3d',
'#5d5d5d',
'#858585',
'#b4b4b4',
'#ffffff',
'#c7cfdd',
'#92a1b9',
'#657392',
'#424c6e',
'#2a2f4e',
'#1a1932',
'#0e071b',
'#1c121c',
'#391f21',
'#5d2c28',
'#8a4836',
'#bf6f4a',
'#e69c69',
'#f6ca9f',
'#f9e6cf',
'#edab50',
'#e07438',
'#c64524',
'#8e251d',
'#ff5000',
'#ed7614',
'#ffa214',
'#ffc825',
'#ffeb57',
'#d3fc7e',
'#99e65f',
'#5ac54f',
'#33984b',
'#1e6f50',
'#134c4c',
'#0c2e44',
'#00396d',
'#0069aa',
'#0098dc',
'#00cdf9',
'#0cf1ff',
'#94fdff',
'#fdd2ed',
'#f389f5',
'#db3ffd',
'#7a09fa',
'#3003d9',
'#0c0293',
'#03193f',
'#3b1443',
'#622461',
'#93388f',
'#ca52c9',
'#c85086',
'#f68187',
'#f5555d',
'#ea323c',
'#c42430',
'#891e2b',
'#571c27',
'#ff0040','#131313','#1b1b1b','#272727','#3d3d3d','#5d5d5d','#858585','#b4b4b4','#ffffff','#c7cfdd',
'#92a1b9','#657392','#424c6e','#2a2f4e','#1a1932','#0e071b','#1c121c','#391f21','#5d2c28','#8a4836',
'#bf6f4a','#e69c69','#f6ca9f','#f9e6cf','#edab50','#e07438','#c64524','#8e251d','#ff5000','#ed7614',
'#ffa214','#ffc825','#ffeb57','#d3fc7e','#99e65f','#5ac54f','#33984b','#1e6f50','#134c4c','#0c2e44',
'#00396d','#0069aa','#0098dc','#00cdf9','#0cf1ff','#94fdff','#fdd2ed','#f389f5','#db3ffd','#7a09fa',
'#3003d9','#0c0293','#03193f','#3b1443','#622461','#93388f','#ca52c9','#c85086','#f68187','#f5555d',
'#ea323c','#c42430','#891e2b','#571c27',
]
}
onVueSetup(() => {
ColorPanel = Interface.Panels.color = new Panel({
id: 'color',
condition: () => Modes.id === 'paint',
@ -321,18 +57,7 @@ onVueSetup(() => {
},
menu: new Menu([
'sort_palette',
'clear_palette',
{name: 'menu.palette.load', id: 'load', icon: 'fa-tasks', children: [
{name: 'menu.palette.load.default', icon: 'bubble_chart', id: 'default', click: () => {
ColorPanel.palette.splice(0, Infinity, ...palettes.default);
}},
{name: 'Endesga 64', description: 'Pixel art palette created by lospec.com/endesga', icon: 'bubble_chart', id: 'endesga64', click: () => {
ColorPanel.palette.splice(0, Infinity, ...palettes.endesga64);
}},
{name: 'Material', icon: 'bubble_chart', id: 'material', click: () => {
ColorPanel.palette.splice(0, Infinity, ...palettes.material);
}},
]}
'load_palette'
])
})
var saved_colors = localStorage.getItem('colors');
@ -398,6 +123,20 @@ onVueSetup(() => {
if (!color.match(/^#[0-9a-f]{6}$/)) {
this.main_color = tinycolor(color).toHexString();
}
},
isDarkColor(hex) {
if (hex) {
hex = hex.replace('#', '')
let dgts = hex.substr(0, 1) + hex.substr(2, 1) + hex.substr(4, 1)
let bg = parseInt(CustomTheme.data.colors.back.substr(1, 1), 16);
let color_range = (bg).toString(16)
+ (Math.isBetween(bg+2, 0, 15) ? (bg+2).toString(16) : '')
+ (Math.isBetween(bg+1, 0, 15) ? (bg+1).toString(16) : '')
+ (Math.isBetween(bg-1, 0, 15) ? (bg-1).toString(16) : '')
+ (Math.isBetween(bg-2, 0, 15) ? (bg-2).toString(16) : '')
let regex = new RegExp(`[^${color_range}]`)
return dgts.search(regex) == -1
}
}
},
watch: {
@ -854,6 +593,7 @@ BARS.defineActions(function() {
category: 'color',
click: function () {
Blockbench.import({
resource_id: 'palette',
extensions: ['gpl', 'css', 'txt', 'hex', 'png', 'aco', 'act', 'ase', 'bbpalette'],
type: 'Blockbench Palette',
readtype: (path) => {
@ -881,6 +621,7 @@ BARS.defineActions(function() {
content += `${t._r}\t${t._g}\t${t._b}\t${color}\n`;
})
Blockbench.export({
resource_id: 'palette',
extensions: ['gpl'],
type: 'GPL Palette',
content
@ -936,12 +677,28 @@ BARS.defineActions(function() {
}
}
})
new Action('clear_palette', {
icon: 'clear',
new Action('load_palette', {
icon: 'fa-tasks',
category: 'color',
click: function () {
ColorPanel.palette.purge();
}
click: function (e) {
new Menu(this.children).open(e.target)
},
children: [
{name: 'menu.palette.load.default', icon: 'bubble_chart', id: 'default', click: () => {
ColorPanel.palette.splice(0, Infinity, ...palettes.default);
}},
{name: 'Endesga 64', description: 'Pixel art palette created by lospec.com/endesga', icon: 'bubble_chart', id: 'endesga64', click: () => {
ColorPanel.palette.splice(0, Infinity, ...palettes.endesga64);
}},
{name: 'Material', icon: 'bubble_chart', id: 'material', click: () => {
ColorPanel.palette.splice(0, Infinity, ...palettes.material);
}},
'_',
{name: 'menu.palette.load.empty', icon: 'clear', id: 'empty', click: () => {
ColorPanel.palette.splice(0, Infinity);
}},
]
})
@ -1005,4 +762,5 @@ BARS.defineActions(function() {
ColorPanel.updateFromHsv();
}
})
})
})
})()

View File

@ -112,7 +112,7 @@ const Painter = {
}
}
}
if (!data) return;
if (!data || (data.cube && data.cube.locked)) return;
var texture = data.cube.faces[data.face].getTexture()
if (!texture || (texture.error && texture.error !== 2)) {
Blockbench.showQuickMessage('message.untextured')
@ -131,7 +131,7 @@ const Painter = {
movePaintToolCanvas(event) {
convertTouchEvent(event);
var data = Canvas.raycast(event)
if (data) {
if (data && data.cube && !data.cube.locked) {
var texture = data.cube.faces[data.face].getTexture()
if (texture) {
var x, y, new_face;
@ -204,7 +204,7 @@ const Painter = {
Painter.drawBrushLine(texture, x, y, event, false, uvTag);
} else {
Painter.current.x = Painter.current.y = 0
Painter.useBrush(texture, x, y, event, uvTag)
Painter.useBrushlike(texture, x, y, event, uvTag)
}
Painter.current.x = x;
Painter.current.y = y;
@ -233,7 +233,7 @@ const Painter = {
Painter.currentPixel = [-1, -1];
},
// Tools
useBrush(texture, x, y, event, uvTag, no_update, is_opposite) {
useBrushlike(texture, x, y, event, uvTag, no_update, is_opposite) {
if (Painter.currentPixel[0] === x && Painter.currentPixel[1] === y) return;
Painter.currentPixel = [x, y]
Painter.brushChanges = true;
@ -248,12 +248,6 @@ const Painter = {
var ctx = canvas.getContext('2d')
ctx.save()
var color = tinycolor(ColorPanel.get()).toRgb();
var size = BarItems.slider_brush_size.get();
let softness = BarItems.slider_brush_softness.get()/100;
let b_opacity = BarItems.slider_brush_opacity.get()/100;
let tool = Toolbox.selected.id;
ctx.beginPath();
if (uvTag) {
var rect = Painter.editing_area = [
@ -275,129 +269,159 @@ const Painter = {
var [w, h] = [rect[2] - rect[0], rect[3] - rect[1]]
ctx.rect(rect[0], rect[1], w, h)
if (tool === 'fill_tool') {
ctx.fillStyle = tinycolor(ColorPanel.get()).setAlpha(b_opacity).toRgbString();
var fill_mode = BarItems.fill_mode.get()
var cube = Painter.current.cube;
if (cube && fill_mode === 'cube') {
for (var face in cube.faces) {
var tag = cube.faces[face]
if (tag.texture === Painter.current.texture.uuid) {
var rect = getRectangle(
Math.floor(tag.uv[0] * uvFactorX),
Math.floor(tag.uv[1] * uvFactorY),
Math.ceil(tag.uv[2] * uvFactorX),
Math.ceil(tag.uv[3] * uvFactorY)
)
ctx.rect(rect.ax, rect.ay, rect.x, rect.y)
ctx.fill()
}
}
} else if (fill_mode === 'face') {
ctx.fill()
} else {
var pxcol = [];
var map = {}
Painter.scanCanvas(ctx, x, y, 1, 1, (x, y, px) => {
px.forEach((val, i) => {
pxcol[i] = val
})
})
Painter.scanCanvas(ctx, rect[0], rect[1], w, h, (x, y, px) => {
if (pxcol.equals(px)) {
if (!map[x]) map[x] = {}
map[x][y] = true
}
})
var scan_value = true;
if (fill_mode === 'color_connected') {
function checkPx(x, y) {
if (map[x] && map[x][y]) {
map[x][y] = false;
checkPx(x+1, y)
checkPx(x-1, y)
checkPx(x, y+1)
checkPx(x, y-1)
}
}
checkPx(x, y)
scan_value = false;
}
Painter.scanCanvas(ctx, rect[0], rect[1], w, h, (x, y, px) => {
if (map[x] && map[x][y] === scan_value) {
var pxcolor = {
r: px[0],
g: px[1],
b: px[2],
a: px[3]/255
}
var result_color = Painter.combineColors(pxcolor, color, b_opacity);
px[0] = result_color.r
px[1] = result_color.g
px[2] = result_color.b
if (!Painter.lock_alpha) px[3] = result_color.a*255
}
})
}
if (Toolbox.selected.id === 'fill_tool') {
Painter.useFilltool(texture, ctx, x, y, { rect, uvFactorX, uvFactorY, w, h })
} else {
ctx.clip()
if (event.touches && event.touches[0] && event.touches[0].force) {
var touch = event.touches[0];
if (touch.force == 1) touch.force == Painter.current.force || 0;
Painter.current.force = touch.force;
if (settings.brush_opacity_modifier.value == 'pressure' && touch.force) {
b_opacity = Math.clamp(b_opacity * touch.force*1.25, 0, 100);
//m_opacity = Math.clamp(m_opacity * touch.force*1.25, 0, 100);
} else if (settings.brush_opacity_modifier.value == 'tilt' && touch.altitudeAngle !== undefined) {
var modifier = Math.clamp(1.5 / (touch.altitudeAngle + 0.3), 1, 4)/2;
b_opacity = Math.clamp(b_opacity * modifier, 0, 100);
//m_opacity = Math.clamp(m_opacity * modifier, 0, 100);
}
if (settings.brush_size_modifier.value == 'pressure' && touch.force) {
size = Math.clamp(touch.force * size * 2, 1, 20);
} else if (settings.brush_size_modifier.value == 'tilt' && touch.altitudeAngle !== undefined) {
size *= Math.clamp(1.5 / (touch.altitudeAngle + 0.3), 1, 4);
}
}
if (tool === 'brush_tool') {
Painter.editCircle(ctx, x, y, size, softness, function(pxcolor, opacity, px, py) {
var a = b_opacity * opacity;
var before = Painter.getAlphaMatrix(texture, px, py)
Painter.setAlphaMatrix(texture, px, py, a);
if (a > before) {
a = (a - before) / (1 - before);
} else if (before) {
a = 0;
}
var result_color = Painter.combineColors(pxcolor, color, a);
if (Painter.lock_alpha) result_color.a = pxcolor.a
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: Painter.lock_alpha ? pxcolor.a : (pxcolor.a*(1-b_opacity))
};
})
}
ctx.restore();
Painter.useBrush(texture, ctx, x, y, event)
}
Painter.editing_area = undefined;
}, {no_undo: true, use_cache: true, no_update});
},
useBrush(texture, ctx, x, y, event) {
var color = tinycolor(ColorPanel.get()).toRgb();
var size = BarItems.slider_brush_size.get();
let softness = BarItems.slider_brush_softness.get()/100;
let b_opacity = BarItems.slider_brush_opacity.get()/100;
let tool = Toolbox.selected.id;
ctx.clip()
if (event.touches && event.touches[0] && event.touches[0].force) {
// Stylus
var touch = event.touches[0];
if (touch.force == 1) touch.force == Painter.current.force || 0;
Painter.current.force = touch.force;
if (settings.brush_opacity_modifier.value == 'pressure' && touch.force) {
b_opacity = Math.clamp(b_opacity * touch.force*1.25, 0, 100);
} else if (settings.brush_opacity_modifier.value == 'tilt' && touch.altitudeAngle !== undefined) {
var modifier = Math.clamp(1.5 / (touch.altitudeAngle + 0.3), 1, 4)/2;
b_opacity = Math.clamp(b_opacity * modifier, 0, 100);
}
if (settings.brush_size_modifier.value == 'pressure' && touch.force) {
size = Math.clamp(touch.force * size * 2, 1, 20);
} else if (settings.brush_size_modifier.value == 'tilt' && touch.altitudeAngle !== undefined) {
size *= Math.clamp(1.5 / (touch.altitudeAngle + 0.3), 1, 4);
}
}
if (tool === 'brush_tool') {
Painter.editCircle(ctx, x, y, size, softness, function(pxcolor, opacity, px, py) {
var a = b_opacity * opacity;
var before = Painter.getAlphaMatrix(texture, px, py)
Painter.setAlphaMatrix(texture, px, py, a);
if (a > before) {
a = (a - before) / (1 - before);
} else if (before) {
a = 0;
}
var result_color = Painter.combineColors(pxcolor, color, a);
if (Painter.lock_alpha) result_color.a = pxcolor.a
return result_color;
})
} else if (tool === 'eraser') {
Painter.editCircle(ctx, x, y, size, softness, function(pxcolor, opacity, px, py) {
if (Painter.lock_alpha) return pxcolor;
var a = b_opacity * opacity;
var before = Painter.getAlphaMatrix(texture, px, py)
Painter.setAlphaMatrix(texture, px, py, a);
if (a > before) {
a = (a - before) / (1 - before);
} else if (before) {
a = 0;
}
pxcolor.a = Math.clamp(pxcolor.a * (1-a), 0, 1);
return pxcolor;
})
}
ctx.restore();
},
useFilltool(texture, ctx, x, y, area) {
var color = tinycolor(ColorPanel.get()).toRgb();
let b_opacity = BarItems.slider_brush_opacity.get()/100;
let tool = Toolbox.selected.id;
let {rect, uvFactorX, uvFactorY, w, h} = area;
ctx.fillStyle = tinycolor(ColorPanel.get()).setAlpha(b_opacity).toRgbString();
var fill_mode = BarItems.fill_mode.get()
var cube = Painter.current.cube;
if (cube && fill_mode === 'cube') {
for (var face in cube.faces) {
var tag = cube.faces[face]
ctx.beginPath();
if (tag.texture === Painter.current.texture.uuid) {
var face_rect = getRectangle(
Math.floor(tag.uv[0] * uvFactorX),
Math.floor(tag.uv[1] * uvFactorY),
Math.ceil(tag.uv[2] * uvFactorX),
Math.ceil(tag.uv[3] * uvFactorY)
)
ctx.rect(face_rect.ax, face_rect.ay, face_rect.x, face_rect.y)
ctx.fill()
}
}
} else if (fill_mode === 'face') {
ctx.fill()
} else {
var pxcol = [];
var map = {}
Painter.scanCanvas(ctx, x, y, 1, 1, (x, y, px) => {
px.forEach((val, i) => {
pxcol[i] = val
})
})
Painter.scanCanvas(ctx, rect[0], rect[1], w, h, (x, y, px) => {
if (pxcol.equals(px)) {
if (!map[x]) map[x] = {}
map[x][y] = true
}
})
var scan_value = true;
if (fill_mode === 'color_connected') {
function checkPx(x, y) {
if (map[x] && map[x][y]) {
map[x][y] = false;
checkPx(x+1, y)
checkPx(x-1, y)
checkPx(x, y+1)
checkPx(x, y-1)
}
}
checkPx(x, y)
scan_value = false;
}
Painter.scanCanvas(ctx, rect[0], rect[1], w, h, (x, y, px) => {
if (map[x] && map[x][y] === scan_value) {
var pxcolor = {
r: px[0],
g: px[1],
b: px[2],
a: px[3]/255
}
var result_color = Painter.combineColors(pxcolor, color, b_opacity);
px[0] = result_color.r
px[1] = result_color.g
px[2] = result_color.b
if (!Painter.lock_alpha) px[3] = result_color.a*255
}
})
}
},
runMirrorBrush(texture, x, y, event, uvTag) {
if (uvTag && Painter.current.cube) {
let mirror_cube = Painter.getMirrorCube(Painter.current.cube);
@ -436,7 +460,7 @@ const Painter = {
let cube = Painter.current.cube;
Painter.current.cube = mirror_cube;
Painter.useBrush(texture, ...point_on_uv, event, face.uv, true, true);
Painter.useBrushlike(texture, ...point_on_uv, event, face.uv, true, true);
Painter.current.cube = cube;
}
}
@ -457,7 +481,7 @@ const Painter = {
while (i <= length) {
x = Math.round(start_x + diff_x / length * i)
y = Math.round(start_y + diff_y / length * i)
Painter.useBrush(texture, x, y, event, uv, i < length-1);
Painter.useBrushlike(texture, x, y, event, uv, i < length-1);
i++;
}
},
@ -617,15 +641,16 @@ const Painter = {
},
getMirrorCube(cube) {
let center = Format.centered_grid ? 0 : 8;
let e = 0.002
if (cube.from[0]-center === center-cube.to[0] && !cube.rotation[1] && !cube.rotation[2]) {
return cube;
} else {
for (var cube2 of Cube.all) {
if (
cube.inflate === cube2.inflate &&
cube.from[2] === cube2.from[2] && cube.to[2] === cube2.to[2] &&
cube.from[1] === cube2.from[1] && cube.to[1] === cube2.to[1] &&
cube.size(0) === cube2.size(0) && cube.to[0]-center === center-cube2.from[0]
Math.epsilon(cube.from[2], cube2.from[2], e) && Math.epsilon(cube.to[2], cube2.to[2], e) &&
Math.epsilon(cube.from[1], cube2.from[1], e) && Math.epsilon(cube.to[1], cube2.to[1], e) &&
Math.epsilon(cube.size(0), cube2.size(0), e) && Math.epsilon(cube.to[0]-center, center-cube2.from[0], e)
) {
return cube2;
}
@ -957,7 +982,7 @@ BARS.defineActions(function() {
condition: () => (Toolbox && ['brush_tool', 'eraser', 'draw_shape_tool'].includes(Toolbox.selected.id)),
category: 'paint',
settings: {
min: 1, max: 20, interval: 1, default: 1,
min: 1, max: 50, interval: 1, default: 1,
}
})
new NumSlider('slider_brush_softness', {

View File

@ -371,14 +371,23 @@ const TextureGenerator = {
coords.w*res_multiple,
coords.h*res_multiple
)
if (coords.w*res_multiple > 2 && coords.h*res_multiple > 2 && color) {
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
)
if (coords.w*res_multiple > 2 && coords.h*res_multiple > 2) {
if (color == null) {
ctx.clearRect(
coords.x * res_multiple + 1,
coords.y * res_multiple + 1,
coords.w * res_multiple - 2,
coords.h * res_multiple - 2
)
} else if (color) {
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
)
}
}
},
boxUVdrawTexture(face, coords, texture, canvas) {
@ -423,9 +432,9 @@ const TextureGenerator = {
ctx.drawImage(
texture.img,
src.ax/Project.texture_width * texture.img.naturalWidth,
src.ay/Project.texture_height * texture.img.naturalHeight,
src.ay/Project.texture_width * texture.img.naturalWidth,
src.x /Project.texture_width * texture.img.naturalWidth,
src.y /Project.texture_height * texture.img.naturalHeight,
src.y /Project.texture_width * texture.img.naturalWidth,
coords.x*res_multiple*flip[0],
coords.y*res_multiple*flip[1],
coords.w*res_multiple*flip[0],
@ -434,7 +443,7 @@ const TextureGenerator = {
ctx.restore()
return true;
},
paintCubeBoxTemplate(cube, texture, canvas, template) {
paintCubeBoxTemplate(cube, texture, canvas, template, transparent) {
if (!template) {
template = new TextureGenerator.boxUVCubeTemplate(cube, Project.box_uv ? 0 : 1);
@ -446,7 +455,7 @@ const TextureGenerator = {
if (!cube.faces[face].texture ||
!TextureGenerator.boxUVdrawTexture(cube.faces[face], d.place(template), texture, canvas)
) {
TextureGenerator.boxUVdrawTemplateRectangle(d.c1, d.c2, cube.faces[face], d.place(template), texture, canvas)
TextureGenerator.boxUVdrawTemplateRectangle(d.c1, transparent ? null : d.c2, cube.faces[face], d.place(template), texture, canvas)
}
}
@ -688,13 +697,15 @@ const TextureGenerator = {
w: ftemp.width,
h: ftemp.height
}
var d = TextureGenerator.face_data[ftemp.face_key];
var d = TextureGenerator.face_data[ftemp.face_key];
var flip_rotation = false
if (!ftemp.texture ||
!drawTexture(ftemp.face, pos)
) {
drawTemplateRectangle(d.c1, d.c2, ftemp.face, pos)
} else {
flip_rotation = ftemp.face.rotation % 180 != 0;
}
var flip_rotation = ftemp.face.rotation % 180 != 0;
ftemp.face.extend({
rotation: 0,
uv: flip_rotation ? [pos.y, pos.x] : [pos.x, pos.y]

View File

@ -80,15 +80,10 @@ class Texture {
//Width / Animation
if (img.naturalWidth !== img.naturalHeight && Format.id == 'java_block') {
if (img.naturalHeight % img.naturalWidth !== 0) {
scope.error = 2;
Blockbench.showQuickMessage('message.square_textures')
} else {
BARS.updateConditions()
}
BARS.updateConditions()
}
if (Project.box_uv && Format.single_texture) {
if (Project.box_uv && Format.single_texture && !scope.error) {
if (!scope.keep_size) {
let pw = Project.texture_width;
@ -101,13 +96,12 @@ class Texture {
//Resolution of this texture has changed
var changed = size_control.old_width && (size_control.old_width != nw || size_control.old_height != nh);
//Resolution could be a multiple of project size
var multi = !(
(pw%nw || ph%nh) &&
(nw%pw || nh%ph)
var multi = (
(pw%nw == 0 || nw%pw == 0) &&
(ph%nh == 0 || nh%ph == 0)
)
if (unlike && changed) {
if (unlike && changed && !multi) {
Blockbench.showMessageBox({
translateKey: 'update_res',
icon: 'photo_size_select_small',
@ -129,11 +123,6 @@ class Texture {
size_control.old_height = img.naturalHeight
}
if ($('.dialog#texture_edit:visible').length > 0 && scope.selected === true) {
scope.openMenu()
}
TextureAnimator.updateButton()
Canvas.updateAllFaces(scope)
if (typeof scope.load_callback === 'function') {
@ -141,7 +130,7 @@ class Texture {
delete scope.load_callback;
}
}
this.img.onerror = function() {
this.img.onerror = function(error) {
if (isApp &&
!scope.isDefault &&
scope.mode !== 'bitmap' &&
@ -166,7 +155,7 @@ class Texture {
case 0: return ''; break;
case 1: return tl('texture.error.file'); break;
//case 1: return tl('texture.error.invalid'); break;
case 2: return tl('texture.error.ratio'); break;
//case 2: return tl('texture.error.ratio'); break;
case 3: return tl('texture.error.parent'); break;
}
}
@ -402,6 +391,7 @@ class Texture {
function _replace() {
Blockbench.import({
resource_id: 'texture',
extensions: ['png', 'tga'],
type: 'PNG Texture',
readtype: 'image',
@ -453,21 +443,21 @@ class Texture {
var scope = this;
this.stopWatcher();
fs.watchFile(scope.path, {interval: 50}, function(curr, prev) {
if (curr.mtime !== prev.mtime) {
if (fs.existsSync(scope.path)) {
let timeout;
this.watcher = fs.watch(scope.path, (eventType) => {
if (eventType == 'change') {
if (timeout) clearTimeout(timeout)
timeout = setTimeout(() => {
scope.reloadTexture();
} else {
scope.stopWatcher();
}
}, 60)
}
})
}
stopWatcher() {
if (this.mode !== 'link' || !isApp || !fs.existsSync(this.path)) {
return;
if (isApp && this.watcher) {
this.watcher.close()
}
fs.unwatchFile(this.path)
return this;
}
generateFolder(path) {
var scope = this
@ -499,6 +489,9 @@ class Texture {
}
return this;
}
getMaterial() {
return Canvas.materials[this.uuid]
}
//Management
select(event) {
textures.forEach(s => {
@ -509,6 +502,7 @@ class Texture {
}
this.selected = true
textures.selected = this
this.scrollTo()
return this;
}
add(undo) {
@ -655,31 +649,54 @@ class Texture {
openMenu() {
var scope = this
scope.select()
showDialog('texture_edit')
let title = `${scope.name} (${scope.width} x ${scope.height})`;
var path = '';
if (scope.path) {
var arr = scope.path.split(osfs)
arr.splice(-1)
var path = arr.join('<span class="slash">/</span>') + '<span class="slash">/</span><span class="accent_color">' + scope.name + '</span>'
$('#texture_edit #te_path').html(path)
} else {
$('#texture_edit #te_path').html('')
path = arr.join('<span class="slash">/</span>') + '<span class="slash">/</span><span class="accent_color">' + scope.name + '</span>'
}
$('#texture_edit #te_title').text(scope.name + ' ('+scope.img.naturalWidth+' x '+scope.img.naturalHeight+')')
$('#texture_edit input#te_variable').val(scope.id)
$('#texture_edit input#te_name').val(scope.name)
$('#texture_edit input#te_folder').val(scope.folder)
$('#texture_edit input#te_namespace').val(scope.namespace)
$('#texture_menu_thumbnail').html(scope.img)
var dialog = new Dialog({
id: 'texture_edit',
title,
lines: [
`<div style="height: 140px;">
<div id="texture_menu_thumbnail">${scope.img.outerHTML}</div>
<p class="multiline_text" id="te_path">${path}</p>
</div>`
],
form: {
name: {label: 'generic.name', value: scope.name},
variable: {label: 'dialog.texture.variable', value: scope.id, condition: () => Format.id === 'java_block'},
folder: {label: 'dialog.texture.folder', value: scope.folder, condition: () => Format.id === 'java_block'},
namespace: {label: 'dialog.texture.namespace', value: scope.namespace, condition: () => Format.id === 'java_block'},
},
onConfirm: function(results) {
if (scope.mode === 'link') {
$('#texture_edit .tool.link_only').show()
$('#texture_edit .tool.bitmap_only').hide()
} else {
$('#texture_edit .tool.link_only').hide()
$('#texture_edit .tool.bitmap_only').show()
}
dialog.hide();
if (
(scope.name === results.name) &&
(results.variable === undefined || scope.id === results.variable) &&
(results.folder === undefined || scope.folder === results.folder) &&
(results.namespace === undefined || scope.namespace === results.namespace)
) {
return;
}
Undo.initEdit({textures: [scope]})
scope.name = results.name;
if (results.variable !== undefined) scope.id = results.variable;
if (results.folder !== undefined) scope.folder = results.folder;
if (results.namespace !== undefined) scope.namespace = results.namespace;
Undo.finishEdit('texture_edit')
}
}).show()
}
resizeDialog() {
let scope = this;
@ -776,6 +793,22 @@ class Texture {
dialog.show()
return this;
}
scrollTo() {
var el = $(`#texture_list > li[texid=${this.uuid}]`)
if (el.length === 0 || textures.length < 2) return;
var outliner_pos = $('#texture_list').offset().top
var el_pos = el.offset().top
if (el_pos > outliner_pos && el_pos + 48 < $('#texture_list').height() + outliner_pos) return;
var multiple = el_pos > outliner_pos ? 0.5 : 0.2
var scroll_amount = el_pos + $('#texture_list').scrollTop() - outliner_pos - 20
scroll_amount -= $('#texture_list').height()*multiple - 15
$('#texture_list').animate({
scrollTop: scroll_amount
}, 200);
}
//Export
javaTextureLink() {
var link = this.name.replace(/\.png$/, '')
@ -819,6 +852,7 @@ class Texture {
find_path = arr.join(osfs)
}
Blockbench.export({
resource_id: 'texture',
type: 'PNG Texture',
extensions: ['png'],
name: scope.name,
@ -968,29 +1002,6 @@ function saveTextures() {
}
})
}
function saveTextureMenu() {
hideDialog()
var tex = textures.selected
var name = $('#texture_edit input#te_name').val(),
id = $('#texture_edit input#te_variable').val(),
folder = $('#texture_edit input#te_folder').val(),
namespace = $('#texture_edit input#te_namespace').val();
if (!(
tex.name === name &&
tex.id === id &&
tex.folder === folder &&
tex.namespace === namespace)
) {
Undo.initEdit({textures})
tex.name = name;
tex.id = id;
tex.folder = folder;
tex.namespace = namespace;
Undo.finishEdit('texture_edit')
}
}
function loadTextureDraggable() {
Vue.nextTick(function() {
setTimeout(function() {
@ -1046,14 +1057,6 @@ function unselectTextures() {
})
textures.selected = false
}
function getTextureById(id) {
if (id === undefined || id === false) return;
if (id == null) {
return {material: transparentMaterial};
}
id = id.replace('#', '');
return $.grep(textures, function(e) {return e.id == id})[0];
}
function getTexturesById(id) {
if (id === undefined) return;
id = id.replace('#', '');
@ -1183,6 +1186,7 @@ BARS.defineActions(function() {
start_path = arr.join(osfs)
}
Blockbench.import({
resource_id: 'texture',
readtype: 'image',
type: 'PNG Texture',
extensions: ['png', 'tga'],

View File

@ -20,6 +20,12 @@ class UVEditor {
this.setGrid(BarItems.uv_grid.get().replace(/x/, ''));
}
}
get width() {
return this.size;
}
set width(v) {
this.size = v;
}
buildDom(toolbar) {
var scope = this
if (this.jquery.main) {
@ -47,6 +53,7 @@ class UVEditor {
</div>
</div>`);
this.img = new Image();
this.img.style.objectFit = Format.animated_textures ? 'cover' : 'fill';
this.jquery.frame.append(this.img)
this.jquery.size = this.jquery.frame.find('div#uv_size')
this.jquery.viewport.append(this.jquery.frame)
@ -56,6 +63,7 @@ class UVEditor {
if (Toolbox.selected.paintTool) {
this.jquery.size.hide()
}
this.jquery.main.toggleClass('checkerboard_trigger', settings.uv_checkerboard.value);
this.jquery.sliders = $('<div class="bar" style="margin-left: 2px;"></div>')
@ -271,13 +279,17 @@ class UVEditor {
var n = (event.deltaY < 0) ? 0.1 : -0.1;
n *= scope.zoom
var number = limitNumber(scope.zoom + n, 1, scope.max_zoom)
if (Math.abs(number - scope.zoom) > 0.001) {
this.scrollLeft += (scope.inner_width * n / 2) * (event.offsetX / scope.jquery.frame.width());
this.scrollTop += (scope.inner_width * n / 2) * (event.offsetY / scope.jquery.frame.height());
}
let old_zoom = scope.zoom;
scope.setZoom(number)
event.preventDefault()
e.preventDefault()
let zoom_diff = scope.zoom - old_zoom;
this.scrollLeft += ((this.scrollLeft + event.offsetX) * zoom_diff) / old_zoom
this.scrollTop += ((this.scrollTop + event.offsetY) * zoom_diff) / old_zoom
return false;
}
})
@ -306,25 +318,29 @@ class UVEditor {
//Paint brush outline
this.brush_outline = $('<div id="uv_brush_outline"></div>');
scope.jquery.frame.on('mouseenter mousemove', e => {
if (Modes.paint && Toolbox.selected.brushTool) {
scope.jquery.frame.append(this.brush_outline);
var pixel_size = scope.inner_width / (scope.texture ? scope.texture.width : Project.texture_width);
//pos
let offset = BarItems.slider_brush_size.get()%2 == 0 && Toolbox.selected.brushTool ? 0.5 : 0;
let left = (0.5 - offset + Math.floor(e.offsetX / pixel_size + offset)) * pixel_size;
let top = (0.5 - offset + Math.floor(e.offsetY / pixel_size + offset)) * pixel_size;
this.brush_outline.css('left', left+'px').css('top', top+'px');
//size
var radius = (BarItems.slider_brush_size.get()/2) * pixel_size;
this.brush_outline.css('padding', radius+'px').css('margin', (-radius)+'px');
}
this.updateBrushOutline(e)
})
scope.jquery.frame.on('mouseleave', e => {
this.brush_outline.detach();
})
this.setSize(this.size)
return this;
}
updateBrushOutline(e) {
if (Modes.paint && Toolbox.selected.brushTool) {
this.jquery.frame.append(this.brush_outline);
var pixel_size = this.inner_width / (this.texture ? this.texture.width : Project.texture_width);
//pos
let offset = BarItems.slider_brush_size.get()%2 == 0 && Toolbox.selected.brushTool ? 0.5 : 0;
let left = (0.5 - offset + Math.floor(e.offsetX / pixel_size + offset)) * pixel_size;
let top = (0.5 - offset + Math.floor(e.offsetY / pixel_size + offset)) * pixel_size;
this.brush_outline.css('left', left+'px').css('top', top+'px');
//size
var radius = (BarItems.slider_brush_size.get()/2) * pixel_size;
this.brush_outline.css('padding', radius+'px').css('margin', (-radius)+'px');
} else {
this.brush_outline.detach();
}
}
message(msg, vars) {
msg = tl(msg, vars)
var box = $('<div class="uv_message_box">' + msg + '</div>')
@ -703,12 +719,12 @@ class UVEditor {
this.jquery.viewport.css('overflow', 'hidden')
}
}
setFace(face, update) {
setFace(face, update = true) {
this.face = face
if (this.id === 'main_uv') {
$('input#'+face+'_radio').prop("checked", true)
}
if (update !== false) {
if (update) {
this.loadData()
}
return this;
@ -867,7 +883,7 @@ class UVEditor {
}
var tex = face ? face.getTexture() : textures[0];
if (!tex || typeof tex !== 'object' || (tex.error && tex.error != 2)) {
main_uv.img.src = '';
this.img.src = '';
this.img.style.display = 'none';
this.texture = false;
} else {
@ -1795,9 +1811,9 @@ const uv_dialog = {
}
},
updateSelection: function() {
$('#uv_dialog_all .UVEditor .uv_headline').removeClass('selected')
$('#uv_dialog_all .UVEditor').removeClass('selected')
uv_dialog.selection.forEach(function(id) {
$('#uv_dialog_all #UVEditor_'+id+' .uv_headline').addClass('selected')
$('#uv_dialog_all #UVEditor_'+id).addClass('selected')
})
},
openDialog: function() {

View File

@ -62,42 +62,6 @@ function getSelectionCenter() {
}
return center;
}
function isMovementGlobal() {
if (selected.length === 0 || (Toolbox.selected.id !== 'resize_tool')) {
return true;
}
if (Format.rotate_cubes) {
if (Cube.selected.length > 1) {
if (Cube.selected[0].rotation.equals([0,0,0])) return true;
var i = 0;
while (i < Cube.selected.length) {
if (!Cube.selected[0].rotation.equals(Cube.selected[i].rotation)) {
return true;
}
i++;
}
}
return Format.bone_rig && Group.selected;
}
if (Format.bone_rig) {
if (Cube.selected[0] && Cube.selected[0].parent.type === 'group') {
var ref_group = Cube.selected[0].parent
var i = 0;
while (i < Cube.selected.length) {
var obj = Cube.selected[i]
if (
obj.parent.type !== 'group' ||
!obj.parent.rotation.equals(ref_group.rotation)
) {
return true;
}
i++;
}
return false
}
return true;
}
}
//Canvas Restriction
function isInBox(val) {
return !(Format.canvas_limit && !settings.deactivate_size_limit.value) || (val < 32 && val > -16)
@ -229,7 +193,29 @@ const Vertexsnap = {
vertexes: new THREE.Object3D(),
vertexed_cubes: [],
hovering: false,
addVertexes: function(cube) {
createVertexGizmo(cube, vec, id) {
//Each vertex needs it's own material for hovering
let outline_color = '0x'+CustomTheme.data.colors.accent.replace('#', '')
let material = new THREE.MeshBasicMaterial({color: parseInt(outline_color)})
let mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material)
let pos = mesh.position.copy(vec)
pos.applyMatrix4(cube.mesh.matrixWorld)
if (!Format.centered_grid) {
pos.addScalar(8)
}
mesh.rotation.copy(cube.mesh.rotation)
if (id == 100) {
mesh.rotation.y += Math.PI/4;
}
mesh.cube = cube
mesh.isVertex = true
mesh.vertex_id = id
mesh.material.transparent = true;
mesh.renderOrder = 999;
Vertexsnap.vertexes.add(mesh)
},
addVertices: function(cube) {
if (Vertexsnap.vertexed_cubes.includes(cube)) return;
if (cube.visibility === false) return;
@ -239,21 +225,9 @@ const Vertexsnap = {
var o_vertices = cube.mesh.geometry.vertices
cube.mesh.updateMatrixWorld()
o_vertices.forEach(function(v, id) {
var outline_color = '0x'+CustomTheme.data.colors.accent.replace('#', '')
//Each vertex needs it's own material for hovering
var material = new THREE.MeshBasicMaterial({color: parseInt(outline_color)})
var mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material)
var pos = mesh.position.copy(v)
pos.applyMatrix4(cube.mesh.matrixWorld)
if (!Format.centered_grid) {
pos.addScalar(8)
}
mesh.rotation.copy(cube.mesh.rotation)
mesh.cube = cube
mesh.isVertex = true
mesh.vertex_id = id
Vertexsnap.vertexes.add(mesh)
Vertexsnap.createVertexGizmo(cube, v, id)
})
Vertexsnap.createVertexGizmo(cube, new THREE.Vector3(), 100)
Vertexsnap.vertexed_cubes.push(cube)
Vertexsnap.updateVertexSize()
},
@ -273,6 +247,7 @@ const Vertexsnap = {
Vertexsnap.vertexes.remove(v)
} else {
v.material.color.set(parseInt('0x'+CustomTheme.data.colors.accent.replace('#', '')))
v.material.depthTest = true;
}
})
}
@ -285,6 +260,8 @@ const Vertexsnap = {
vertex.material.color.g = 1
Vertexsnap.hovering = true
vertex.material.depthTest = false;
if (Vertexsnap.step1 === false) {
//Line
var geometry = new THREE.Geometry();
@ -302,7 +279,7 @@ const Vertexsnap = {
select: function() {
Vertexsnap.removeVertexes()
Cube.selected.forEach(function(obj) {
Vertexsnap.addVertexes(obj)
Vertexsnap.addVertices(obj)
})
if (Cube.selected.length) {
$('#preview').css('cursor', (Vertexsnap.step1 ? 'copy' : 'alias'))
@ -320,6 +297,7 @@ const Vertexsnap = {
Vertexsnap.cubes = Cube.selected.slice()
Vertexsnap.removeVertexes()
$('#preview').css('cursor', (Vertexsnap.step1 ? 'copy' : 'alias'))
} else {
Vertexsnap.snap(data)
$('#preview').css('cursor', (Vertexsnap.step1 ? 'copy' : 'alias'))
@ -329,55 +307,73 @@ const Vertexsnap = {
snap: function(data) {
Undo.initEdit({elements: Vertexsnap.cubes})
var global_delta = data.vertex.position
global_delta.sub(Vertexsnap.vertex_pos)
let mode = BarItems.vertex_snap_mode.get()
if (BarItems.vertex_snap_mode.get() === 'scale') {
//Scale
if (Vertexsnap.vertex_id === 100) {
var m;
switch (Vertexsnap.vertex_id) {
case 0: m=[ 1,1,1 ]; break;
case 1: m=[ 1,1,0 ]; break;
case 2: m=[ 1,0,1 ]; break;
case 3: m=[ 1,0,0 ]; break;
case 4: m=[ 0,1,0 ]; break;
case 5: m=[ 0,1,1 ]; break;
case 6: m=[ 0,0,0 ]; break;
case 7: m=[ 0,0,1 ]; break;
}
Vertexsnap.cubes.forEach(function(cube) {
let vec = new THREE.Vector3().copy(data.vertex.position)
Vertexsnap.cubes.forEach(function(obj) {
var q = obj.mesh.getWorldQuaternion(new THREE.Quaternion()).inverse()
var cube_pos = new THREE.Vector3().copy(global_delta).applyQuaternion(q)
for (i=0; i<3; i++) {
if (m[i] === 1) {
obj.to[i] = limitToBox(obj.to[i] + cube_pos.getComponent(i), obj.inflate)
} else {
obj.from[i] = limitToBox(obj.from[i] + cube_pos.getComponent(i), -obj.inflate)
}
}
if (Project.box_uv && obj.visibility) {
Canvas.updateUV(obj)
if (Format.bone_rig && cube.parent instanceof Group && cube.mesh.parent) {
cube.mesh.parent.worldToLocal(vec);
}
let vec_array = vec.toArray()
vec_array.V3_add(cube.parent.origin);
cube.transferOrigin(vec_array)
})
} else {
Vertexsnap.cubes.forEach(function(obj) {
var cube_pos = new THREE.Vector3().copy(global_delta)
if (Format.bone_rig && obj.parent instanceof Group && obj.mesh.parent) {
var q = obj.mesh.parent.getWorldQuaternion(new THREE.Quaternion()).inverse();
cube_pos.applyQuaternion(q);
var global_delta = data.vertex.position
global_delta.sub(Vertexsnap.vertex_pos)
if (mode === 'scale') {
//Scale
var m;
switch (Vertexsnap.vertex_id) {
case 0: m=[ 1,1,1 ]; break;
case 1: m=[ 1,1,0 ]; break;
case 2: m=[ 1,0,1 ]; break;
case 3: m=[ 1,0,0 ]; break;
case 4: m=[ 0,1,0 ]; break;
case 5: m=[ 0,1,1 ]; break;
case 6: m=[ 0,0,0 ]; break;
case 7: m=[ 0,0,1 ]; break;
}
if (Format.rotate_cubes) {
obj.origin.V3_add(cube_pos);
}
var in_box = obj.moveVector(cube_pos.toArray());
if (!in_box && Format.canvas_limit && !settings.deactivate_size_limit.value) {
Blockbench.showMessageBox({translateKey: 'canvas_limit_error'})
}
})
Vertexsnap.cubes.forEach(function(obj) {
var q = obj.mesh.getWorldQuaternion(new THREE.Quaternion()).inverse()
var cube_pos = new THREE.Vector3().copy(global_delta).applyQuaternion(q)
for (i=0; i<3; i++) {
if (m[i] === 1) {
obj.to[i] = limitToBox(obj.to[i] + cube_pos.getComponent(i), obj.inflate)
} else {
obj.from[i] = limitToBox(obj.from[i] + cube_pos.getComponent(i), -obj.inflate)
}
}
if (Project.box_uv && obj.visibility) {
Canvas.updateUV(obj)
}
})
} else if (mode === 'move') {
Vertexsnap.cubes.forEach(function(obj) {
var cube_pos = new THREE.Vector3().copy(global_delta)
if (Format.bone_rig && obj.parent instanceof Group && obj.mesh.parent) {
var q = obj.mesh.parent.getWorldQuaternion(new THREE.Quaternion()).inverse();
cube_pos.applyQuaternion(q);
}
if (Format.rotate_cubes) {
obj.origin.V3_add(cube_pos);
}
var in_box = obj.moveVector(cube_pos.toArray());
if (!in_box && Format.canvas_limit && !settings.deactivate_size_limit.value) {
Blockbench.showMessageBox({translateKey: 'canvas_limit_error'})
}
})
}
}
Vertexsnap.removeVertexes()
@ -518,7 +514,7 @@ function setScaleAllPivot(mode) {
}
function scaleAllSelectOverflow() {
cancelScaleAll()
selected.length = 0;
selected.empty();
scaleAll.overflow.forEach(obj => {
obj.selectLow()
})
@ -601,24 +597,36 @@ function moveElementsInSpace(difference, axis) {
if (el.resizable) el.to[axis] += difference;
if (el.rotatable) el.origin[axis] += difference;
} else {
let move_origin = !!group;
if (group_m) {
var m = group_m
} else {
var m = new THREE.Vector3();
m[getAxisLetter(axis)] = difference;
var rotation = new THREE.Quaternion();
if (el.mesh) {
el.mesh.getWorldQuaternion(rotation);
} else if (el.parent instanceof Group) {
el.parent.mesh.getWorldQuaternion(rotation);
let parent = el.parent;
while (parent instanceof Group) {
if (!parent.rotation.allEqual(0)) break;
parent = parent.parent;
}
if (parent == 'root') {
// If none of the parent groups are rotated, move origin.
move_origin = true;
} else {
var rotation = new THREE.Quaternion();
if (el.mesh) {
el.mesh.getWorldQuaternion(rotation);
} else if (el.parent instanceof Group) {
el.parent.mesh.getWorldQuaternion(rotation);
}
m.applyQuaternion(rotation.inverse());
}
m.applyQuaternion(rotation.inverse());
}
if (el.movable) el.from.V3_add(m.x, m.y, m.z);
if (el.resizable) el.to.V3_add(m.x, m.y, m.z);
if (group) {
if (move_origin) {
if (el.rotatable) el.origin.V3_add(m.x, m.y, m.z);
}
}
@ -1315,13 +1323,16 @@ BARS.defineActions(function() {
new Action('toggle_visibility', {
icon: 'visibility',
category: 'transform',
condition: {modes: ['edit']},
click: function () {toggleCubeProperty('visibility')}
})
new Action('toggle_locked', {
icon: 'fas.fa-lock',
category: 'transform',
click: function () {toggleCubeProperty('locked')}
})
new Action('toggle_export', {
icon: 'save',
category: 'transform',
condition: {modes: ['edit']},
click: function () {toggleCubeProperty('export')}
})
new Action('toggle_autouv', {
@ -1339,7 +1350,7 @@ BARS.defineActions(function() {
new Action('toggle_mirror_uv', {
icon: 'icon-mirror_x',
category: 'transform',
condition: () => Project.box_uv && Modes.edit,
condition: () => Project.box_uv && (Modes.edit || Modes.paint),
click: function () {toggleCubeProperty('shade')}
})
new Action('update_autouv', {

View File

@ -162,6 +162,9 @@ Math.lerp = function(a,b,m) {
Math.isBetween = function(n, a, b) {
return (n - a) * (n - b) <= 0
}
Math.epsilon = function(a, b, epsilon) {
return Math.abs(b - a) < epsilon
}
Math.trimDeg = function(a) {
return (a+180*15)%360-180
}
@ -181,13 +184,23 @@ Math.areMultiples = function(n1, n2) {
(n2/n1)%1 === 0
)
}
Math.getNextPower =function(num, min) {
Math.getNextPower = function(num, min) {
var i = min ? min : 2
while (i < num && i < 4000) {
i *= 2
}
return i;
}
Math.snapToValues = function(val, snap_points, epsilon = 12) {
let snaps = snap_points.slice().sort((a, b) => {
return Math.abs(val-a) - Math.abs(val-b)
})
if (Math.abs(snaps[0] - val) < epsilon) {
return snaps[0]
} else {
return val
}
}
function trimFloatNumber(val) {
if (val == '') return val;
var string = val.toFixed(4)
@ -332,13 +345,17 @@ Array.prototype.remove = function (item) { {
}
}
Array.prototype.empty = function() {
this.length = 0;
this.splice(0, Infinity);
return this;
}
Array.prototype.purge = function() {
this.splice(0, Infinity);
return this;
}
Array.prototype.replace = function(items) {
this.splice(0, Infinity, ...items);
return this;
}
Array.prototype.findInArray = function(key, value) {
for (var i = 0; i < this.length; i++) {
if (this[i][key] === value) return this[i]

View File

@ -33,6 +33,9 @@ function initializeWebApp() {
}
})
}
if (Blockbench.browser == 'firefox') {
document.body.style.imageRendering = 'crisp-edges'
}
}
setInterval(function() {

View File

@ -280,7 +280,6 @@
"keybind.cancel": "Abbrechen",
"action.slider_inflate": "Aufblasen",
"action.slider_inflate.desc": "Vergrößert Elemente in alle Richtungen, ohne dabei die Textur zu verändern",
"action.brush_mode": "Pinselmodus",
"action.slider_brush_size": "Radius",
"action.slider_brush_size.desc": "Radius des Pinsels in Pixeln",
"action.slider_brush_opacity": "Deckkraft",
@ -541,8 +540,6 @@
"dialog.update.latest": "Aktuelle Version",
"dialog.update.installed": "Installierte Version",
"dialog.update.update": "Aktualisieren",
"action.brush_mode.brush": "Rund",
"action.brush_mode.noise": "Rauschen",
"action.vertex_snap_mode.move": "Verschieben",
"action.vertex_snap_mode.scale": "Größe ändern",
"action.open_model_folder": "Modellordner öffnen",
@ -948,8 +945,6 @@
"settings.brush_size_modifier.desc": "Beeinflusse die Größe des Pinsels bei Benutzung von einem Stylus",
"settings.brush_modifier.pressure": "Druck",
"settings.brush_modifier.tilt": "Neigung",
"settings.class_export_version": "Mod-Entity Exportversopm",
"settings.class_export_version.desc": "Die Spielversion, für die Entitymodelle für Mods exportiert werden",
"category.color": "Farbe",
"action.import_theme": "Theme importieren",
"action.export_theme": "Theme exportieren",
@ -969,8 +964,6 @@
"action.generate_palette.desc": "Erstellt eine Palette aus einer Textur",
"action.sort_palette": "Palette sortieren",
"action.sort_palette.desc": "Sortiert alle Farben der Palette nach Farbton und Helligkeit",
"action.clear_palette": "Palette leeren",
"action.clear_palette.desc": "Alle Farben aus der Palette entfernen",
"action.timelapse": "Zeitraffer...",
"action.timelapse.desc": "Zeichnet eine Zeitrafferaufnahme von der Benutzung von Blockbench auf",
"action.add_keyframe": "Keyframe hinzufügen",
@ -1087,5 +1080,34 @@
"uv_editor.copy_paste_tool.cut": "Ausschneiden",
"uv_editor.copy_paste_tool.mirror_x": "Spiegeln (X)",
"uv_editor.copy_paste_tool.mirror_y": "Spiegeln (Y)",
"uv_editor.copy_paste_tool.rotate": "Um 90 Grad drehen"
"uv_editor.copy_paste_tool.rotate": "Um 90 Grad drehen",
"dialog.project.modded_entity_version": "Exportversion",
"dialog.save_angle.position": "Kameraposition",
"dialog.save_angle.target": "Zielpunkt",
"dialog.skin.pose": "Pose",
"layout.color.frame": "Fensterrahmen",
"layout.color.frame.desc": "Rand und Titelleiste des Fensters",
"settings.large_grid_size": "Block Grid Size",
"settings.large_grid_size.desc": "Size of the block grid",
"action.load_plugin_from_url": "Load Plugin from URL",
"action.load_plugin_from_url.desc": "Load a plugin from a server by specifying the URL",
"action.cube_counter.desc": "Displays the current number of cubes and other statistics",
"action.unlock_everything": "Unlock Everything",
"action.unlock_everything.desc": "Unlock all groups and elements in the outliner.",
"action.load_palette": "Palette laden",
"action.load_palette.desc": "Eine der mitgelieferten Paletten laden",
"action.toggle_locked": "Toggle Lock",
"action.toggle_locked.desc": "Toggle whether the selected elements are locked",
"action.apply_display_preset": "Apply Preset",
"action.apply_display_preset.desc": "Apply a default or custom display setting preset",
"action.apply_display_preset.here": "Apply To This Slot",
"action.apply_display_preset.everywhere": "Apply To All Slots",
"action.resolve_keyframe_expressions": "Resolve Keyframe",
"action.resolve_keyframe_expressions.desc": "Resolves the math expressions of the selected keyframes",
"action.fold_all_animations": "Fold All Animators",
"action.timeline_focus.used": "Verwendet",
"menu.palette.load.empty": "Leer",
"switches.lock": "Lock",
"camera_angle.isometric_right": "Isometric Right",
"camera_angle.isometric_left": "Isometric Left"
}

View File

@ -230,6 +230,7 @@
"dialog.project.parent": "Parent Model",
"dialog.project.geoname": "Model Identifier",
"dialog.project.openparent": "Open Parent",
"dialog.project.modded_entity_version": "Export Version",
"dialog.project.ao": "Ambient Occlusion",
"dialog.project.box_uv": "Box UV",
"dialog.project.width": "Texture Width",
@ -328,6 +329,8 @@
"dialog.save_angle.projection": "Projection",
"dialog.save_angle.projection.perspective": "Perspective",
"dialog.save_angle.projection.orthographic": "Orthographic",
"dialog.save_angle.position": "Camera Position",
"dialog.save_angle.target": "Focal Point",
"dialog.input.title": "Input",
@ -335,7 +338,6 @@
"dialog.update.refresh": "Refresh",
"dialog.update.up_to_date": "Blockbench is up to date!",
"dialog.update.connecting": "Connecting to server",
"dialog.update.refresh": "Retry",
"dialog.update.no_connection": "No internet connection",
"dialog.update.latest": "Latest Version",
"dialog.update.installed": "Installed Version",
@ -360,8 +362,9 @@
"dialog.model_stats.faces": "Faces",
"dialog.skin.title": "Create Skin",
"dialog.skin.model": "Skin",
"dialog.skin.model": "Model",
"dialog.skin.texture": "Texture (Optional)",
"dialog.skin.pose": "Pose",
"dialog.settings.settings": "Settings",
"dialog.settings.keybinds": "Keybindings",
@ -390,6 +393,8 @@
"layout.color.border.desc": "Border of buttons and inputs",
"layout.color.accent": "Accent",
"layout.color.accent.desc": "Slider thumb and other details",
"layout.color.frame": "Window Frame",
"layout.color.frame.desc": "Border and title bar of the window",
"layout.color.grid": "Grid",
"layout.color.grid.desc": "3D preview grid",
"layout.color.wireframe": "Wireframe",
@ -465,10 +470,12 @@
"settings.base_grid": "Small Grid",
"settings.base_grid.desc": "Show small grid and axes",
"settings.large_grid": "Large Grid",
"settings.large_grid.desc": "Show 3x3 block grid",
"settings.full_grid": "Full Large Grid",
"settings.full_grid.desc": "Show 3x3 precise grid",
"settings.large_grid": "Block Grid",
"settings.large_grid.desc": "Show 16x16 block-size grid",
"settings.large_grid_size": "Block Grid Size",
"settings.large_grid_size.desc": "Size of the block grid",
"settings.full_grid": "Precise Block Grid",
"settings.full_grid.desc": "Show pixel-precise block grid",
"settings.large_box": "Large Box",
"settings.large_box.desc": "Show 3x3 block boundaries",
"settings.display_grid": "Display Mode",
@ -516,8 +523,6 @@
"settings.brush_modifier.tilt": "Tilt",
"settings.brush_modifier.none": "None",
"settings.dialog_unsaved_textures": "Unsaved Textures",
"settings.dialog_unsaved_textures.desc": "Show \"Unsaved Textures\" dialog",
"settings.dialog_larger_cubes": "Model Too Large",
"settings.dialog_larger_cubes.desc": "Show \"Model Too Large\" dialog",
"settings.dialog_rotation_limit": "Rotation Limits",
@ -527,8 +532,6 @@
"settings.minifiedout.desc": "Write JSON file in one line",
"settings.export_groups": "Export Groups",
"settings.export_groups.desc": "Save groups in blockmodel files",
"settings.class_export_version": "Modded Entity Export Version",
"settings.class_export_version.desc": "The format version for modded entity models",
"settings.credit": "Credit Comment",
"settings.credit.desc": "Add a credit comment to exported files",
"settings.sketchfab_token": "Sketchfab Token",
@ -698,6 +701,8 @@
"action.reset_keybindings.desc": "Reset all keybindings to Blockbench's defaults",
"action.load_plugin": "Load Plugin from File",
"action.load_plugin.desc": "Load a plugin by importing the source file",
"action.load_plugin_from_url": "Load Plugin from URL",
"action.load_plugin_from_url.desc": "Load a plugin from a server by specifying the URL",
"action.reload_plugins": "Reload Plugins",
"action.reload_plugins.desc": "Reload all development plugins",
"action.reset_layout": "Reset Layout",
@ -732,7 +737,7 @@
"action.outliner_toggle": "Toggle More Options",
"action.outliner_toggle.desc": "Toggles switches for more options in the outliner",
"action.cube_counter": "Cube Counter",
"action.cube_counter": "Displays the current number of cubes and other statistics",
"action.cube_counter.desc": "Displays the current number of cubes and other statistics",
"action.duplicate": "Duplicate",
"action.duplicate.desc": "Duplicates the selected cubes or group",
@ -740,6 +745,8 @@
"action.delete.desc": "Deletes the selected cubes or group",
"action.sort_outliner": "Sort Outliner",
"action.sort_outliner.desc": "Sort the outliner alphabetically",
"action.unlock_everything": "Unlock Everything",
"action.unlock_everything.desc": "Unlock all groups and elements in the outliner.",
"action.element_colors": "Cube Colors",
"action.element_colors.desc": "Show cube colors in the outliner",
"action.select_window": "Select...",
@ -764,8 +771,8 @@
"action.generate_palette.desc": "Generate palette from a texture",
"action.sort_palette": "Sort Palette",
"action.sort_palette.desc": "Sort all colors on the palette by color and brightness",
"action.clear_palette": "Clear Palette",
"action.clear_palette.desc": "Remove all colors from the palette",
"action.load_palette": "Load Palette",
"action.load_palette.desc": "Load one of the built-in palette presets",
"action.transform_space": "Transform Space",
"action.transform_space.desc": "Default transform space for elements and bones",
@ -788,6 +795,8 @@
"action.toggle_visibility.desc": "Toggle the visibility of the selected cubes",
"action.toggle_export": "Toggle Export",
"action.toggle_export.desc": "Toggle the export setting of the selected cubes",
"action.toggle_locked": "Toggle Lock",
"action.toggle_locked.desc": "Toggle whether the selected elements are locked",
"action.toggle_autouv": "Toggle Auto UV",
"action.toggle_autouv.desc": "Toggle the auto UV setting of the selected cubes",
"action.toggle_shade": "Toggle Shading",
@ -801,6 +810,10 @@
"action.add_display_preset": "New Preset",
"action.add_display_preset.desc": "Add a new display setting preset",
"action.apply_display_preset": "Apply Preset",
"action.apply_display_preset.desc": "Apply a default or custom display setting preset",
"action.apply_display_preset.here": "Apply To This Slot",
"action.apply_display_preset.everywhere": "Apply To All Slots",
"action.gui_light": "GUI Light",
"action.gui_light.desc": "Select the way the item is lit in the inventory",
"action.gui_light.side": "Side Light",
@ -924,6 +937,8 @@
"action.change_keyframe_file.desc": "Select an audio file to preview a sound effect.",
"action.reset_keyframe": "Reset Keyframe",
"action.reset_keyframe.desc": "Reset all values of the selected keyframes",
"action.resolve_keyframe_expressions": "Resolve Keyframe",
"action.resolve_keyframe_expressions.desc": "Resolves the math expressions of the selected keyframes",
"action.reverse_keyframes": "Reverse Keyframes",
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes",
"action.select_all_keyframes": "Select All Keyframes",
@ -942,8 +957,9 @@
"action.previous_keyframe.desc": "Jump to the previous keyframe",
"action.next_keyframe": "Next Keyframe",
"action.next_keyframe.desc": "Jump to the next keyframe",
"action.bring_up_all_animations": "Bring Up All Animations",
"action.bring_up_all_animations": "Bring Up All Animators",
"action.bring_up_all_animations.desc": "Brings all modified animators into the timeline",
"action.fold_all_animations": "Fold All Animators",
"action.clear_timeline": "Clear Timeline",
"action.clear_timeline.desc": "Clear all unselected bones from the timeline",
"action.select_effect_animator": "Animate Effects",
@ -951,6 +967,7 @@
"action.timeline_focus": "Channel",
"action.timeline_focus.desc": "Select the animation channels to display in the timeline",
"action.timeline_focus.all": "All",
"action.timeline_focus.used": "In Use",
"timeline.rotation": "Rotation",
@ -1007,8 +1024,8 @@
"menu.group.sort": "Sort",
"menu.group.resolve": "Resolve",
"menu.palette.load": "Load Palette",
"menu.palette.load.default": "Default",
"menu.palette.load.empty": "Blank",
"menu.texture.face": "Apply to Face",
"menu.texture.blank": "Apply to Untextured Faces",
@ -1077,6 +1094,7 @@
"cube.color.lime": "Lime",
"switches.visibility": "Visibility",
"switches.lock": "Lock",
"switches.export": "Export",
"switches.shading": "Shade",
"switches.mirror": "Mirror UV",
@ -1152,6 +1170,9 @@
"direction.top": "Top",
"direction.bottom": "Bottom",
"camera_angle.isometric_right": "Isometric Right",
"camera_angle.isometric_left": "Isometric Left",
"dialog.edit_session.title": "Edit Session",
"edit_session.username": "Username",
"edit_session.token": "Token",

View File

@ -280,7 +280,6 @@
"keybind.cancel": "Cancelar",
"action.slider_inflate": "Inflar",
"action.slider_inflate.desc": "Inflar cubos en todas las direcciones sin cambiar el UV",
"action.brush_mode": "Modo Pincel",
"action.slider_brush_size": "Tamaño",
"action.slider_brush_size.desc": "Radio del pincel en píxeles",
"action.slider_brush_opacity": "Opacidad",
@ -541,8 +540,6 @@
"dialog.update.latest": "Última version",
"dialog.update.installed": "Versión instalada",
"dialog.update.update": "Actualizar",
"action.brush_mode.brush": "Redondo",
"action.brush_mode.noise": "Ruido",
"action.vertex_snap_mode.move": "Mover",
"action.vertex_snap_mode.scale": "Reescalar",
"action.open_model_folder": "Abrir la Carpeta del Modelo",
@ -948,8 +945,6 @@
"settings.brush_size_modifier.desc": "Modifica el tamaño del pincel al usar un lápiz",
"settings.brush_modifier.pressure": "Presión",
"settings.brush_modifier.tilt": "Inclinar",
"settings.class_export_version": "Versión de Exportación de Entidad de Mod",
"settings.class_export_version.desc": "La versión de formato para modelos de entidades de mod",
"category.color": "Color",
"action.import_theme": "Importar Tema",
"action.export_theme": "Exportar Tema",
@ -969,8 +964,6 @@
"action.generate_palette.desc": "Genera la paleta a partir de una textura",
"action.sort_palette": "Organizar Paleta",
"action.sort_palette.desc": "Organiza todos los colores de la paleta por color y brillo",
"action.clear_palette": "Limpiar Paleta",
"action.clear_palette.desc": "Elimina todos los colores de la Paleta",
"action.timelapse": "Timelapse...",
"action.timelapse.desc": "Graba un timelapse de tu proceso de modelaje",
"action.add_keyframe": "Añadir Frame Clave",
@ -1087,5 +1080,34 @@
"uv_editor.copy_paste_tool.cut": "Cortar",
"uv_editor.copy_paste_tool.mirror_x": "Invertir X",
"uv_editor.copy_paste_tool.mirror_y": "Invertir Y",
"uv_editor.copy_paste_tool.rotate": "Rotar 90 Grados"
"uv_editor.copy_paste_tool.rotate": "Rotar 90 Grados",
"dialog.project.modded_entity_version": "Export Version",
"dialog.save_angle.position": "Camera Position",
"dialog.save_angle.target": "Focal Point",
"dialog.skin.pose": "Pose",
"layout.color.frame": "Window Frame",
"layout.color.frame.desc": "Border and title bar of the window",
"settings.large_grid_size": "Block Grid Size",
"settings.large_grid_size.desc": "Size of the block grid",
"action.load_plugin_from_url": "Load Plugin from URL",
"action.load_plugin_from_url.desc": "Load a plugin from a server by specifying the URL",
"action.cube_counter.desc": "Displays the current number of cubes and other statistics",
"action.unlock_everything": "Unlock Everything",
"action.unlock_everything.desc": "Unlock all groups and elements in the outliner.",
"action.load_palette": "Load Palette",
"action.load_palette.desc": "Load one of the built-in palette presets",
"action.toggle_locked": "Toggle Lock",
"action.toggle_locked.desc": "Toggle whether the selected elements are locked",
"action.apply_display_preset": "Apply Preset",
"action.apply_display_preset.desc": "Apply a default or custom display setting preset",
"action.apply_display_preset.here": "Apply To This Slot",
"action.apply_display_preset.everywhere": "Apply To All Slots",
"action.resolve_keyframe_expressions": "Resolve Keyframe",
"action.resolve_keyframe_expressions.desc": "Resolves the math expressions of the selected keyframes",
"action.fold_all_animations": "Fold All Animators",
"action.timeline_focus.used": "In Use",
"menu.palette.load.empty": "Blank",
"switches.lock": "Lock",
"camera_angle.isometric_right": "Isometric Right",
"camera_angle.isometric_left": "Isometric Left"
}

View File

@ -280,7 +280,6 @@
"keybind.cancel": "Annuler",
"action.slider_inflate": "Gonflement",
"action.slider_inflate.desc": "Grossir les cubes dans toutes les directions sans changer les UV.",
"action.brush_mode": "Mode pinceau",
"action.slider_brush_size": "Taille",
"action.slider_brush_size.desc": "Rayon du pinceau en pixels",
"action.slider_brush_opacity": "Opacité",
@ -541,8 +540,6 @@
"dialog.update.latest": "Dernière version",
"dialog.update.installed": "Version installée",
"dialog.update.update": "Mettre à jour",
"action.brush_mode.brush": "Rond",
"action.brush_mode.noise": "Bruit",
"action.vertex_snap_mode.move": "Déplacer",
"action.vertex_snap_mode.scale": "Redimensionner",
"action.open_model_folder": "Ouvrir le dossier du modèle",
@ -948,8 +945,6 @@
"settings.brush_size_modifier.desc": "Modifier la taille du pinceau avec un stylet",
"settings.brush_modifier.pressure": "Pression",
"settings.brush_modifier.tilt": "Inclinaison",
"settings.class_export_version": "Version d'export d'entité moddée",
"settings.class_export_version.desc": "Version de format pour des modèles d'entités moddées",
"category.color": "Couleur",
"action.import_theme": "Thème d'importation",
"action.export_theme": "Thème d'exportation",
@ -969,8 +964,6 @@
"action.generate_palette.desc": "Générer une palette à partir d'une texture",
"action.sort_palette": "Trier palette",
"action.sort_palette.desc": "Trier toutes les couleurs par teinte et luminosité",
"action.clear_palette": "Vider la palette",
"action.clear_palette.desc": "Retire toutes les couleurs de la palette",
"action.timelapse": "Timelapse…",
"action.timelapse.desc": "Enregistrer un timelapse de la modélisation",
"action.add_keyframe": "Ajouter une keyframe",
@ -1087,5 +1080,34 @@
"uv_editor.copy_paste_tool.cut": "Couper",
"uv_editor.copy_paste_tool.mirror_x": "Miroir X",
"uv_editor.copy_paste_tool.mirror_y": "Miroir Y",
"uv_editor.copy_paste_tool.rotate": "Rotation de 90 degrés"
"uv_editor.copy_paste_tool.rotate": "Rotation de 90 degrés",
"dialog.project.modded_entity_version": "Export Version",
"dialog.save_angle.position": "Camera Position",
"dialog.save_angle.target": "Focal Point",
"dialog.skin.pose": "Pose",
"layout.color.frame": "Window Frame",
"layout.color.frame.desc": "Border and title bar of the window",
"settings.large_grid_size": "Block Grid Size",
"settings.large_grid_size.desc": "Size of the block grid",
"action.load_plugin_from_url": "Load Plugin from URL",
"action.load_plugin_from_url.desc": "Load a plugin from a server by specifying the URL",
"action.cube_counter.desc": "Displays the current number of cubes and other statistics",
"action.unlock_everything": "Unlock Everything",
"action.unlock_everything.desc": "Unlock all groups and elements in the outliner.",
"action.load_palette": "Load Palette",
"action.load_palette.desc": "Load one of the built-in palette presets",
"action.toggle_locked": "Toggle Lock",
"action.toggle_locked.desc": "Toggle whether the selected elements are locked",
"action.apply_display_preset": "Apply Preset",
"action.apply_display_preset.desc": "Apply a default or custom display setting preset",
"action.apply_display_preset.here": "Apply To This Slot",
"action.apply_display_preset.everywhere": "Apply To All Slots",
"action.resolve_keyframe_expressions": "Resolve Keyframe",
"action.resolve_keyframe_expressions.desc": "Resolves the math expressions of the selected keyframes",
"action.fold_all_animations": "Fold All Animators",
"action.timeline_focus.used": "In Use",
"menu.palette.load.empty": "Blank",
"switches.lock": "Lock",
"camera_angle.isometric_right": "Isometric Right",
"camera_angle.isometric_left": "Isometric Left"
}

View File

@ -280,7 +280,6 @@
"keybind.cancel": "Annulla",
"action.slider_inflate": "Gonfiare",
"action.slider_inflate.desc": "Gonfiare cubi in tutte le direzioni non modificando l'UV",
"action.brush_mode": "Modalità Pennello",
"action.slider_brush_size": "Dimensione",
"action.slider_brush_size.desc": "Raggio del pennello in pixel",
"action.slider_brush_opacity": "Opacità",
@ -541,8 +540,6 @@
"dialog.update.latest": "Versione più Recente",
"dialog.update.installed": "Versione Installata",
"dialog.update.update": "Aggiornamento",
"action.brush_mode.brush": "Pennello",
"action.brush_mode.noise": "Sfumatura",
"action.vertex_snap_mode.move": "Muovi",
"action.vertex_snap_mode.scale": "Scala",
"action.open_model_folder": "Apri Cartella Modello",
@ -875,7 +872,7 @@
"panel.element.origin": "Origine",
"panel.element.rotation": "Rotazione",
"message.canvas_limit_error.title": "Errore di Limite della Tela",
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the pivot point to prevent this.",
"message.canvas_limit_error.message": "L'azione non può essere eseguita correttamente perché il formato limita la tela a 48 unità. Spostare il punto di articolazione per impedirlo.",
"data.effect": "Effetto",
"generic.name": "Nome",
"settings.recent_projects": "Limite Modelli Recenti",
@ -929,7 +926,7 @@
"message.timelapse_start": "Timelapse avviato",
"message.timelapse_stop": "Timelapse interrotto",
"message.import_palette.replace_palette": "Sostituisci vecchia tavolozza",
"message.import_palette.threshold": "Merge Threshold",
"message.import_palette.threshold": "Unisci soglia",
"dialog.timelapse.interval": "Intervallo (Secondi)",
"dialog.timelapse.source": "Sorgente",
"dialog.timelapse.source.interface": "Interfaccia",
@ -941,15 +938,13 @@
"layout.css": "CSS Personalizzato",
"settings.category.paint": "Dipingere",
"settings.deactivate_size_limit": "Disattiva Limite Dimensioni",
"settings.deactivate_size_limit.desc": "Deactivate the size limit for specific model formats. WARNING: This can cause invalid models.",
"settings.deactivate_size_limit.desc": "Disattiva il limite di dimensioni per formati di modelli specifici. ATTENZIONE: ciò può causare modelli non validi.",
"settings.brush_opacity_modifier": "Modificatore Opacità Pennello",
"settings.brush_opacity_modifier.desc": "Modifica l'opacità del pennello quando viene utilizzato uno stilo",
"settings.brush_size_modifier": "Modificatore Dimensioni Pennello",
"settings.brush_size_modifier.desc": "Modify the brush size when using a stylus",
"settings.brush_size_modifier.desc": "Modifica le dimensioni del pennello quando si utilizza uno stilo",
"settings.brush_modifier.pressure": "Pressione",
"settings.brush_modifier.tilt": "Inclinazione",
"settings.class_export_version": "Versione Entity Export per Mod",
"settings.class_export_version.desc": "La versione del formato per modelli entity per i mod",
"category.color": "Colore",
"action.import_theme": "Importa Tema",
"action.export_theme": "Esporta Tema",
@ -969,13 +964,11 @@
"action.generate_palette.desc": "Genera una tavolozza da una texture",
"action.sort_palette": "Ordina Tavolozza",
"action.sort_palette.desc": "Ordina tutti i colori della tavolozza per colore e luminosità",
"action.clear_palette": "Pulisci Tavolozza",
"action.clear_palette.desc": "Rimuovi tutti i colori dalla tavolozza",
"action.timelapse": "Timelapse...",
"action.timelapse.desc": "Registra un timelapse del tuo processo di modellazione",
"action.add_keyframe": "Aggiungi Fotogramma",
"action.add_keyframe.desc": "Aggiungi un fotogramma automaticamente. Premi shift per forzare valori predefinti",
"action.bring_up_all_animations.desc": "Brings all modified animators into the timeline",
"action.bring_up_all_animations.desc": "Porta tutti gli animatori modificati nella sequenza temporale",
"timeline.timeline": "Istruzioni",
"menu.palette.load": "Carica Tavolozza",
"menu.palette.load.default": "Predefinita",
@ -1012,21 +1005,21 @@
"menu.help.donate": "Dona",
"menu.help.about": "Informazioni",
"menu.preview.background.clipboard": "Carica dagli Appunti",
"dialog.ignore": "Ignore",
"generic.unset": "Unset",
"dialog.ignore": "Ignora",
"generic.unset": "Non settato",
"message.invalid_builtin_parent.title": "Invalid Built-in Parent",
"message.invalid_builtin_parent.message": "The link to the invalid parent model '%0' was removed in order to export a valid model.",
"dialog.resize_texture.fill": "Fill with",
"dialog.resize_texture.fill.transparent": "Transparent",
"dialog.resize_texture.fill.color": "Color",
"dialog.resize_texture.fill.repeat": "Repeat",
"dialog.resize_texture.fill.stretch": "Stretch",
"message.invalid_builtin_parent.message": "Il collegamento al modello principale non valido '% 0' è stato rimosso per esportare un modello valido.",
"dialog.resize_texture.fill": "Riempire con",
"dialog.resize_texture.fill.transparent": "Trasparente",
"dialog.resize_texture.fill.color": "Colore",
"dialog.resize_texture.fill.repeat": "Ripeti",
"dialog.resize_texture.fill.stretch": "Allunga",
"dialog.scale.element_pivot": "Element Pivot",
"dialog.scale.selection_center": "Selection Center",
"dialog.create_gif.length_mode": "Length Mode",
"dialog.create_gif.length_mode.seconds": "Seconds",
"dialog.create_gif.length_mode.frames": "Frames",
"dialog.create_gif.length_mode.animation": "Animation Length",
"dialog.scale.selection_center": "Centro di Selezione",
"dialog.create_gif.length_mode": "Modalità lunghezza",
"dialog.create_gif.length_mode.seconds": "Secondi",
"dialog.create_gif.length_mode.frames": "Montatura",
"dialog.create_gif.length_mode.animation": "Lunghezza della'animazione",
"dialog.create_gif.length_mode.turntable": "Turntable Rotation",
"dialog.save_angle.projection": "Projection",
"dialog.save_angle.projection.perspective": "Perspective",
@ -1087,5 +1080,34 @@
"uv_editor.copy_paste_tool.cut": "Cut",
"uv_editor.copy_paste_tool.mirror_x": "Mirror X",
"uv_editor.copy_paste_tool.mirror_y": "Mirror Y",
"uv_editor.copy_paste_tool.rotate": "Rotate 90 Degrees"
"uv_editor.copy_paste_tool.rotate": "Rotate 90 Degrees",
"dialog.project.modded_entity_version": "Export Version",
"dialog.save_angle.position": "Camera Position",
"dialog.save_angle.target": "Focal Point",
"dialog.skin.pose": "Pose",
"layout.color.frame": "Window Frame",
"layout.color.frame.desc": "Border and title bar of the window",
"settings.large_grid_size": "Block Grid Size",
"settings.large_grid_size.desc": "Size of the block grid",
"action.load_plugin_from_url": "Load Plugin from URL",
"action.load_plugin_from_url.desc": "Load a plugin from a server by specifying the URL",
"action.cube_counter.desc": "Displays the current number of cubes and other statistics",
"action.unlock_everything": "Unlock Everything",
"action.unlock_everything.desc": "Unlock all groups and elements in the outliner.",
"action.load_palette": "Load Palette",
"action.load_palette.desc": "Load one of the built-in palette presets",
"action.toggle_locked": "Toggle Lock",
"action.toggle_locked.desc": "Toggle whether the selected elements are locked",
"action.apply_display_preset": "Apply Preset",
"action.apply_display_preset.desc": "Apply a default or custom display setting preset",
"action.apply_display_preset.here": "Apply To This Slot",
"action.apply_display_preset.everywhere": "Apply To All Slots",
"action.resolve_keyframe_expressions": "Resolve Keyframe",
"action.resolve_keyframe_expressions.desc": "Resolves the math expressions of the selected keyframes",
"action.fold_all_animations": "Fold All Animators",
"action.timeline_focus.used": "In Use",
"menu.palette.load.empty": "Blank",
"switches.lock": "Lock",
"camera_angle.isometric_right": "Isometric Right",
"camera_angle.isometric_left": "Isometric Left"
}

View File

@ -280,7 +280,6 @@
"keybind.cancel": "キャンセル",
"action.slider_inflate": "Inflate",
"action.slider_inflate.desc": "UVを変えずにキューブを膨張させる",
"action.brush_mode": "Brush Mode",
"action.slider_brush_size": "Size",
"action.slider_brush_size.desc": "ブラシの半径",
"action.slider_brush_opacity": "Opacity",
@ -541,8 +540,6 @@
"dialog.update.latest": "最新のバージョン",
"dialog.update.installed": "インストールされたバージョン",
"dialog.update.update": "更新する",
"action.brush_mode.brush": "Round",
"action.brush_mode.noise": "Noise",
"action.vertex_snap_mode.move": "Move",
"action.vertex_snap_mode.scale": "Scale",
"action.open_model_folder": "モデルフォルダを開く",
@ -948,8 +945,6 @@
"settings.brush_size_modifier.desc": "ブラシの大きさを変更します",
"settings.brush_modifier.pressure": "筆圧",
"settings.brush_modifier.tilt": "チルト",
"settings.class_export_version": "エンティティエクスポートバージョン",
"settings.class_export_version.desc": "modエンティティモデルのバージョンを変更します",
"category.color": "カラー",
"action.import_theme": "テーマをインポート",
"action.export_theme": "テーマをエクスポート",
@ -969,8 +964,6 @@
"action.generate_palette.desc": "テクスチャからパレットを生成します",
"action.sort_palette": "ソート",
"action.sort_palette.desc": "パレット上のすべてのカラーを色と明るさで並べ替えます",
"action.clear_palette": "クリアー",
"action.clear_palette.desc": "パレット上のすべてのカラーを削除します",
"action.timelapse": "タイムラプス…",
"action.timelapse.desc": "モデリングプロセスのタイムラプスを記録します",
"action.add_keyframe": "キーフレームを追加",
@ -1087,5 +1080,34 @@
"uv_editor.copy_paste_tool.cut": "カット",
"uv_editor.copy_paste_tool.mirror_x": "Mirror X",
"uv_editor.copy_paste_tool.mirror_y": "Mirror Y",
"uv_editor.copy_paste_tool.rotate": "Rotate 90°"
"uv_editor.copy_paste_tool.rotate": "Rotate 90°",
"dialog.project.modded_entity_version": "Export Version",
"dialog.save_angle.position": "Camera Position",
"dialog.save_angle.target": "Focal Point",
"dialog.skin.pose": "Pose",
"layout.color.frame": "Window Frame",
"layout.color.frame.desc": "Border and title bar of the window",
"settings.large_grid_size": "Block Grid Size",
"settings.large_grid_size.desc": "Size of the block grid",
"action.load_plugin_from_url": "Load Plugin from URL",
"action.load_plugin_from_url.desc": "Load a plugin from a server by specifying the URL",
"action.cube_counter.desc": "Displays the current number of cubes and other statistics",
"action.unlock_everything": "Unlock Everything",
"action.unlock_everything.desc": "Unlock all groups and elements in the outliner.",
"action.load_palette": "Load Palette",
"action.load_palette.desc": "Load one of the built-in palette presets",
"action.toggle_locked": "Toggle Lock",
"action.toggle_locked.desc": "Toggle whether the selected elements are locked",
"action.apply_display_preset": "Apply Preset",
"action.apply_display_preset.desc": "Apply a default or custom display setting preset",
"action.apply_display_preset.here": "Apply To This Slot",
"action.apply_display_preset.everywhere": "Apply To All Slots",
"action.resolve_keyframe_expressions": "Resolve Keyframe",
"action.resolve_keyframe_expressions.desc": "Resolves the math expressions of the selected keyframes",
"action.fold_all_animations": "Fold All Animators",
"action.timeline_focus.used": "In Use",
"menu.palette.load.empty": "Blank",
"switches.lock": "Lock",
"camera_angle.isometric_right": "Isometric Right",
"camera_angle.isometric_left": "Isometric Left"
}

View File

@ -83,7 +83,7 @@
"message.default_textures.select": "Selecteer de standaard \"textures\"-map",
"message.image_editor.title": "Selecteer een afbeelding-bewerker",
"message.image_editor.file": "Selecteer Bestand...",
"message.image_editor.exe": "Selecteer een foto-editor uitvoerbaar bestand",
"message.image_editor.exe": "Selecteer een foto-bewerker uitvoerbaar bestand",
"message.display_skin.title": "Toon Skin",
"message.display_skin.message": "Selecteer een skin bestand van je computer of vul een spelernaam in",
"message.display_skin.upload": "Upload Skin",
@ -206,8 +206,8 @@
"settings.show_actions.desc": "Toon alle acties in de status balk",
"settings.backup_interval": "Backup Frequentie",
"settings.backup_interval.desc": "Frequentie van de automatische backups in minuten",
"settings.origin_size": "Oorsprong Markeerder",
"settings.origin_size.desc": "Grootte van de rotatie oorsprong",
"settings.origin_size": "Draaipunt Markeerder",
"settings.origin_size.desc": "Grootte van rotatie draaipunt markeerder",
"settings.control_size": "As Controle Grootte",
"settings.control_size.desc": "Grootte van de 3 assen controle gereedschap",
"settings.display_skin": "Toon Skin",
@ -280,7 +280,6 @@
"keybind.cancel": "Annuleer",
"action.slider_inflate": "Opblazen",
"action.slider_inflate.desc": "Kubussen alle kanten op opblazen zonder de UV te veranderen",
"action.brush_mode": "Mode",
"action.slider_brush_size": "Grootte",
"action.slider_brush_size.desc": "Formaat van de kwast",
"action.slider_brush_opacity": "Doorzichtigheid",
@ -302,7 +301,7 @@
"action.resize_tool": "Formaat veranderen",
"action.resize_tool.desc": "Gereedschap om elementen te selecteren en te vergrootten",
"action.brush_tool": "Verfkwast",
"action.brush_tool.desc": "Gereedschap om te tekenen op bitmap texturen op oppervlakken of in de UV editor.",
"action.brush_tool.desc": "Gereedschap om te tekenen op bitmap texturen op oppervlakken of in de UV bewerker.",
"action.vertex_snap_tool": "Hoeken Snap",
"action.vertex_snap_tool.desc": "Beweeg een kubus naar een ander kubus door twee hoeken te verbinden",
"action.swap_tools": "Verwissel Gereedschap",
@ -413,8 +412,8 @@
"action.save_textures.desc": "Sla alle niet-opgeslagen texturen op",
"action.animated_textures": "Start Geanimeerde Texturen",
"action.animated_textures.desc": "Start en pauzeer de weergave van geanimeerde texturen",
"action.origin_to_geometry": "Centreer Oorsprong",
"action.origin_to_geometry.desc": "Zet de oorsprong naar het midden van de geometrie",
"action.origin_to_geometry": "Centreer Draaipunt",
"action.origin_to_geometry.desc": "Zet het draaipunt naar het midden van de geometrie",
"action.rescale_toggle": "Zet Herschaal Aan/Uit",
"action.rescale_toggle.desc": "Herschaal kubussen gebaseerd op hun huidige rotatie",
"action.bone_reset_toggle": "Herstel bot",
@ -488,7 +487,7 @@
"panel.display": "Toning",
"panel.textures": "Afbeeldingen",
"panel.outliner": "Omlijning",
"uv_editor.title": "UV Editor",
"uv_editor.title": "UV Bewerker",
"uv_editor.all_faces": "Alle",
"uv_editor.no_faces": "Geen",
"face.north": "Noord",
@ -541,8 +540,6 @@
"dialog.update.latest": "Laatste Versie",
"dialog.update.installed": "Geïnstalleerde Versie",
"dialog.update.update": "Update",
"action.brush_mode.brush": "Penseel",
"action.brush_mode.noise": "Lawaai ",
"action.vertex_snap_mode.move": "Beweeg",
"action.vertex_snap_mode.scale": "Schaal",
"action.open_model_folder": "Open Model Map",
@ -707,7 +704,7 @@
"language_name": "Nederlands",
"message.plugin_reload": "%0 lokale plugins herlaadden",
"settings.brightness": "Helderheid",
"settings.brightness.desc": "Helderheid van de ",
"settings.brightness.desc": "Helderheid van de voorvertoning. Standaard is 50",
"menu.preview.perspective.reset": "Herstel Camera",
"action.fill_mode": "Vul Modus",
"action.fill_mode.face": "Oppervlak",
@ -725,7 +722,7 @@
"keybindings.recording": "Neem Toetsbinding Op",
"keybindings.press": "Druk op een knop of een combinatie van knoppen of klik ergens op het scherm om toetsbinding op te nemen",
"action.pivot_tool": "Draai Gereedschap",
"action.pivot_tool.desc": "Gereedschap om het pivot punt van de kubussen en botten te veranderen",
"action.pivot_tool.desc": "Gereedschap om het Draaipunt van de kubussen en botten te veranderen",
"action.slider_animation_speed": "Terugspeelsnelheid",
"action.slider_animation_speed.desc": "Terugspeelsnelheid van de tijdlijn in percent",
"action.previous_keyframe": "Vorige Keyframe",
@ -747,7 +744,7 @@
"settings.sketchfab_token": "Sketchfab Token",
"settings.sketchfab_token.desc": "Token om blockbench te autoriseren om te uploaden naar u Sketchfab account",
"panel.color": "Kleur",
"data.origin": "Rotatie",
"data.origin": "Draaipunt",
"message.sketchfab.success": "Model succesvol geüpload",
"message.sketchfab.error": "Gefaald om model up te loaden naar Sketchfab",
"settings.outliner_colors": "Omlijning Kleuren",
@ -872,10 +869,10 @@
"panel.element": "Element",
"panel.element.position": "Positie",
"panel.element.size": "Grootte",
"panel.element.origin": "Rotatie Punt",
"panel.element.origin": "Draaipunt",
"panel.element.rotation": "Rotatie",
"message.canvas_limit_error.title": "Canvas limiet Error",
"message.canvas_limit_error.message": "De actie kon niet correct worden uitgevoerd omdat het format het canvas limiteert tot 48 eenheden. Verschuif de rotatie oorsprong om dit te voorkomen.",
"message.canvas_limit_error.message": "De actie kon niet correct worden uitgevoerd omdat het format het canvas limiteert tot 48 eenheden. Verschuif het draaipunt om dit te voorkomen.",
"data.effect": "Effect",
"generic.name": "Naam",
"settings.recent_projects": "Recent Model Limiet",
@ -908,8 +905,8 @@
"action.slider_size.desc": "Herschaal kubussen op de %0 as",
"action.slider_rotation": "Roteer %0",
"action.slider_rotation.desc": "Roteer kubussen op de %0 as",
"action.slider_origin": "Oorsprong %0",
"action.slider_origin.desc": "Verplaats oorsprong op de %0 as",
"action.slider_origin": "Draaipunt %0",
"action.slider_origin.desc": "Verplaats draaipunt op de %0 as",
"action.rotate_cw": "Roteer %0 +90",
"action.rotate_cw.desc": "Roteer de geselecteerde kubussen 90° om de %0 as",
"action.rotate_ccw": "Roteer %0 -90",
@ -935,7 +932,7 @@
"dialog.timelapse.source.interface": "Deactiveer het grootte limiet voor specifieke model formaten. WARNING: Dit kan ongeldige modellen veroorzaken.",
"dialog.timelapse.source.locked": "Vastgezette Hoek",
"dialog.timelapse.destination": "Bestemmingsmap",
"layout.color.checkerboard": "Schaakbord",
"layout.color.checkerboard": "Dambord",
"layout.color.checkerboard.desc": "Achtergrond van canvas en UV editor",
"layout.font.code": "Code Font",
"layout.css": "Custom CSS",
@ -948,8 +945,6 @@
"settings.brush_size_modifier.desc": "Bewerk de kwast grootte wanneer een pen wordt gebruikt",
"settings.brush_modifier.pressure": "Druk",
"settings.brush_modifier.tilt": "Tilt",
"settings.class_export_version": "Modded Entity Exporteer Versie",
"settings.class_export_version.desc": "De formaat versie voor modded entity modellen",
"category.color": "Kleur",
"action.import_theme": "Importeer Thema",
"action.export_theme": "Exporteer Thema",
@ -969,8 +964,6 @@
"action.generate_palette.desc": "Genereer palette van een textuur",
"action.sort_palette": "Sorteer Palet",
"action.sort_palette.desc": "Sorteer alle kleuren op het palet op basis van kleur en helderheid",
"action.clear_palette": "Maak Palet Schoon",
"action.clear_palette.desc": "Verwijder alle kleuren van het palet",
"action.timelapse": "Timelapse...",
"action.timelapse.desc": "Neem een timelapse van u modeleer proces op",
"action.add_keyframe": "Voeg Keyframe toe",
@ -1012,55 +1005,55 @@
"menu.help.donate": "Doneer",
"menu.help.about": "Over...",
"menu.preview.background.clipboard": "Laad van Klembord",
"dialog.ignore": "Ignore",
"generic.unset": "Unset",
"message.invalid_builtin_parent.title": "Invalid Built-in Parent",
"message.invalid_builtin_parent.message": "The link to the invalid parent model '%0' was removed in order to export a valid model.",
"dialog.resize_texture.fill": "Fill with",
"dialog.resize_texture.fill.transparent": "Transparent",
"dialog.resize_texture.fill.color": "Color",
"dialog.resize_texture.fill.repeat": "Repeat",
"dialog.ignore": "Negeer",
"generic.unset": "Ongezet",
"message.invalid_builtin_parent.title": "Ongeldige Ingebouwde Ouder",
"message.invalid_builtin_parent.message": "De link naar het ongeldige ouder model '%0' was verwijderd om een geldig model te exporteren",
"dialog.resize_texture.fill": "Vul met",
"dialog.resize_texture.fill.transparent": "Transparant",
"dialog.resize_texture.fill.color": "Kleur",
"dialog.resize_texture.fill.repeat": "Herhaal",
"dialog.resize_texture.fill.stretch": "Stretch",
"dialog.scale.element_pivot": "Element Pivot",
"dialog.scale.selection_center": "Selection Center",
"dialog.create_gif.length_mode": "Length Mode",
"dialog.create_gif.length_mode.seconds": "Seconds",
"dialog.create_gif.length_mode.frames": "Frames",
"dialog.create_gif.length_mode.animation": "Animation Length",
"dialog.create_gif.length_mode.turntable": "Turntable Rotation",
"dialog.save_angle.projection": "Projection",
"dialog.save_angle.projection.perspective": "Perspective",
"dialog.save_angle.projection.orthographic": "Orthographic",
"dialog.sketchfab_uploader.animations": "Animations",
"dialog.settings.theme": "Theme",
"dialog.scale.element_pivot": "Element Draaipunt",
"dialog.scale.selection_center": "Selectie Midden",
"dialog.create_gif.length_mode": "Lengte Modus",
"dialog.create_gif.length_mode.seconds": "Seconden",
"dialog.create_gif.length_mode.frames": "Beelden",
"dialog.create_gif.length_mode.animation": "Animatie Lengte",
"dialog.create_gif.length_mode.turntable": "Draaitafel Rotatie",
"dialog.save_angle.projection": "Projectie",
"dialog.save_angle.projection.perspective": "Perspectief",
"dialog.save_angle.projection.orthographic": "Orthografisch",
"dialog.sketchfab_uploader.animations": "Animaties",
"dialog.settings.theme": "Thema",
"settings.category.interface": "Interface",
"settings.preview_checkerboard": "Preview Checkerboard",
"settings.preview_checkerboard.desc": "Toggle the checkerboard background behind the preview",
"settings.uv_checkerboard": "UV Editor Checkerboard",
"settings.uv_checkerboard.desc": "Toggle the checkerboard background behind the UV editor",
"category.paint": "Paint",
"action.fill_mode.color_connected": "Connected Colors",
"action.draw_shape_type": "Shape Type",
"action.draw_shape_type.rectangle": "Rectangle",
"action.draw_shape_type.rectangle_h": "Rectangle (Hollow)",
"action.draw_shape_type.ellipse": "Ellipse",
"action.draw_shape_type.ellipse_h": "Ellipse (Hollow)",
"action.draw_shape_type.line": "Line",
"action.mirror_painting": "Mirror Painting",
"action.mirror_painting.description": "Mirror your paint strokes to the other side of the model",
"action.lock_alpha": "Lock Alpha Channel",
"action.lock_alpha.description": "Lock the transparency of all pixels",
"action.draw_shape_tool": "Draw Shape",
"action.draw_shape_tool.desc": "Tool to draw simple shapes on textures",
"action.copy_paste_tool": "Copy Paste Tool",
"action.copy_paste_tool.desc": "Tool to copy and paste selections of textures",
"action.export_gltf": "Export As glTF",
"action.export_gltf.desc": "Export model and animations as glTF file to use in other 3D applications",
"action.transform_space": "Transform Space",
"action.transform_space.desc": "Default transform space for elements and bones",
"action.transform_space.global": "Global",
"action.transform_space.bone": "Bone",
"action.transform_space.local": "Local",
"settings.preview_checkerboard": "Preview Dambord",
"settings.preview_checkerboard.desc": "Zet de dambord achtergrond achter de voorvertoning",
"settings.uv_checkerboard": "UV Bewerker Dambord",
"settings.uv_checkerboard.desc": "Zet de dambord achtergrond achter de UV bewerker",
"category.paint": "Verf",
"action.fill_mode.color_connected": "Verbonden Kleuren",
"action.draw_shape_type": "Vorm Type",
"action.draw_shape_type.rectangle": "Rechthoek",
"action.draw_shape_type.rectangle_h": "Rechthoek (Hol)",
"action.draw_shape_type.ellipse": "Elipse",
"action.draw_shape_type.ellipse_h": "Elipse (Hol)",
"action.draw_shape_type.line": "Lijn",
"action.mirror_painting": "Spiegel Schilderij",
"action.mirror_painting.description": "Spiegel je verfstreken naar de andere kant van het model",
"action.lock_alpha": "Zet Alpha Kanaal Vast",
"action.lock_alpha.description": "Zet de doorzichtigheid van alle pixels vast",
"action.draw_shape_tool": "Teken Vorm",
"action.draw_shape_tool.desc": "Gereedschap om simpele vormen op texturen tekenen",
"action.copy_paste_tool": "Kopieer Plak Gereedschap",
"action.copy_paste_tool.desc": "Gereedschap om selecties van texturen te kopiëren en te plakken",
"action.export_gltf": "Exporteer Als glTF",
"action.export_gltf.desc": "Exporteer model en animaties als glTF bestand om te gebruiken in andere 3D applicaties",
"action.transform_space": "Transformeer Ruimte",
"action.transform_space.desc": "Standaard transformeer ruimte voor elementen en botten",
"action.transform_space.global": "Globaal",
"action.transform_space.bone": "Bot",
"action.transform_space.local": "Locaal",
"action.toggle_camera_projection": "Toggle Camera Projection",
"action.toggle_camera_projection.desc": "Toggle the camera projection between perspective and orthographic",
"action.load_camera_angle": "Camera Angle: %0",
@ -1087,5 +1080,34 @@
"uv_editor.copy_paste_tool.cut": "Cut",
"uv_editor.copy_paste_tool.mirror_x": "Mirror X",
"uv_editor.copy_paste_tool.mirror_y": "Mirror Y",
"uv_editor.copy_paste_tool.rotate": "Rotate 90 Degrees"
"uv_editor.copy_paste_tool.rotate": "Rotate 90 Degrees",
"dialog.project.modded_entity_version": "Export Version",
"dialog.save_angle.position": "Camera Position",
"dialog.save_angle.target": "Focal Point",
"dialog.skin.pose": "Pose",
"layout.color.frame": "Window Frame",
"layout.color.frame.desc": "Border and title bar of the window",
"settings.large_grid_size": "Block Grid Size",
"settings.large_grid_size.desc": "Size of the block grid",
"action.load_plugin_from_url": "Load Plugin from URL",
"action.load_plugin_from_url.desc": "Load a plugin from a server by specifying the URL",
"action.cube_counter.desc": "Displays the current number of cubes and other statistics",
"action.unlock_everything": "Unlock Everything",
"action.unlock_everything.desc": "Unlock all groups and elements in the outliner.",
"action.load_palette": "Load Palette",
"action.load_palette.desc": "Load one of the built-in palette presets",
"action.toggle_locked": "Toggle Lock",
"action.toggle_locked.desc": "Toggle whether the selected elements are locked",
"action.apply_display_preset": "Apply Preset",
"action.apply_display_preset.desc": "Apply a default or custom display setting preset",
"action.apply_display_preset.here": "Apply To This Slot",
"action.apply_display_preset.everywhere": "Apply To All Slots",
"action.resolve_keyframe_expressions": "Resolve Keyframe",
"action.resolve_keyframe_expressions.desc": "Resolves the math expressions of the selected keyframes",
"action.fold_all_animations": "Fold All Animators",
"action.timeline_focus.used": "In Use",
"menu.palette.load.empty": "Blank",
"switches.lock": "Lock",
"camera_angle.isometric_right": "Isometric Right",
"camera_angle.isometric_left": "Isometric Left"
}

View File

@ -280,7 +280,6 @@
"keybind.cancel": "Anuluj",
"action.slider_inflate": "Nadmuchaj",
"action.slider_inflate.desc": "Nadmuchaj kostki we wszystkich kierunkach, bez zmieniania UV.",
"action.brush_mode": "Tryb pędzla",
"action.slider_brush_size": "Wielkość",
"action.slider_brush_size.desc": "Promień pędzla w pikselach",
"action.slider_brush_opacity": "Nieprzezroczystość",
@ -541,8 +540,6 @@
"dialog.update.latest": "Najnowsza wersja",
"dialog.update.installed": "Zainstalowana wersja",
"dialog.update.update": "Aktualizacja",
"action.brush_mode.brush": "Szczotka",
"action.brush_mode.noise": "Mieszanie",
"action.vertex_snap_mode.move": "Przesuń",
"action.vertex_snap_mode.scale": "Skaluj",
"action.open_model_folder": "Otwórz folder modelu",
@ -705,24 +702,24 @@
"action.open_backup_folder.desc": "Otwórz folder kopii zapasowej BlockBench",
"switches.mirror": "Lustro UV",
"language_name": "Polski",
"message.plugin_reload": "Reloaded %0 local plugins",
"settings.brightness": "Brightness",
"settings.brightness.desc": "Brightness of the preview. Default is 50",
"menu.preview.perspective.reset": "Reset Camera",
"action.fill_mode": "Fill Mode",
"action.fill_mode.face": "Face",
"action.fill_mode.color": "Colors",
"action.fill_mode.cube": "Cube",
"action.toggle_mirror_uv": "Mirror UV",
"message.plugin_reload": "Przeładowano %0 lokalnych pluginów",
"settings.brightness": "Jasność",
"settings.brightness.desc": "Jasność podglądu. Domyślnie 50.",
"menu.preview.perspective.reset": "Zresetuj kamerę",
"action.fill_mode": "Tryb wypełniania",
"action.fill_mode.face": "Przód",
"action.fill_mode.color": "Kolory",
"action.fill_mode.cube": "Sześcian",
"action.toggle_mirror_uv": "Odbicie UV",
"action.toggle_mirror_uv.desc": "Toggle the UV mirroring on the X axis of the selected cubes",
"action.toggle_uv_overlay": "Toggle UV Overlay",
"action.toggle_uv_overlay": "Przełącz pokrycie UV",
"action.toggle_uv_overlay.desc": "When enabled, displays all UV mapping overlays above the texture.",
"menu.texture.blank": "Apply to Untextured Faces",
"dialog.scale.select_overflow": "Select Overflow",
"dialog.create_texture.compress": "Compress Template",
"dialog.create_texture.compress": "Skompresuj Szablon",
"action.action_control": "Action Control",
"action.action_control.desc": "Search and execute any available action",
"keybindings.recording": "Recording Keybinding",
"keybindings.recording": "Nagrywanie skrótów klawiszowych",
"keybindings.press": "Press a key or key combination or click anywhere on the screen to record your keybinding.",
"action.pivot_tool": "Pivot Tool",
"action.pivot_tool.desc": "Tool to change the pivot point of cubes and bones",
@ -739,25 +736,25 @@
"action.upload_sketchfab": "Sketchfab Upload",
"message.sketchfab.name_or_token": "Please enter your Sketchfab token and a name",
"dialog.sketchfab_uploader.title": "Upload Sketchfab Model",
"dialog.sketchfab_uploader.token": "API Token",
"dialog.sketchfab_uploader.token": "Token API",
"dialog.sketchfab_uploader.about_token": "The token is used to connect Blockbench to your Sketchfab account. You can find it on %0",
"dialog.sketchfab_uploader.name": "Model Name",
"dialog.sketchfab_uploader.description": "Description",
"dialog.sketchfab_uploader.tags": "Tags",
"dialog.sketchfab_uploader.name": "Nazwa modelu",
"dialog.sketchfab_uploader.description": "Opis",
"dialog.sketchfab_uploader.tags": "Tagi",
"settings.sketchfab_token": "Sketchfab Token",
"settings.sketchfab_token.desc": "Token to authorize Blockbench to upload to your Sketchfab account",
"panel.color": "Color",
"panel.color": "Kolor",
"data.origin": "Pivot",
"message.sketchfab.success": "Uploaded model successfully",
"message.sketchfab.error": "Failed to upload model to Sketchfab",
"message.sketchfab.success": "Model został wysłany",
"message.sketchfab.error": "Wystąpił problem podczas udostępniania modelu na Sketchfab",
"settings.outliner_colors": "Outliner Colors",
"settings.outliner_colors.desc": "Display cube colors in the outliner",
"action.upload_sketchfab.desc": "Upload your model to Sketchfab",
"action.upload_sketchfab.desc": "Udostępnij model na Sketchfab",
"action.element_colors": "Cube Colors",
"action.element_colors.desc": "Show cube colors in the outliner",
"texture.error.file": "File not found",
"texture.error.invalid": "Invalid file",
"texture.error.ratio": "Invalid aspect ratio",
"texture.error.file": "Plik nieznaleziony",
"texture.error.invalid": "Niepoprawny plik",
"texture.error.ratio": "Niepoprawny format",
"texture.error.parent": "Texture file provided by parent model",
"message.recover_backup.title": "Recover Model",
"message.recover_backup.message": "Blockbench was closed without saving. Do you want to recover the model?",
@ -771,23 +768,23 @@
"action.reset_keyframe": "Reset Keyframe",
"action.reset_keyframe.desc": "Reset all values of the selected keyframes",
"dialog.edit_session.title": "Edit Session",
"edit_session.username": "Username",
"edit_session.username": "Nazwa użytkownika",
"edit_session.token": "Token",
"edit_session.about": "Edit Sessions can be used to collaborate on models across the internet. Create a session and copy the token and send it to friends, who can then use it to join.",
"edit_session.join": "Join Session",
"edit_session.create": "Create Session",
"edit_session.quit": "Quit Session",
"edit_session.joined": "%0 joined the session",
"edit_session.left": "%0 left the session",
"edit_session.quit_session": "Left current session",
"edit_session.join": "Dołącz do sesji",
"edit_session.create": "Stwórz sesję",
"edit_session.quit": "Wyjdź z sesji",
"edit_session.joined": "%0 dołączył do sesji",
"edit_session.left": "%0 opuścił sesję",
"edit_session.quit_session": "Opuść aktualną sesję",
"edit_session.status": "Status",
"edit_session.hosting": "Hosting",
"edit_session.connected": "Connected to a session",
"dialog.sketchfab_uploader.private": "Private (Pro)",
"dialog.sketchfab_uploader.password": "Password (Pro)",
"action.toggle_chat": "Toggle Chat",
"action.toggle_chat.desc": "Toggle the visibility of the chat history",
"action.uv_select_all": "Select All",
"edit_session.connected": "Połączono z sesją",
"dialog.sketchfab_uploader.private": "Prywatne (Pro)",
"dialog.sketchfab_uploader.password": "Hasło (Pro)",
"action.toggle_chat": "Przełącz czat",
"action.toggle_chat.desc": "Przełącz widoczność historii czatu",
"action.uv_select_all": "Zaznacz wszystkie",
"action.uv_select_all.desc": "Select all faces in the UV dialog",
"panel.chat": "Chat",
"edit_session.welcome": "Welcome to this session by %0",
@ -805,10 +802,10 @@
"mode.start.recent": "Recent",
"format.free": "Free Model",
"format.free.desc": "Model without restrictions for Unity etc.",
"format.java_block": "Java Block/Item",
"format.java_block.desc": "Block model for Java Edition. Size and rotations are limited.",
"format.java_block": "Java Blok/Przedmiot",
"format.java_block.desc": "Model bloku na Java Edition. Rozmiar i kąty obrotu są ograniczone.",
"format.bedrock": "Bedrock Model",
"format.bedrock.desc": "Model for Bedrock Edition",
"format.bedrock.desc": "Model na Bedrock Edition",
"format.bedrock_old": "Bedrock Legacy Model",
"format.bedrock_old.desc": "Pre-1.12 Bedrock Edition entity model",
"format.modded_entity": "Modded Entity",
@ -829,24 +826,24 @@
"dialog.model_stats.locators": "Locators",
"dialog.model_stats.groups": "Groups",
"dialog.model_stats.vertices": "Vertices",
"dialog.model_stats.faces": "Faces",
"settings.username": "Username",
"dialog.model_stats.faces": "Powierzchnie",
"settings.username": "Nazwa użytkownika",
"settings.username.desc": "Username for edit sessions",
"settings.painting_grid": "Painting Grid",
"settings.painting_grid.desc": "Show grid on textured cubes in paint mode",
"action.slider_brush_min_opacity": "Minimum Opacity",
"action.slider_brush_min_opacity.desc": "Minimum opacity of the noise brush in percent",
"action.convert_project": "Convert Project",
"action.convert_project": "Konwertuj projekt",
"action.convert_project.desc": "Converts the current project to a project for another model format",
"action.close_project": "Close Project",
"action.close_project": "Zamknij projekt",
"action.close_project.desc": "Closes the currently open project",
"action.export_bedrock": "Export Bedrock Geometry",
"action.export_bedrock.desc": "Export the model as a bedrock edition geometry file.",
"action.save_project": "Save Project",
"action.save_project": "Zapisz projekt",
"action.save_project.desc": "Saves the current model as a project file",
"action.save_project_as": "Save Project As",
"action.save_project_as": "Zapisz projekt jako",
"action.save_project_as.desc": "Saves the current model as a project file at a new location",
"action.export_over": "Save Model",
"action.export_over": "Zapisz model",
"action.export_over.desc": "Saves the model, textures and animations by overwriting the files",
"action.add_locator": "Add Locator",
"action.add_locator.desc": "Adds a new locator to control positions of particles, leashes etc",
@ -856,13 +853,13 @@
"action.sidebar_right.desc": "Open the interface to edit elements",
"action.uv_turn_mapping": "Turn Mapping",
"action.uv_turn_mapping.desc": "Turn the UV mapping around 90 degrees",
"action.remove_blank_faces": "Remove Blank Faces",
"action.remove_blank_faces.desc": "Deletes all untextured faces of the selection",
"menu.uv.select": "Select Cubes",
"web.download_app": "Download App",
"action.remove_blank_faces": "Usuń puste powierzchnie",
"action.remove_blank_faces.desc": "Usuwa wszystkie nieoteksturowane powierzchnie z zaznaczenia",
"menu.uv.select": "Wybierz sześcian",
"web.download_app": "Pobierz aplikację",
"uv_editor.turned": "Turned Mapping",
"display.reference.crossbow": "Crossbow",
"dialog.settings.search_results": "Search Results",
"dialog.settings.search_results": "Wyniki wyszukiwania",
"settings.animation_snap": "Animation Snap",
"settings.animation_snap.desc": "Snap interval for keyframes in the animation timeline in steps per second",
"action.import_optifine_part": "Import OptiFine Part",
@ -870,10 +867,10 @@
"data.locator": "Locator",
"mode.start.no_recents": "No recently opened models",
"panel.element": "Element",
"panel.element.position": "Position",
"panel.element.size": "Size",
"panel.element.position": "Pozycja",
"panel.element.size": "Rozmiar",
"panel.element.origin": "Pivot Point",
"panel.element.rotation": "Rotation",
"panel.element.rotation": "Obrót",
"message.canvas_limit_error.title": "Canvas Limit Error",
"message.canvas_limit_error.message": "The action could not be performed correctly because the format limits the canvas to 48 units. Shift the pivot point to prevent this.",
"data.effect": "Effect",
@ -890,19 +887,19 @@
"action.select_effect_animator.desc": "Opens timeline to add sound and particle effects",
"action.timeline_focus": "Channel",
"action.timeline_focus.desc": "Select the animation channels to display in the timeline",
"action.timeline_focus.all": "All",
"timeline.particle": "Particle",
"timeline.sound": "Sound",
"timeline.effects": "Effects",
"action.timeline_focus.all": "Wszystko",
"timeline.particle": "Cząsteczka",
"timeline.sound": "Dźwięk",
"timeline.effects": "Efekty",
"data.format": "Format",
"format.optifine_part": "OptiFine Part",
"format.optifine_part.desc": "JPM part for OptiFine entity models",
"action.reverse_keyframes": "Reverse Keyframes",
"action.reverse_keyframes.desc": "Reverse the order of the selected keyframes",
"generic.help": "Help",
"message.removed_faces": "Removed %0 faces",
"dialog.sketchfab_uploader.draft": "Draft",
"action.slider_pos": "Move %0",
"generic.help": "Pomoc",
"message.removed_faces": "Usunięto %0 powierzchni",
"dialog.sketchfab_uploader.draft": "Szkic",
"action.slider_pos": "Przesuń %0",
"action.slider_pos.desc": "Move cubes on the %0 axis",
"action.slider_size": "Size %0",
"action.slider_size.desc": "Resize cubes on the %0 axis",
@ -918,11 +915,11 @@
"action.flip.desc": "Flip the selected cubes on the %0 axis",
"action.center": "Center %0",
"action.center.desc": "Center the selected cubes on the %0 axis",
"action.bring_up_all_animations": "Bring Up All Animations",
"panel.bone": "Bone",
"data.color": "Color",
"generic.export": "Export",
"generic.none": "None",
"action.bring_up_all_animations": "Bring Up All Animators",
"panel.bone": "Kość",
"data.color": "Kolor",
"generic.export": "Eksportuj",
"generic.none": "Żadne",
"status_bar.recording": "Recording Timelapse",
"message.add_to_palette": "Added to palette",
"message.size_modifiers": "Hold down Ctrl or Shift to transform in smaller increments.",
@ -931,25 +928,23 @@
"message.import_palette.replace_palette": "Replace old palette",
"message.import_palette.threshold": "Merge Threshold",
"dialog.timelapse.interval": "Interval (Seconds)",
"dialog.timelapse.source": "Source",
"dialog.timelapse.source.interface": "Interface",
"dialog.timelapse.source": "Źródło",
"dialog.timelapse.source.interface": "Interfejs",
"dialog.timelapse.source.locked": "Locked Angle",
"dialog.timelapse.destination": "Destination Folder",
"layout.color.checkerboard": "Checkerboard",
"layout.color.checkerboard.desc": "Background of canvas and UV editor",
"layout.font.code": "Code Font",
"layout.css": "Custom CSS",
"settings.category.paint": "Paint",
"settings.category.paint": "Maluj",
"settings.deactivate_size_limit": "Deactivate Size Limit",
"settings.deactivate_size_limit.desc": "Deactivate the size limit for specific model formats. WARNING: This can cause invalid models.",
"settings.brush_opacity_modifier": "Brush Opacity Modifier",
"settings.brush_opacity_modifier.desc": "Modify the brush opacity when using a stylus",
"settings.brush_size_modifier": "Brush Size Modifier",
"settings.brush_size_modifier.desc": "Modify the brush size when using a stylus",
"settings.brush_modifier.pressure": "Pressure",
"settings.brush_modifier.pressure": "Nacisk",
"settings.brush_modifier.tilt": "Tilt",
"settings.class_export_version": "Modded Entity Export Version",
"settings.class_export_version.desc": "The format version for modded entity models",
"category.color": "Kolor",
"action.import_theme": "Importuj styl",
"action.export_theme": "Eksportuj styl",
@ -969,8 +964,6 @@
"action.generate_palette.desc": "Generate palette from a texture",
"action.sort_palette": "Sort Palette",
"action.sort_palette.desc": "Sort all colors on the palette by color and brightness",
"action.clear_palette": "Wyczyść paletę",
"action.clear_palette.desc": "Usuń wszystkie kolory z palety",
"action.timelapse": "Timelapse",
"action.timelapse.desc": "Nagraj timelaps procesu modelowania",
"action.add_keyframe": "Dodaj klatkę kluczową",
@ -1010,26 +1003,26 @@
"menu.help.plugin_documentation": "Plugin API Documentation",
"menu.help.search_action": "Search and Run Action",
"menu.help.donate": "Wesprzyj",
"menu.help.about": "About...",
"menu.help.about": "O Blockbench...",
"menu.preview.background.clipboard": "Wczytaj ze schowka",
"dialog.ignore": "Ignore",
"dialog.ignore": "Ignoruj",
"generic.unset": "Unset",
"message.invalid_builtin_parent.title": "Invalid Built-in Parent",
"message.invalid_builtin_parent.message": "The link to the invalid parent model '%0' was removed in order to export a valid model.",
"dialog.resize_texture.fill": "Fill with",
"dialog.resize_texture.fill.transparent": "Transparent",
"dialog.resize_texture.fill.color": "Color",
"dialog.resize_texture.fill.repeat": "Repeat",
"dialog.resize_texture.fill.stretch": "Stretch",
"dialog.resize_texture.fill.transparent": "Przeźroczysty",
"dialog.resize_texture.fill.color": "Kolor",
"dialog.resize_texture.fill.repeat": "Powtórz",
"dialog.resize_texture.fill.stretch": "Rozciągnij",
"dialog.scale.element_pivot": "Element Pivot",
"dialog.scale.selection_center": "Selection Center",
"dialog.create_gif.length_mode": "Length Mode",
"dialog.create_gif.length_mode.seconds": "Seconds",
"dialog.create_gif.length_mode.frames": "Frames",
"dialog.create_gif.length_mode.animation": "Animation Length",
"dialog.create_gif.length_mode.seconds": "Sekund",
"dialog.create_gif.length_mode.frames": "Klatki",
"dialog.create_gif.length_mode.animation": "Długość animacji",
"dialog.create_gif.length_mode.turntable": "Turntable Rotation",
"dialog.save_angle.projection": "Projection",
"dialog.save_angle.projection.perspective": "Perspective",
"dialog.save_angle.projection.perspective": "Perspektywa",
"dialog.save_angle.projection.orthographic": "Orthographic",
"dialog.sketchfab_uploader.animations": "Animations",
"dialog.settings.theme": "Theme",
@ -1045,7 +1038,7 @@
"action.draw_shape_type.rectangle_h": "Rectangle (Hollow)",
"action.draw_shape_type.ellipse": "Ellipse",
"action.draw_shape_type.ellipse_h": "Ellipse (Hollow)",
"action.draw_shape_type.line": "Line",
"action.draw_shape_type.line": "Linia",
"action.mirror_painting": "Mirror Painting",
"action.mirror_painting.description": "Mirror your paint strokes to the other side of the model",
"action.lock_alpha": "Lock Alpha Channel",
@ -1058,8 +1051,8 @@
"action.export_gltf.desc": "Export model and animations as glTF file to use in other 3D applications",
"action.transform_space": "Transform Space",
"action.transform_space.desc": "Default transform space for elements and bones",
"action.transform_space.global": "Global",
"action.transform_space.bone": "Bone",
"action.transform_space.global": "Globalne",
"action.transform_space.bone": "Kość",
"action.transform_space.local": "Local",
"action.toggle_camera_projection": "Toggle Camera Projection",
"action.toggle_camera_projection.desc": "Toggle the camera projection between perspective and orthographic",
@ -1068,24 +1061,53 @@
"action.slider_face_tint": "Tint Index",
"action.slider_face_tint.desc": "Set the tint index of the current face. -1 means unset.",
"menu.help.quickstart": "Quickstart Wizard",
"menu.help.developer": "Developer",
"menu.help.developer": "Deweloper",
"menu.help.developer.dev_tools": "Open Dev Tools",
"menu.help.developer.reset_storage": "Factory Reset",
"menu.help.developer.reset_storage.confirm": "Are you sure you want to reset Blockbench to factory settings? This will delete all custom settings, keybindings and installed plugins.",
"menu.help.developer.cache_reload": "Cache Reload",
"menu.texture.resize": "Resize...",
"menu.texture.resize": "Zmień rozmiar...",
"menu.preview.orthographic": "Orthographic",
"menu.preview.save_angle": "Save Angle...",
"menu.preview.angle": "Angles",
"menu.preview.angle.initial": "Initial Angle",
"menu.preview.angle.load": "Load",
"menu.preview.maximize": "Maximize",
"panel.color.both": "Both",
"uv_editor.copy_selection": "Copy Selection",
"uv_editor.paste_selection": "Paste Selection",
"menu.preview.angle.load": "Wczytaj",
"menu.preview.maximize": "Maksymalizuj",
"panel.color.both": "Oba",
"uv_editor.copy_selection": "Kopiuj zaznaczenie",
"uv_editor.paste_selection": "Wklej zaznaczenie",
"uv_editor.copy_paste_tool.place": "Place",
"uv_editor.copy_paste_tool.cut": "Cut",
"uv_editor.copy_paste_tool.mirror_x": "Mirror X",
"uv_editor.copy_paste_tool.mirror_y": "Mirror Y",
"uv_editor.copy_paste_tool.rotate": "Rotate 90 Degrees"
"uv_editor.copy_paste_tool.rotate": "Rotate 90 Degrees",
"dialog.project.modded_entity_version": "Export Version",
"dialog.save_angle.position": "Camera Position",
"dialog.save_angle.target": "Focal Point",
"dialog.skin.pose": "Pose",
"layout.color.frame": "Window Frame",
"layout.color.frame.desc": "Border and title bar of the window",
"settings.large_grid_size": "Block Grid Size",
"settings.large_grid_size.desc": "Size of the block grid",
"action.load_plugin_from_url": "Load Plugin from URL",
"action.load_plugin_from_url.desc": "Load a plugin from a server by specifying the URL",
"action.cube_counter.desc": "Displays the current number of cubes and other statistics",
"action.unlock_everything": "Unlock Everything",
"action.unlock_everything.desc": "Unlock all groups and elements in the outliner.",
"action.load_palette": "Load Palette",
"action.load_palette.desc": "Load one of the built-in palette presets",
"action.toggle_locked": "Toggle Lock",
"action.toggle_locked.desc": "Toggle whether the selected elements are locked",
"action.apply_display_preset": "Apply Preset",
"action.apply_display_preset.desc": "Apply a default or custom display setting preset",
"action.apply_display_preset.here": "Apply To This Slot",
"action.apply_display_preset.everywhere": "Apply To All Slots",
"action.resolve_keyframe_expressions": "Resolve Keyframe",
"action.resolve_keyframe_expressions.desc": "Resolves the math expressions of the selected keyframes",
"action.fold_all_animations": "Fold All Animators",
"action.timeline_focus.used": "In Use",
"menu.palette.load.empty": "Blank",
"switches.lock": "Lock",
"camera_angle.isometric_right": "Isometric Right",
"camera_angle.isometric_left": "Isometric Left"
}

View File

@ -280,7 +280,6 @@
"keybind.cancel": "Cancelar",
"action.slider_inflate": "Aumentar",
"action.slider_inflate.desc": "Aumentar cubos em todas as direções sem alterar o mapeamento.",
"action.brush_mode": "Modo do pincel",
"action.slider_brush_size": "Tamanho",
"action.slider_brush_size.desc": "Tamanho do pincel (em pixels)",
"action.slider_brush_opacity": "Opacidade",
@ -541,8 +540,6 @@
"dialog.update.latest": "Última Versão",
"dialog.update.installed": "Versão Instalada",
"dialog.update.update": "Atualização",
"action.brush_mode.brush": "Redondo",
"action.brush_mode.noise": "Ruído",
"action.vertex_snap_mode.move": "Mover",
"action.vertex_snap_mode.scale": "Redimensionar",
"action.open_model_folder": "Abrir Pasta de Modelos",
@ -948,8 +945,6 @@
"settings.brush_size_modifier.desc": "Modifique o tamanho do pincel ao usar uma caneta",
"settings.brush_modifier.pressure": "Pressão",
"settings.brush_modifier.tilt": "Inclinar",
"settings.class_export_version": "Versão de exportação de entidade modificada",
"settings.class_export_version.desc": "A versão do formato para modelos de entidade modificados.",
"category.color": "Cor",
"action.import_theme": "Importar Tema",
"action.export_theme": "Exportar Tema",
@ -969,8 +964,6 @@
"action.generate_palette.desc": "Gerar paleta a partir de uma textura",
"action.sort_palette": "Classificar Paleta",
"action.sort_palette.desc": "Classifique todas as cores da paleta por cor e brilho",
"action.clear_palette": "Limpar Paleta",
"action.clear_palette.desc": "Remove todas as cores da paleta",
"action.timelapse": "Timelapse...",
"action.timelapse.desc": "Grave um timelapse do seu progresso de modelagem",
"action.add_keyframe": "Adicionar quadro-chave",
@ -994,7 +987,7 @@
"format.skin.desc": "Edit player and entity skins",
"message.sketchfab.setup_guide": "Want to learn how to set up models in Sketchfab? Read %0",
"dialog.skin.title": "Create Skin",
"dialog.skin.model": "Skin",
"dialog.skin.model": "Model",
"dialog.skin.texture": "Texture (Optional)",
"action.toggle_skin_layer": "Toggle Skin Layer",
"action.toggle_skin_layer.desc": "Toggle the hat and clothing layer of the skin model",
@ -1087,5 +1080,34 @@
"uv_editor.copy_paste_tool.cut": "Cut",
"uv_editor.copy_paste_tool.mirror_x": "Mirror X",
"uv_editor.copy_paste_tool.mirror_y": "Mirror Y",
"uv_editor.copy_paste_tool.rotate": "Rotate 90 Degrees"
"uv_editor.copy_paste_tool.rotate": "Rotate 90 Degrees",
"dialog.project.modded_entity_version": "Export Version",
"dialog.save_angle.position": "Camera Position",
"dialog.save_angle.target": "Focal Point",
"dialog.skin.pose": "Pose",
"layout.color.frame": "Window Frame",
"layout.color.frame.desc": "Border and title bar of the window",
"settings.large_grid_size": "Block Grid Size",
"settings.large_grid_size.desc": "Size of the block grid",
"action.load_plugin_from_url": "Load Plugin from URL",
"action.load_plugin_from_url.desc": "Load a plugin from a server by specifying the URL",
"action.cube_counter.desc": "Displays the current number of cubes and other statistics",
"action.unlock_everything": "Unlock Everything",
"action.unlock_everything.desc": "Unlock all groups and elements in the outliner.",
"action.load_palette": "Load Palette",
"action.load_palette.desc": "Load one of the built-in palette presets",
"action.toggle_locked": "Toggle Lock",
"action.toggle_locked.desc": "Toggle whether the selected elements are locked",
"action.apply_display_preset": "Apply Preset",
"action.apply_display_preset.desc": "Apply a default or custom display setting preset",
"action.apply_display_preset.here": "Apply To This Slot",
"action.apply_display_preset.everywhere": "Apply To All Slots",
"action.resolve_keyframe_expressions": "Resolve Keyframe",
"action.resolve_keyframe_expressions.desc": "Resolves the math expressions of the selected keyframes",
"action.fold_all_animations": "Fold All Animators",
"action.timeline_focus.used": "In Use",
"menu.palette.load.empty": "Blank",
"switches.lock": "Lock",
"camera_angle.isometric_right": "Isometric Right",
"camera_angle.isometric_left": "Isometric Left"
}

View File

@ -280,7 +280,6 @@
"keybind.cancel": "Отменить",
"action.slider_inflate": "Раздуть",
"action.slider_inflate.desc": "Раздуть кубы во все направления без изменений в UV",
"action.brush_mode": "Режим кисти",
"action.slider_brush_size": "Размер",
"action.slider_brush_size.desc": "Размер кисти в пикселях",
"action.slider_brush_opacity": "Непрозрачность",
@ -541,8 +540,6 @@
"dialog.update.latest": "Новейшая версия",
"dialog.update.installed": "Установленная версия",
"dialog.update.update": "Обновление",
"action.brush_mode.brush": "Кисть",
"action.brush_mode.noise": "Шум",
"action.vertex_snap_mode.move": "Перемещение",
"action.vertex_snap_mode.scale": "Масштабирование",
"action.open_model_folder": "Открыть расположение модели",
@ -948,8 +945,6 @@
"settings.brush_size_modifier.desc": "Модифицировать размер кисти при использовании стилуса",
"settings.brush_modifier.pressure": "Давление",
"settings.brush_modifier.tilt": "Наклон",
"settings.class_export_version": "Модифицированная версия экспорта сущностей",
"settings.class_export_version.desc": "Версия формата для модифицированных моделей сущностей",
"category.color": "Цвет",
"action.import_theme": "Импорт темы",
"action.export_theme": "Экспорт темы",
@ -969,8 +964,6 @@
"action.generate_palette.desc": "Сгенерировать палитру из текстуры",
"action.sort_palette": "Сортировка палитры",
"action.sort_palette.desc": "Сортировать цвета на палитре по цвету и яркости",
"action.clear_palette": "Очистка палитры",
"action.clear_palette.desc": "Удалить все цвета из палитры",
"action.timelapse": "Временная шкала",
"action.timelapse.desc": "Записать процесс создания модели",
"action.add_keyframe": "Добавить ключевой кадр",
@ -1087,5 +1080,34 @@
"uv_editor.copy_paste_tool.cut": "Cut",
"uv_editor.copy_paste_tool.mirror_x": "Mirror X",
"uv_editor.copy_paste_tool.mirror_y": "Mirror Y",
"uv_editor.copy_paste_tool.rotate": "Rotate 90 Degrees"
"uv_editor.copy_paste_tool.rotate": "Rotate 90 Degrees",
"dialog.project.modded_entity_version": "Export Version",
"dialog.save_angle.position": "Camera Position",
"dialog.save_angle.target": "Focal Point",
"dialog.skin.pose": "Pose",
"layout.color.frame": "Window Frame",
"layout.color.frame.desc": "Border and title bar of the window",
"settings.large_grid_size": "Block Grid Size",
"settings.large_grid_size.desc": "Size of the block grid",
"action.load_plugin_from_url": "Load Plugin from URL",
"action.load_plugin_from_url.desc": "Load a plugin from a server by specifying the URL",
"action.cube_counter.desc": "Displays the current number of cubes and other statistics",
"action.unlock_everything": "Unlock Everything",
"action.unlock_everything.desc": "Unlock all groups and elements in the outliner.",
"action.load_palette": "Load Palette",
"action.load_palette.desc": "Load one of the built-in palette presets",
"action.toggle_locked": "Toggle Lock",
"action.toggle_locked.desc": "Toggle whether the selected elements are locked",
"action.apply_display_preset": "Apply Preset",
"action.apply_display_preset.desc": "Apply a default or custom display setting preset",
"action.apply_display_preset.here": "Apply To This Slot",
"action.apply_display_preset.everywhere": "Apply To All Slots",
"action.resolve_keyframe_expressions": "Resolve Keyframe",
"action.resolve_keyframe_expressions.desc": "Resolves the math expressions of the selected keyframes",
"action.fold_all_animations": "Fold All Animators",
"action.timeline_focus.used": "In Use",
"menu.palette.load.empty": "Blank",
"switches.lock": "Lock",
"camera_angle.isometric_right": "Isometric Right",
"camera_angle.isometric_left": "Isometric Left"
}

View File

@ -280,7 +280,6 @@
"keybind.cancel": "Avbryt",
"action.slider_inflate": "Blåsa upp",
"action.slider_inflate.desc": "Blås upp kuber i alla riktningar utan att ändra UV.",
"action.brush_mode": "Penselläge",
"action.slider_brush_size": "Storlek",
"action.slider_brush_size.desc": "Penselns radie i pixlar",
"action.slider_brush_opacity": "Opacitet",
@ -541,8 +540,6 @@
"dialog.update.latest": "Senaste version",
"dialog.update.installed": "Installerad version",
"dialog.update.update": "Uppdatera",
"action.brush_mode.brush": "Rund",
"action.brush_mode.noise": "Brus",
"action.vertex_snap_mode.move": "Flytta",
"action.vertex_snap_mode.scale": "Skala",
"action.open_model_folder": "Öppna modellmapp",
@ -918,7 +915,7 @@
"action.flip.desc": "Flip the selected cubes on the %0 axis",
"action.center": "Center %0",
"action.center.desc": "Center the selected cubes on the %0 axis",
"action.bring_up_all_animations": "Bring Up All Animations",
"action.bring_up_all_animations": "Bring Up All Animators",
"panel.bone": "Ben",
"data.color": "Färg",
"generic.export": "Export",
@ -948,8 +945,6 @@
"settings.brush_size_modifier.desc": "Modify the brush size when using a stylus",
"settings.brush_modifier.pressure": "Tryck",
"settings.brush_modifier.tilt": "Tilt",
"settings.class_export_version": "Modded Entity Export Version",
"settings.class_export_version.desc": "The format version for modded entity models",
"category.color": "Färg",
"action.import_theme": "Import Theme",
"action.export_theme": "Export Theme",
@ -969,8 +964,6 @@
"action.generate_palette.desc": "Generate palette from a texture",
"action.sort_palette": "Sort Palette",
"action.sort_palette.desc": "Sort all colors on the palette by color and brightness",
"action.clear_palette": "Clear Palette",
"action.clear_palette.desc": "Remove all colors from the palette",
"action.timelapse": "Timelapse...",
"action.timelapse.desc": "Record a timelapse of your modeling process",
"action.add_keyframe": "Add Keyframe",
@ -994,7 +987,7 @@
"format.skin.desc": "Edit player and entity skins",
"message.sketchfab.setup_guide": "Want to learn how to set up models in Sketchfab? Read %0",
"dialog.skin.title": "Create Skin",
"dialog.skin.model": "Skin",
"dialog.skin.model": "Model",
"dialog.skin.texture": "Texture (Optional)",
"action.toggle_skin_layer": "Toggle Skin Layer",
"action.toggle_skin_layer.desc": "Toggle the hat and clothing layer of the skin model",
@ -1087,5 +1080,34 @@
"uv_editor.copy_paste_tool.cut": "Cut",
"uv_editor.copy_paste_tool.mirror_x": "Mirror X",
"uv_editor.copy_paste_tool.mirror_y": "Mirror Y",
"uv_editor.copy_paste_tool.rotate": "Rotate 90 Degrees"
"uv_editor.copy_paste_tool.rotate": "Rotate 90 Degrees",
"dialog.project.modded_entity_version": "Export Version",
"dialog.save_angle.position": "Camera Position",
"dialog.save_angle.target": "Focal Point",
"dialog.skin.pose": "Pose",
"layout.color.frame": "Window Frame",
"layout.color.frame.desc": "Border and title bar of the window",
"settings.large_grid_size": "Block Grid Size",
"settings.large_grid_size.desc": "Size of the block grid",
"action.load_plugin_from_url": "Load Plugin from URL",
"action.load_plugin_from_url.desc": "Load a plugin from a server by specifying the URL",
"action.cube_counter.desc": "Displays the current number of cubes and other statistics",
"action.unlock_everything": "Unlock Everything",
"action.unlock_everything.desc": "Unlock all groups and elements in the outliner.",
"action.load_palette": "Load Palette",
"action.load_palette.desc": "Load one of the built-in palette presets",
"action.toggle_locked": "Toggle Lock",
"action.toggle_locked.desc": "Toggle whether the selected elements are locked",
"action.apply_display_preset": "Apply Preset",
"action.apply_display_preset.desc": "Apply a default or custom display setting preset",
"action.apply_display_preset.here": "Apply To This Slot",
"action.apply_display_preset.everywhere": "Apply To All Slots",
"action.resolve_keyframe_expressions": "Resolve Keyframe",
"action.resolve_keyframe_expressions.desc": "Resolves the math expressions of the selected keyframes",
"action.fold_all_animations": "Fold All Animators",
"action.timeline_focus.used": "In Use",
"menu.palette.load.empty": "Blank",
"switches.lock": "Lock",
"camera_angle.isometric_right": "Isometric Right",
"camera_angle.isometric_left": "Isometric Left"
}

View File

@ -1,7 +1,7 @@
{
"dialog.ok": "好的",
"dialog.cancel": "取消",
"dialog.confirm": "确认",
"dialog.confirm": "Confirm",
"dialog.close": "关闭",
"dialog.import": "导入",
"dialog.save": "保存",
@ -280,7 +280,6 @@
"keybind.cancel": "取消",
"action.slider_inflate": "缩放",
"action.slider_inflate.desc": "在不改变 UV 的情况下放大所有立方体",
"action.brush_mode": "笔刷模式",
"action.slider_brush_size": "尺寸",
"action.slider_brush_size.desc": "笔刷的半径(以像素为单位)",
"action.slider_brush_opacity": "不透明度",
@ -541,8 +540,6 @@
"dialog.update.latest": "最新版本",
"dialog.update.installed": "已安装的版本",
"dialog.update.update": "更新",
"action.brush_mode.brush": "笔刷",
"action.brush_mode.noise": "噪点",
"action.vertex_snap_mode.move": "移动",
"action.vertex_snap_mode.scale": "缩放",
"action.open_model_folder": "打开模型文件夹",
@ -948,8 +945,6 @@
"settings.brush_size_modifier.desc": "使用手写笔时修改画笔的大小",
"settings.brush_modifier.pressure": "压感",
"settings.brush_modifier.tilt": "倾斜",
"settings.class_export_version": "模组实体导出版本",
"settings.class_export_version.desc": "模组实体格式对应的版本",
"category.color": "颜色",
"action.import_theme": "导入主题",
"action.export_theme": "导出主题",
@ -969,8 +964,6 @@
"action.generate_palette.desc": "从材质纹理贴图生成调色板",
"action.sort_palette": "排列调色板",
"action.sort_palette.desc": "按颜色和亮度对调色板上所有的颜色进行排序",
"action.clear_palette": "清除调色板",
"action.clear_palette.desc": "从调色板中删除所有颜色",
"action.timelapse": "延时摄影……",
"action.timelapse.desc": "拍摄你建模过程的延时摄影",
"action.add_keyframe": "添加关键帧",
@ -1087,5 +1080,34 @@
"uv_editor.copy_paste_tool.cut": "剪切",
"uv_editor.copy_paste_tool.mirror_x": "镜像 X 轴",
"uv_editor.copy_paste_tool.mirror_y": "镜像 Y 轴",
"uv_editor.copy_paste_tool.rotate": "旋转90度"
"uv_editor.copy_paste_tool.rotate": "旋转90度",
"dialog.project.modded_entity_version": "Export Version",
"dialog.save_angle.position": "Camera Position",
"dialog.save_angle.target": "Focal Point",
"dialog.skin.pose": "Pose",
"layout.color.frame": "Window Frame",
"layout.color.frame.desc": "Border and title bar of the window",
"settings.large_grid_size": "Block Grid Size",
"settings.large_grid_size.desc": "Size of the block grid",
"action.load_plugin_from_url": "Load Plugin from URL",
"action.load_plugin_from_url.desc": "Load a plugin from a server by specifying the URL",
"action.cube_counter.desc": "Displays the current number of cubes and other statistics",
"action.unlock_everything": "Unlock Everything",
"action.unlock_everything.desc": "Unlock all groups and elements in the outliner.",
"action.load_palette": "Load Palette",
"action.load_palette.desc": "Load one of the built-in palette presets",
"action.toggle_locked": "Toggle Lock",
"action.toggle_locked.desc": "Toggle whether the selected elements are locked",
"action.apply_display_preset": "Apply Preset",
"action.apply_display_preset.desc": "Apply a default or custom display setting preset",
"action.apply_display_preset.here": "Apply To This Slot",
"action.apply_display_preset.everywhere": "Apply To All Slots",
"action.resolve_keyframe_expressions": "Resolve Keyframe",
"action.resolve_keyframe_expressions.desc": "Resolves the math expressions of the selected keyframes",
"action.fold_all_animations": "Fold All Animators",
"action.timeline_focus.used": "In Use",
"menu.palette.load.empty": "Blank",
"switches.lock": "Lock",
"camera_angle.isometric_right": "Isometric Right",
"camera_angle.isometric_left": "Isometric Left"
}

View File

@ -1,7 +1,7 @@
{
"name": "Blockbench",
"description": "Model editing and animation software",
"version": "3.4.2",
"version": "3.5.0",
"license": "MIT",
"author": {
"name": "JannisX11",
@ -73,6 +73,7 @@
}
},
"scripts": {
"dev": "electron .",
"dist": "electron-builder --publish=always",
"win64": "electron-builder -w --ia32 --publish=always",
"win32": "electron-builder -w --x64 --publish=always",
@ -80,7 +81,7 @@
},
"devDependencies": {
"async": "^2.4.1",
"electron": "8.0.2",
"electron": "8.2.1",
"electron-builder": "^21.2.0"
}
}

51
service_worker.js Normal file
View File

@ -0,0 +1,51 @@
const cacheName = 'blockbench_3.2.0';
const staticAssets = [
'./',
'./index.html',
'./css/',
'./js',
'./lib',
'./font',
'./lang',
'./assets',
'./favicon.png',
'./manifest.json',
];
self.addEventListener('install', async (event) => {
var cache = await caches.open(cacheName);
await cache.addAll(staticAssets);
return self.skipWaiting();
})
self.addEventListener('activate', (event) => {
self.clients.claim();
})
self.addEventListener('fetch', async (event) => {
var req = event.request;
var url = new URL(req.url);
if (url.origin == 'location.origin') {
event.respondWith(cacheFirst(req));
} else {
event.respondWith(networkAndCache(req));
}
})
async function cacheFirst(req) {
var cache = await caches.open(cacheName);
var cached = await cache.match(req);
return cached || fetch(req);
}
async function networkAndCache(req) {
var cache = await caches.open(cacheName);
try {
var fresh = await fetch(req);
await cache.put(req, fresh.clone());
return fresh;
} catch (err) {
var cached = await cache.match(req);
return cached;
}
}