Basic model merging function

This commit is contained in:
JannisX11 2021-01-09 13:37:50 +01:00
parent b6c3c3fbaa
commit c2ed10d547
6 changed files with 183 additions and 59 deletions

View File

@ -504,7 +504,8 @@ const MenuBar = {
'close_project',
'_',
{name: 'menu.file.import', id: 'import', icon: 'insert_drive_file', children: [
'add_model',
'import_project',
'import_java_block_model',
'import_optifine_part',
'extrude_texture'
]},

View File

@ -9,6 +9,7 @@ class Codec {
Merge.function(this, data, 'load');
Merge.function(this, data, 'compile');
Merge.function(this, data, 'parse');
Merge.function(this, data, 'merge');
Merge.function(this, data, 'write');
Merge.function(this, data, 'overwrite');
Merge.function(this, data, 'export');

View File

@ -2,6 +2,56 @@
let FORMATV = '3.6';
function processHeader(model) {
if (!model.meta) {
Blockbench.showMessageBox({
translateKey: 'invalid_model',
icon: 'error',
})
return;
}
if (!model.meta.format_version) {
model.meta.format_version = model.meta.format;
}
if (compareVersions(model.meta.format_version, FORMATV)) {
Blockbench.showMessageBox({
translateKey: 'outdated_client',
icon: 'error',
})
return;
}
}
function processCompatibility(model) {
if (!model.meta.model_format) {
if (model.meta.bone_rig) {
model.meta.model_format = 'bedrock_old';
} else {
model.meta.model_format = 'java_block';
}
}
if (model.cubes && !model.elements) {
model.elements = model.cubes;
}
if (model.outliner) {
if (compareVersions('3.2', model.meta.format_version)) {
//Fix Z-axis inversion pre 3.2
function iterate(list) {
for (var child of list) {
if (typeof child == 'object' ) {
iterate(child.children);
if (child.rotation) child.rotation[2] *= -1;
}
}
}
iterate(model.outliner)
}
parseGroups(model.outliner)
}
}
var codec = new Codec('project', {
name: 'Blockbench Project',
extension: 'bbmodel',
@ -124,30 +174,13 @@ var codec = new Codec('project', {
}
},
parse(model, path) {
if (!model.meta) {
Blockbench.showMessageBox({
translateKey: 'invalid_model',
icon: 'error',
})
return;
}
if (!model.meta.format_version) {
model.meta.format_version = model.meta.format;
}
if (compareVersions(model.meta.format_version, FORMATV)) {
Blockbench.showMessageBox({
translateKey: 'outdated_client',
icon: 'error',
})
return;
}
processHeader(model);
processCompatibility(model);
if (model.meta.model_format) {
var format = Formats[model.meta.model_format]||Formats.free;
format.select()
} else if (model.meta.bone_rig) {
Formats.bedrock_old.select()
} else {
Formats.java_block.select()
}
Blockbench.dispatchEvent('load_project', {model, path});
@ -179,10 +212,8 @@ var codec = new Codec('project', {
}
})
}
if (model.cubes && !model.elements) {
model.elements = model.cubes;
}
if (model.elements) {
let default_texture = Texture.getDefault();
model.elements.forEach(function(element) {
var copy = NonGroup.fromSave(element, true)
@ -192,8 +223,8 @@ var codec = new Codec('project', {
if (texture) {
copy.faces[face].texture = texture.uuid
}
} else if (Texture.getDefault() && copy.faces && copy.faces[face].texture !== null) {
copy.faces[face].texture = Texture.getDefault().uuid
} else if (default_texture && copy.faces && copy.faces[face].texture !== null) {
copy.faces[face].texture = default_texture.uuid
}
}
copy.init()
@ -202,18 +233,6 @@ var codec = new Codec('project', {
loadOutlinerDraggable()
}
if (model.outliner) {
if (compareVersions('3.2', model.meta.format_version)) {
//Fix Z-axis inversion pre 3.2
function iterate(list) {
for (var child of list) {
if (typeof child == 'object' ) {
iterate(child.children);
if (child.rotation) child.rotation[2] *= -1;
}
}
}
iterate(model.outliner)
}
parseGroups(model.outliner)
}
if (model.animations) {
@ -236,6 +255,89 @@ var codec = new Codec('project', {
Canvas.updateAllBones()
Canvas.updateAllPositions()
this.dispatchEvent('parsed', {model})
},
merge(model, path) {
/**
* Todo
*
* texture merging
* UV handling
* Outliner issue
* undo
*/
processHeader(model);
processCompatibility(model);
Blockbench.dispatchEvent('merge_project', {model, path});
this.dispatchEvent('merge', {model})
if (model.overrides instanceof Array && Project.overrides instanceof Array) {
Project.overrides.push(...model.overrides);
}
let width = model.resolution.width || Project.texture_width;
let height = model.resolution.height || Project.texture_height;
function loadTexture(tex) {
var tex_copy = new Texture(tex, tex.uuid).add(false);
if (isApp && tex.path && fs.existsSync(tex.path) && !model.meta.backup) {
tex_copy.fromPath(tex.path)
} else if (tex.source && tex.source.substr(0, 5) == 'data:') {
tex_copy.fromDataURL(tex.source)
}
}
if (model.textures && (!Format.single_texture || Texture.all.length == 0)) {
model.textures.forEach(loadTexture)
}
if (model.elements) {
let default_texture = Texture.getDefault();
model.elements.forEach(function(element) {
var copy = NonGroup.fromSave(element, true)
for (var face in copy.faces) {
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 (default_texture && copy.faces && copy.faces[face].texture !== null) {
copy.faces[face].texture = default_texture.uuid
}
}
copy.init()
})
loadOutlinerDraggable()
}
if (model.outliner) {
parseGroups(model.outliner)
}
if (model.animations) {
model.animations.forEach(ani => {
var base_ani = new Animation()
base_ani.uuid = ani.uuid;
base_ani.extend(ani).add();
})
}
if (model.animation_variable_placeholders) {
let vue = Interface.Panels.variable_placeholders.inside_vue;
if (vue._data.text) {
vue._data.text = vue._data.text + '\n\n' + model.animation_variable_placeholders;
} else {
vue._data.text = model.animation_variable_placeholders;
}
}
if (model.display !== undefined) {
DisplayMode.loadJSON(model.display)
}
Canvas.updateAllBones()
Canvas.updateAllPositions()
this.dispatchEvent('parsed', {model})
}
})
@ -263,6 +365,24 @@ BARS.defineActions(function() {
codec.export()
}
})
new Action('import_project', {
icon: 'icon-blockbench_file',
category: 'file',
click: function () {
Blockbench.import({
resource_id: 'model',
extensions: [codec.extension],
type: codec.name,
multiple: true,
}, function(files) {
files.forEach(file => {
var model = autoParseJSON(file.content);
codec.merge(model);
})
})
}
})
})
})()

View File

@ -473,6 +473,24 @@ BARS.defineActions(function() {
codec.export();
}
})
new Action('import_java_block_model', {
icon: 'assessment',
category: 'file',
condition: () => Format == format,
click: function () {
Blockbench.import({
resource_id: 'model',
extensions: ['json'],
type: codec.name,
multiple: true,
}, function(files) {
files.forEach(file => {
var model = autoParseJSON(file.content)
codec.parse(model, file.path, true)
})
})
}
})
})
})()

View File

@ -496,24 +496,6 @@ BARS.defineActions(function() {
})
}
})
new Action('add_model', {
icon: 'assessment',
category: 'file',
condition: _ => (Format.id == 'java_block'),
click: function () {
Blockbench.import({
resource_id: 'model',
extensions: ['json'],
type: 'JSON Model',
multiple: true,
}, function(files) {
files.forEach(file => {
var model = autoParseJSON(file.content)
Codecs.java_block.parse(model, file.path, true)
})
})
}
})
new Action('extrude_texture', {
icon: 'eject',
category: 'file',

View File

@ -701,8 +701,8 @@
"action.convert_project.desc": "Converts the current project to a project for another model format",
"action.close_project": "Close Project",
"action.close_project.desc": "Closes the currently open project",
"action.add_model": "Add Model",
"action.add_model.desc": "Add a model from a file to the current model",
"action.import_java_block_model": "Add Java Block/Item Model",
"action.import_java_block_model.desc": "Add a Minecraft Java block/item model from a json file to the current model",
"action.extrude_texture": "Extruded Texture",
"action.extrude_texture.desc": "Generate a model by stretching out a texture",
"action.export_blockmodel": "Export Block/Item Model",
@ -732,6 +732,8 @@
"action.save_project.desc": "Saves the current model as a project file",
"action.save_project_as": "Save Project As",
"action.save_project_as.desc": "Saves the current model as a project file at a new location",
"action.import_project": "Import Project",
"action.import_project.desc": "Import another project from a .bbmodel file into the current project",
"action.export_over": "Save Model",
"action.export_over.desc": "Saves the model, textures and animations by overwriting the files",