Rewrite bedrock model import select dialog

This commit is contained in:
JannisX11 2022-11-19 19:59:57 +01:00
parent ac89a9c269
commit 888bfa3fa4
6 changed files with 140 additions and 316 deletions

View File

@ -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);
}

View File

@ -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>

View File

@ -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';

View File

@ -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

View File

@ -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",