mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-02-11 16:12:06 +08:00
445 lines
12 KiB
JavaScript
445 lines
12 KiB
JavaScript
(function() {
|
|
|
|
function parseGeometry(data) {
|
|
let geometry_name = data.name.replace(/^geometry\./, '');
|
|
|
|
let existing_tab = isApp && ModelProject.all.find(project => (
|
|
Project !== project && project.export_path == Project.export_path && project.geometry_name == geometry_name
|
|
))
|
|
if (existing_tab) {
|
|
Project.close().then(() => {
|
|
existing_tab.select();
|
|
});
|
|
return;
|
|
}
|
|
|
|
codec.dispatchEvent('parse', {model: data.object});
|
|
Project.geometry_name = geometry_name;
|
|
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 || 0);
|
|
Project.visible_box[1] = Math.max(Project.visible_box[1], data.object.visible_bounds_height || 0);
|
|
if (data.object.visible_bounds_offset && typeof data.object.visible_bounds_offset[1] == 'number') {
|
|
Project.visible_box[2] = data.object.visible_bounds_offset[1] || 0;
|
|
}
|
|
}
|
|
|
|
var bones = {}
|
|
|
|
if (data.object.bones) {
|
|
var included_bones = []
|
|
data.object.bones.forEach(function(b) {
|
|
included_bones.push(b.name)
|
|
})
|
|
data.object.bones.forEach(function(b, bi) {
|
|
var group = new Group({
|
|
name: b.name,
|
|
origin: b.pivot,
|
|
rotation: b.rotation,
|
|
material: b.material,
|
|
color: Group.all.length%markerColors.length
|
|
}).init()
|
|
bones[b.name] = group
|
|
if (b.pivot) {
|
|
group.origin[0] *= -1
|
|
}
|
|
group.rotation[0] *= -1;
|
|
group.rotation[1] *= -1;
|
|
|
|
group.mirror_uv = b.mirror === true
|
|
group.reset = b.reset === true
|
|
|
|
if (b.cubes) {
|
|
b.cubes.forEach(function(s) {
|
|
var base_cube = new Cube({name: b.name, autouv: 0, color: group.color})
|
|
if (s.origin) {
|
|
base_cube.from.V3_set(s.origin);
|
|
base_cube.from[0] = -(base_cube.from[0] + s.size[0])
|
|
if (s.size) {
|
|
base_cube.to[0] = s.size[0] + base_cube.from[0]
|
|
base_cube.to[1] = s.size[1] + base_cube.from[1]
|
|
base_cube.to[2] = s.size[2] + base_cube.from[2]
|
|
}
|
|
}
|
|
if (s.uv) {
|
|
base_cube.uv_offset[0] = s.uv[0]
|
|
base_cube.uv_offset[1] = s.uv[1]
|
|
}
|
|
if (s.inflate && typeof s.inflate === 'number') {
|
|
base_cube.inflate = s.inflate
|
|
}
|
|
if (s.mirror === undefined) {
|
|
base_cube.mirror_uv = group.mirror_uv
|
|
} else {
|
|
base_cube.mirror_uv = s.mirror === true
|
|
}
|
|
base_cube.addTo(group).init()
|
|
})
|
|
}
|
|
if (b.children) {
|
|
b.children.forEach(function(cg) {
|
|
cg.addTo(group)
|
|
})
|
|
}
|
|
if (b.locators) {
|
|
for (var key in b.locators) {
|
|
var coords, rotation;
|
|
if (b.locators[key] instanceof Array) {
|
|
coords = b.locators[key];
|
|
} else {
|
|
coords = b.locators[key].offset;
|
|
rotation = b.locators[key].rotation;
|
|
}
|
|
coords[0] *= -1
|
|
var locator = new Locator({position: coords, name: key, rotation}).addTo(group).init();
|
|
}
|
|
}
|
|
var parent_group = 'root';
|
|
if (b.parent) {
|
|
if (bones[b.parent]) {
|
|
parent_group = bones[b.parent]
|
|
} else {
|
|
data.object.bones.forEach(function(ib) {
|
|
if (ib.name === b.parent) {
|
|
ib.children && ib.children.length ? ib.children.push(group) : ib.children = [group]
|
|
}
|
|
})
|
|
}
|
|
}
|
|
group.addTo(parent_group)
|
|
})
|
|
}
|
|
|
|
codec.dispatchEvent('parsed', {model: data.object});
|
|
|
|
loadTextureDraggable()
|
|
Canvas.updateAllBones()
|
|
setProjectTitle()
|
|
if (isApp && Project.geometry_name && Project.BedrockEntityManager) {
|
|
Project.BedrockEntityManager.initEntity()
|
|
}
|
|
Validator.validate()
|
|
updateSelection()
|
|
}
|
|
|
|
|
|
var codec = new Codec('bedrock_old', {
|
|
name: 'Bedrock Entity Model',
|
|
extension: 'json',
|
|
remember: true,
|
|
multiple_per_file: true,
|
|
load_filter: {
|
|
type: 'json',
|
|
extensions: ['json'],
|
|
condition(model) {
|
|
return (model.format_version && compareVersions('1.12.0', model.format_version)) ||
|
|
Object.keys(model).find(s => s.match(/^geometry\./));
|
|
}
|
|
},
|
|
compile(options) {
|
|
if (options === undefined) options = {}
|
|
var entitymodel = {}
|
|
entitymodel.texturewidth = Project.texture_width;
|
|
entitymodel.textureheight = Project.texture_height;
|
|
var bones = []
|
|
var visible_box = new THREE.Box3()
|
|
|
|
var groups = getAllGroups();
|
|
var loose_elements = [];
|
|
Outliner.root.forEach(obj => {
|
|
if (obj.type === 'cube' || obj.type == 'locator') {
|
|
loose_elements.push(obj)
|
|
}
|
|
})
|
|
if (loose_elements.length) {
|
|
let group = new Group({
|
|
name: 'bb_main'
|
|
});
|
|
group.children.push(...loose_elements);
|
|
group.is_catch_bone = true;
|
|
group.createUniqueName();
|
|
groups.splice(0, 0, group);
|
|
}
|
|
|
|
groups.forEach(function(g) {
|
|
if (g.type !== 'group') return;
|
|
if (!settings.export_empty_groups.value && !g.children.find(child => child.export)) return;
|
|
//Bone
|
|
var bone = {}
|
|
bone.name = g.name
|
|
if (g.parent.type === 'group') {
|
|
bone.parent = g.parent.name
|
|
}
|
|
bone.pivot = g.origin.slice()
|
|
bone.pivot[0] *= -1
|
|
if (!g.rotation.allEqual(0)) {
|
|
bone.rotation = [
|
|
-g.rotation[0],
|
|
-g.rotation[1],
|
|
g.rotation[2]
|
|
]
|
|
}
|
|
if (g.reset) bone.reset = true;
|
|
if (g.mirror_uv && Project.box_uv) bone.mirror = true;
|
|
if (g.material) bone.material = g.material;
|
|
|
|
//Elements
|
|
var cubes = []
|
|
var locators = {};
|
|
for (var obj of g.children) {
|
|
if (obj.export) {
|
|
if (obj instanceof Cube) {
|
|
|
|
var template = new oneLiner()
|
|
template.origin = obj.from.slice()
|
|
template.size = obj.size()
|
|
template.origin[0] = -(template.origin[0] + template.size[0])
|
|
template.uv = obj.uv_offset
|
|
if (obj.inflate && typeof obj.inflate === 'number') {
|
|
template.inflate = obj.inflate
|
|
}
|
|
if (obj.mirror_uv === !bone.mirror) {
|
|
template.mirror = obj.mirror_uv
|
|
}
|
|
//Visible Bounds
|
|
var mesh = obj.mesh
|
|
if (mesh) {
|
|
visible_box.expandByObject(mesh)
|
|
}
|
|
cubes.push(template)
|
|
|
|
} else if (obj instanceof Locator) {
|
|
|
|
locators[obj.name] = obj.position.slice();
|
|
locators[obj.name][0] *= -1;
|
|
}
|
|
}
|
|
}
|
|
if (cubes.length) {
|
|
bone.cubes = cubes
|
|
}
|
|
if (Object.keys(locators).length) {
|
|
bone.locators = locators
|
|
}
|
|
bones.push(bone)
|
|
})
|
|
|
|
if (bones.length && options.visible_box !== false) {
|
|
|
|
let visible_box = calculateVisibleBox();
|
|
entitymodel.visible_bounds_width = visible_box[0] || 0;
|
|
entitymodel.visible_bounds_height = visible_box[1] || 0;
|
|
entitymodel.visible_bounds_offset = [0, visible_box[2] || 0, 0]
|
|
}
|
|
if (bones.length) {
|
|
entitymodel.bones = bones
|
|
}
|
|
this.dispatchEvent('compile', {model: entitymodel, options});
|
|
|
|
if (options.raw) {
|
|
return entitymodel
|
|
} else {
|
|
var model_name = 'geometry.' + (Project.geometry_name||Project.name||'unknown')
|
|
return autoStringify({
|
|
format_version: '1.10.0',
|
|
[model_name]: entitymodel
|
|
})
|
|
}
|
|
},
|
|
parse(data, path) {
|
|
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(geometries[0]);
|
|
return;
|
|
} else if (isApp && BedrockEntityManager.CurrentContext?.geometry) {
|
|
return parseGeometry(geometries.find(geo => geo.name == BedrockEntityManager.CurrentContext.geometry));
|
|
}
|
|
|
|
geometries.forEach(geo => {
|
|
geo.uuid = guid();
|
|
|
|
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)
|
|
})
|
|
}
|
|
},
|
|
methods: {
|
|
selectGeometry(geo) {
|
|
this.selected = selected = geo;
|
|
},
|
|
open(geo) {
|
|
Dialog.open.hide();
|
|
parseGeometry(geo);
|
|
},
|
|
tl
|
|
},
|
|
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;
|
|
Blockbench.export({
|
|
resource_id: 'model',
|
|
type: this.name,
|
|
extensions: [this.extension],
|
|
name: this.fileName(),
|
|
startpath: this.startPath(),
|
|
content: this.compile({raw: isApp}),
|
|
custom_writer: isApp ? (a, path) => scope.overwrite(a, path, () => scope.afterSave(path)) : null,
|
|
})
|
|
},
|
|
|
|
overwrite(content, path, cb) {
|
|
|
|
var model_name = 'geometry.' + (Project.geometry_name.replace(/^geometry\./, '')||'unknown')
|
|
var data;
|
|
try {
|
|
data = fs.readFileSync(path, 'utf-8')
|
|
} catch (err) {}
|
|
var obj = {
|
|
format_version: '1.10.0'
|
|
}
|
|
if (data) {
|
|
try {
|
|
obj = autoParseJSON(data, false)
|
|
} catch (err) {
|
|
err = err+''
|
|
var answer = electron.dialog.showMessageBoxSync(currentwindow, {
|
|
type: 'warning',
|
|
buttons: [
|
|
tl('message.bedrock_overwrite_error.backup_overwrite'),
|
|
tl('message.bedrock_overwrite_error.overwrite'),
|
|
tl('dialog.cancel')
|
|
],
|
|
title: 'Blockbench',
|
|
message: tl('message.bedrock_overwrite_error.message'),
|
|
detail: err,
|
|
noLink: false
|
|
})
|
|
if (answer === 0) {
|
|
var backup_file_name = pathToName(path, true) + ' backup ' + new Date().toLocaleString().split(':').join('_')
|
|
backup_file_name = path.replace(pathToName(path, false), backup_file_name)
|
|
fs.writeFile(backup_file_name, data, function (err2) {
|
|
if (err2) {
|
|
console.log('Error saving backup model: ', err2)
|
|
}
|
|
})
|
|
}
|
|
if (answer === 2) {
|
|
return;
|
|
}
|
|
}
|
|
if (typeof obj === 'object') {
|
|
for (var key in obj) {
|
|
if (obj.hasOwnProperty(key) &&
|
|
obj[key].bones &&
|
|
typeof obj[key].bones === 'object' &&
|
|
obj[key].bones.constructor.name === 'Array'
|
|
) {
|
|
obj[key].bones.forEach(function(bone) {
|
|
if (typeof bone.cubes === 'object' &&
|
|
bone.cubes.constructor.name === 'Array'
|
|
) {
|
|
bone.cubes.forEach(function(c, ci) {
|
|
bone.cubes[ci] = new oneLiner(c)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
obj[model_name] = this.compile({raw: true});
|
|
content = autoStringify(obj);
|
|
|
|
Blockbench.writeFile(path, {content}, cb);
|
|
}
|
|
})
|
|
|
|
var format = new ModelFormat({
|
|
id: 'bedrock_old',
|
|
extension: 'json',
|
|
icon: 'icon-format_bedrock_legacy',
|
|
category: 'minecraft',
|
|
show_on_start_screen: false,
|
|
box_uv: true,
|
|
single_texture: true,
|
|
bone_rig: true,
|
|
centered_grid: true,
|
|
animated_textures: true,
|
|
animation_files: true,
|
|
animation_controllers: true,
|
|
animation_mode: true,
|
|
locators: true,
|
|
codec,
|
|
onSetup(project) {
|
|
if (isApp) {
|
|
project.BedrockEntityManager = new BedrockEntityManager(project);
|
|
}
|
|
}
|
|
})
|
|
codec.format = format;
|
|
|
|
BARS.defineActions(function() {
|
|
codec.export_action = new Action({
|
|
id: 'export_entity',
|
|
icon: format.icon,
|
|
category: 'file',
|
|
condition: () => Format == format,
|
|
click: function () {
|
|
codec.export()
|
|
}
|
|
})
|
|
})
|
|
|
|
})()
|
|
|