mirror of
https://github.com/JannisX11/blockbench.git
synced 2024-11-21 01:13:37 +08:00
Rewrite bedrock model import select dialog
This commit is contained in:
parent
ac89a9c269
commit
888bfa3fa4
@ -959,36 +959,34 @@
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
/*PE Import Dialog*/
|
||||
#pe_list {
|
||||
max-height: 600px;
|
||||
margin-bottom: 20px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
#pe_list li {
|
||||
/*PE Import Dialog*/
|
||||
dialog#bedrock_model_select .search_bar {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
#model_select_list li {
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
padding: 2px 0;
|
||||
}
|
||||
#pe_list li > * {
|
||||
#model_select_list li.selected {
|
||||
background-color: var(--color-selected);
|
||||
color: var(--color-light);
|
||||
}
|
||||
#model_select_list li:hover {
|
||||
color: var(--color-light);
|
||||
}
|
||||
#model_select_list li > * {
|
||||
margin: 0;
|
||||
margin-left: 12px;
|
||||
cursor: default;
|
||||
overflow-x: hidden;
|
||||
cursor: inherit;
|
||||
}
|
||||
#pe_list li.selected {
|
||||
background-color: var(--color-selected);
|
||||
#model_select_list > li > label {
|
||||
color: var(--color-subtle_text);
|
||||
}
|
||||
#pe_list li > .pe_icon {
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
float: left;
|
||||
margin: 4px;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 0;
|
||||
#model_select_list > li.selected > label {
|
||||
color: var(--color-text);
|
||||
}
|
||||
#pe_list li > h4 > span {
|
||||
font-size: 0.7;
|
||||
}
|
||||
/* Screenshot */
|
||||
/* Screenshot */
|
||||
dialog#screenshot content {
|
||||
color: var(--color-subtle_text);
|
||||
}
|
||||
|
27
index.html
27
index.html
@ -173,33 +173,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<dialog class="dialog draggable" id="entity_import">
|
||||
<div class="dialog_handle">
|
||||
<div class="dialog_title tl">dialog.entitylist.title</div>
|
||||
</div>
|
||||
<div class="dialog_content">
|
||||
<div class="dialog_bar narrow tl">dialog.entitylist.text</div>
|
||||
<div class="search_bar">
|
||||
<input type="text" class="dark_bordered" id="pe_search_bar" oninput="pe_list._data.search_term = $(this).val().toUpperCase()">
|
||||
<i class="material-icons" id="plugin_search_bar_icon">search</i>
|
||||
</div>
|
||||
<ul id="pe_list" class="list">
|
||||
<li v-for="item in searched" v-bind:class="{ selected: item.selected }" v-on:click="selectE(item, $event)" v-on:dblclick="open(item)">
|
||||
<img class="pe_icon" v-if="item.icon" v-bind:src="item.icon">
|
||||
<div class="pe_icon" v-else></div>
|
||||
<h4>{{ item.title }} <span>({{ item.name }})</span></h4>
|
||||
<p>{{ item.bonecount+' '+tl('dialog.entitylist.bones') }}, {{ item.cubecount+' '+tl('dialog.entitylist.cubes') }}</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="dialog_bar button_bar">
|
||||
<button type="button" class="tl confirm_btn" onclick="">dialog.import</button>
|
||||
<button type="button" class="cancel_btn tl" onclick="hideDialog();BarItems.close_project.click()">dialog.cancel</button>
|
||||
</div>
|
||||
<div class="dialog_close_button" onclick="hideDialog();BarItems.close_project.click()"><i class="material-icons">clear</i></div>
|
||||
</dialog>
|
||||
|
||||
<dialog class="dialog draggable" id="image_extruder">
|
||||
<div class="dialog_handle">
|
||||
<div class="dialog_title tl">dialog.extrude.title</div>
|
||||
|
@ -154,7 +154,7 @@ window.BedrockEntityManager = class BedrockEntityManager {
|
||||
if (!this.search_term) return this.valid_textures_list;
|
||||
let term = this.search_term.toLowerCase();
|
||||
return this.valid_textures_list.filter(path => {
|
||||
return path.toLowerCase().includes(this.search_term);
|
||||
return path.toLowerCase().includes(term);
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -1065,154 +1065,78 @@ var codec = new Codec('bedrock', {
|
||||
Blockbench.writeFile(path, {content}, cb);
|
||||
},
|
||||
parse(data, path) {
|
||||
pe_list_data.length = 0
|
||||
if (Format != Formats.bedrock && Format != Formats.bedrock_block) Formats.bedrock.select()
|
||||
|
||||
var geometries = []
|
||||
for (var geo of data['minecraft:geometry']) {
|
||||
geometries.push(geo);
|
||||
let geometries = [];
|
||||
for (let geo of data['minecraft:geometry']) {
|
||||
if (typeof geo !== 'object') continue;
|
||||
geometries.push({object: geo});
|
||||
}
|
||||
if (geometries.length === 1) {
|
||||
parseGeometry({object: data['minecraft:geometry'][0]})
|
||||
return;
|
||||
return parseGeometry(geometries[0]);
|
||||
}
|
||||
|
||||
$('#pe_search_bar').val('')
|
||||
if (pe_list && pe_list._data) {
|
||||
pe_list._data.search_text = ''
|
||||
}
|
||||
geometries.forEach(geo => {
|
||||
geo.uuid = guid();
|
||||
geo.id = geo.object.description?.identifier || '';
|
||||
geo.name = geo.id;
|
||||
|
||||
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) {
|
||||
model_entry.object.bones.forEach(function(b) {
|
||||
var rotation = b.rotation
|
||||
if (!rotation || rotation[0] === undefined) {
|
||||
if (entityMode.hardcodes[model_entry.name] && entityMode.hardcodes[model_entry.name][b.name]) {
|
||||
rotation = entityMode.hardcodes[model_entry.name][b.name].rotation
|
||||
}
|
||||
}
|
||||
if (b.cubes) {
|
||||
b.cubes.forEach(function(c) {
|
||||
if (c.origin && c.size) {
|
||||
//Do cube
|
||||
var inflate = c.inflate||0
|
||||
var coords = {
|
||||
x: (c.origin[2]-inflate)*isize+24,
|
||||
y: 40-(c.origin[1]+c.size[1]+inflate)*isize,
|
||||
w: (c.size[2]+2*inflate)*isize,
|
||||
h: (c.size[1]+2*inflate)*isize
|
||||
}
|
||||
var shade = (limitNumber(c.origin[0], -24, 24)+24)/48*255
|
||||
var color = parseInt('0xffffff'+shade.toString(16))
|
||||
coords.x = limitNumber(coords.x, 0, 47)
|
||||
coords.y = limitNumber(coords.y, 0, 47)
|
||||
coords.w = limitNumber(coords.w, 0, 47 - coords.x)
|
||||
coords.h = limitNumber(coords.h, 0, 47 - coords.y)
|
||||
if (coords.h > 0 && coords.w > 0) {
|
||||
if (rotation && rotation[0] !== 0 && b.pivot) {
|
||||
Painter.drawRotatedRectangle(
|
||||
image,
|
||||
0xffffff88,
|
||||
coords,
|
||||
b.pivot[2]*isize+24,
|
||||
40-b.pivot[1]*isize,
|
||||
-rotation[0]
|
||||
)
|
||||
} else {
|
||||
Painter.drawRectangle(image, 0xffffff88, coords)
|
||||
}
|
||||
}
|
||||
}
|
||||
geo.bonecount = 0;
|
||||
geo.cubecount = 0;
|
||||
if (geo.object.bones instanceof Array) {
|
||||
geo.object.bones.forEach(bone => {
|
||||
geo.bonecount++;
|
||||
if (bone.cubes instanceof Array) geo.cubecount += bone.cubes.length;
|
||||
})
|
||||
}
|
||||
})
|
||||
console.log(geometries)
|
||||
|
||||
let selected = null;
|
||||
new Dialog({
|
||||
id: 'bedrock_model_select',
|
||||
title: 'dialog.select_model.title',
|
||||
buttons: ['Import', 'dialog.cancel'],
|
||||
component: {
|
||||
data() {return {
|
||||
search_term: '',
|
||||
geometries,
|
||||
selected: null,
|
||||
}},
|
||||
computed: {
|
||||
filtered_geometries() {
|
||||
if (!this.search_term) return this.geometries;
|
||||
let term = this.search_term.toLowerCase();
|
||||
return this.geometries.filter(geo => {
|
||||
return geo.name.toLowerCase().includes(term)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
//Send
|
||||
image.getBase64("image/png", function(a, dataUrl){
|
||||
model_entry.icon = dataUrl
|
||||
})
|
||||
})
|
||||
}
|
||||
for (var geo of data['minecraft:geometry']) {
|
||||
var key = geo.description && geo.description.identifier;
|
||||
if (key && key.includes('geometry.')) {
|
||||
var base_model = {
|
||||
name: key,
|
||||
bonecount: 0,
|
||||
cubecount: 0,
|
||||
selected: false,
|
||||
object: geo,
|
||||
icon: false
|
||||
}
|
||||
var oversize = 2;
|
||||
var words = key.replace(/:.*/g, '').replace('geometry.', '').split(/[\._]/g)
|
||||
words.forEach(function(w, wi) {
|
||||
words[wi] = capitalizeFirstLetter(w)
|
||||
})
|
||||
base_model.title = words.join(' ')
|
||||
if (geo.bones) {
|
||||
base_model.bonecount = geo.bones.length
|
||||
geo.bones.forEach(function(b) {
|
||||
if (b.cubes) {
|
||||
base_model.cubecount += b.cubes.length
|
||||
b.cubes.forEach(function(c) {
|
||||
if (c.origin && c.size && (c.origin[2] < -12 || c.origin[2] + c.size[2] > 12 || c.origin[1] + c.size[1] > 22) && oversize === 2) oversize = 1
|
||||
if (c.origin && c.size && (c.origin[2] < -24 || c.origin[2] + c.size[2] > 24)) oversize = 0.5
|
||||
})
|
||||
}
|
||||
})
|
||||
if (typeof base_model.cubecount !== 'number') {
|
||||
base_model.cubecount = '[E]'
|
||||
} else if (base_model.cubecount > 0) {
|
||||
|
||||
create_thumbnail(base_model, oversize)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
pe_list_data.push(base_model)
|
||||
}
|
||||
}
|
||||
if (pe_list == undefined) {
|
||||
pe_list = new Vue({
|
||||
el: '#pe_list',
|
||||
data: {
|
||||
search_text: '',
|
||||
list: pe_list_data
|
||||
},
|
||||
methods: {
|
||||
selectE(item, event) {
|
||||
var index = pe_list_data.indexOf(item)
|
||||
pe_list_data.forEach(function(s) {
|
||||
s.selected = false;
|
||||
})
|
||||
pe_list_data[index].selected = true
|
||||
selectGeometry(geo) {
|
||||
this.selected = selected = geo;
|
||||
},
|
||||
open() {
|
||||
parseGeometry()
|
||||
open(geo) {
|
||||
parseGeometry(geo);
|
||||
},
|
||||
tl
|
||||
},
|
||||
computed: {
|
||||
searched() {
|
||||
return this.list.filter(item => {
|
||||
return item.name.toUpperCase().includes(this.search_text)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
showDialog('entity_import')
|
||||
$('#pe_list').css('max-height', (window.innerHeight - 320) +'px')
|
||||
$('input#pe_search_bar').select()
|
||||
$('#entity_import .confirm_btn').off('click')
|
||||
$('#entity_import .confirm_btn').on('click', (e) => {
|
||||
parseGeometry()
|
||||
})
|
||||
template: `
|
||||
<div>
|
||||
<search-bar v-model="search_term"></search-bar>
|
||||
<ul class="list" id="model_select_list">
|
||||
<li v-for="geometry in filtered_geometries" :key="geometry.uuid" :class="{selected: geometry == selected}" @click="selectGeometry(geometry)" @dblclick="open(geometry)">
|
||||
<p>{{ geometry.name }}</p>
|
||||
<label>{{ geometry.bonecount+' ${tl('dialog.select_model.bones')}' }}, {{ geometry.cubecount+' ${tl('dialog.select_model.cubes')}' }}</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`
|
||||
},
|
||||
onConfirm() {
|
||||
parseGeometry(selected);
|
||||
}
|
||||
}).show();
|
||||
},
|
||||
fileName() {
|
||||
var name = Project.name||'model';
|
||||
|
@ -265,147 +265,77 @@ var codec = new Codec('bedrock_old', {
|
||||
}
|
||||
},
|
||||
parse(data, path) {
|
||||
pe_list_data.length = 0
|
||||
|
||||
var geometries = []
|
||||
for (var key in data) {
|
||||
if (typeof data[key] === 'object') {
|
||||
geometries.push(key);
|
||||
}
|
||||
let geometries = [];
|
||||
for (let key in data) {
|
||||
if (typeof data[key] !== 'object') continue;
|
||||
geometries.push({
|
||||
name: key,
|
||||
object: data[key]
|
||||
});
|
||||
}
|
||||
if (geometries.length === 1) {
|
||||
parseGeometry({object: data[geometries[0]], name: geometries[0]})
|
||||
parseGeometry(geometries[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
$('#pe_search_bar').val('')
|
||||
if (pe_list && pe_list._data) {
|
||||
pe_list._data.search_term = ''
|
||||
}
|
||||
geometries.forEach(geo => {
|
||||
geo.uuid = guid();
|
||||
|
||||
function create_thumbnail(model_entry, isize) {
|
||||
var included_bones = []
|
||||
model_entry.object.bones.forEach(function(b) {
|
||||
included_bones.push(b.name)
|
||||
})
|
||||
new Jimp(48, 48, 0x00000000, function(err, image) {
|
||||
model_entry.object.bones.forEach(function(b) {
|
||||
var rotation = b.rotation
|
||||
if (!rotation || rotation[0] === undefined) {
|
||||
if (entityMode.hardcodes[model_entry.name] && entityMode.hardcodes[model_entry.name][b.name]) {
|
||||
rotation = entityMode.hardcodes[model_entry.name][b.name].rotation
|
||||
}
|
||||
}
|
||||
if (b.cubes) {
|
||||
b.cubes.forEach(function(c) {
|
||||
if (c.origin && c.size) {
|
||||
//Do cube
|
||||
var inflate = c.inflate||0
|
||||
var coords = {
|
||||
x: (c.origin[2]-inflate)*isize+24,
|
||||
y: 40-(c.origin[1]+c.size[1]+inflate)*isize,
|
||||
w: (c.size[2]+2*inflate)*isize,
|
||||
h: (c.size[1]+2*inflate)*isize
|
||||
}
|
||||
var shade = (limitNumber(c.origin[0], -24, 24)+24)/48*255
|
||||
var color = parseInt('0xffffff'+shade.toString(16))
|
||||
coords.x = limitNumber(coords.x, 0, 47)
|
||||
coords.y = limitNumber(coords.y, 0, 47)
|
||||
coords.w = limitNumber(coords.w, 0, 47 - coords.x)
|
||||
coords.h = limitNumber(coords.h, 0, 47 - coords.y)
|
||||
if (coords.h > 0 && coords.w > 0) {
|
||||
if (rotation && rotation[0] !== 0 && b.pivot) {
|
||||
Painter.drawRotatedRectangle(
|
||||
image,
|
||||
0xffffff88,
|
||||
coords,
|
||||
b.pivot[2]*isize+24,
|
||||
40-b.pivot[1]*isize,
|
||||
-rotation[0]
|
||||
)
|
||||
} else {
|
||||
Painter.drawRectangle(image, 0xffffff88, coords)
|
||||
}
|
||||
}
|
||||
}
|
||||
geo.bonecount = 0;
|
||||
geo.cubecount = 0;
|
||||
if (geo.object.bones instanceof Array) {
|
||||
geo.object.bones.forEach(bone => {
|
||||
geo.bonecount++;
|
||||
if (bone.cubes instanceof Array) geo.cubecount += bone.cubes.length;
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
let selected = null;
|
||||
new Dialog({
|
||||
id: 'bedrock_model_select',
|
||||
title: 'dialog.select_model.title',
|
||||
buttons: ['Import', 'dialog.cancel'],
|
||||
component: {
|
||||
data() {return {
|
||||
search_term: '',
|
||||
geometries,
|
||||
selected: null,
|
||||
}},
|
||||
computed: {
|
||||
filtered_geometries() {
|
||||
if (!this.search_term) return this.geometries;
|
||||
let term = this.search_term.toLowerCase();
|
||||
return this.geometries.filter(geo => {
|
||||
return geo.name.toLowerCase().includes(term)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
//Send
|
||||
image.getBase64("image/png", function(a, dataUrl){
|
||||
model_entry.icon = dataUrl
|
||||
})
|
||||
})
|
||||
}
|
||||
for (var key in data) {
|
||||
if (key.includes('geometry.') && data.hasOwnProperty(key)) {
|
||||
var base_model = {name: key, bonecount: 0, cubecount: 0, selected: false, object: data[key], icon: false}
|
||||
var oversize = 2;
|
||||
var words = key.replace(/:.*/g, '').replace('geometry.', '').split(/[\._]/g)
|
||||
words.forEach(function(w, wi) {
|
||||
words[wi] = capitalizeFirstLetter(w)
|
||||
})
|
||||
base_model.title = words.join(' ')
|
||||
if (data[key].bones) {
|
||||
base_model.bonecount = data[key].bones.length
|
||||
data[key].bones.forEach(function(b) {
|
||||
if (b.cubes) {
|
||||
base_model.cubecount += b.cubes.length
|
||||
b.cubes.forEach(function(c) {
|
||||
if (c.origin && c.size && (c.origin[2] < -12 || c.origin[2] + c.size[2] > 12 || c.origin[1] + c.size[1] > 22) && oversize === 2) oversize = 1
|
||||
if (c.origin && c.size && (c.origin[2] < -24 || c.origin[2] + c.size[2] > 24)) oversize = 0.5
|
||||
})
|
||||
}
|
||||
})
|
||||
if (typeof base_model.cubecount !== 'number') {
|
||||
base_model.cubecount = '[E]'
|
||||
} else if (base_model.cubecount > 0) {
|
||||
|
||||
create_thumbnail(base_model, oversize)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
pe_list_data.push(base_model)
|
||||
}
|
||||
}
|
||||
if (pe_list == undefined) {
|
||||
pe_list = new Vue({
|
||||
el: '#pe_list',
|
||||
data: {
|
||||
search_term: '',
|
||||
list: pe_list_data
|
||||
},
|
||||
methods: {
|
||||
selectE: function(item, event) {
|
||||
var index = pe_list_data.indexOf(item)
|
||||
pe_list_data.forEach(function(s) {
|
||||
s.selected = false;
|
||||
})
|
||||
pe_list_data[index].selected = true
|
||||
selectGeometry(geo) {
|
||||
this.selected = selected = geo;
|
||||
},
|
||||
open() {
|
||||
parseGeometry()
|
||||
open(geo) {
|
||||
parseGeometry(geo);
|
||||
},
|
||||
tl
|
||||
},
|
||||
computed: {
|
||||
searched() {
|
||||
return this.list.filter(item => {
|
||||
return item.name.toUpperCase().includes(this.search_term)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
showDialog('entity_import')
|
||||
$('#pe_list').css('max-height', (window.innerHeight - 320) +'px')
|
||||
$('input#pe_search_bar').select()
|
||||
$('#entity_import .confirm_btn').off('click')
|
||||
$('#entity_import .confirm_btn').on('click', (e) => {
|
||||
parseGeometry()
|
||||
})
|
||||
template: `
|
||||
<div>
|
||||
<search-bar v-model="search_term"></search-bar>
|
||||
<ul class="list" id="model_select_list">
|
||||
<li v-for="geometry in filtered_geometries" :key="geometry.uuid" :class="{selected: geometry == selected}" @click="selectGeometry(geometry)" @dblclick="open(geometry)">
|
||||
<p>{{ geometry.name }}</p>
|
||||
<label>{{ geometry.bonecount+' ${tl('dialog.select_model.bones')}' }}, {{ geometry.cubecount+' ${tl('dialog.select_model.cubes')}' }}</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`
|
||||
},
|
||||
onConfirm() {
|
||||
parseGeometry(selected);
|
||||
}
|
||||
}).show();
|
||||
},
|
||||
export() {
|
||||
var scope = this;
|
||||
|
File diff suppressed because one or more lines are too long
@ -487,10 +487,9 @@
|
||||
"dialog.toolbar_edit.hidden": "Hidden",
|
||||
"dialog.toolbar_edit.hidden_tools": "Some tools might be hidden because they are not available in the current mode, format, or situation.",
|
||||
|
||||
"dialog.entitylist.title": "Open Entity Model",
|
||||
"dialog.entitylist.text": "Select the model you want to import",
|
||||
"dialog.entitylist.bones": "Bones",
|
||||
"dialog.entitylist.cubes": "Cubes",
|
||||
"dialog.select_model.title": "Select Model",
|
||||
"dialog.select_model.bones": "Bones",
|
||||
"dialog.select_model.cubes": "Cubes",
|
||||
|
||||
"dialog.animation_import.title": "Select Animations to Import",
|
||||
"dialog.animation_export.title": "Select Animations to Export",
|
||||
|
Loading…
Reference in New Issue
Block a user