//New function newProject(entity_mode) { if (showSaveDialog()) { if (Toolbox.selected.id !== 'move_tool') BarItems.move_tool.select(); elements.length = 0; TreeElements.length = 1; TreeElements.splice(0, 1); Canvas.materials.length = 0; textures.length = 0; selected.length = 0; selected_group = undefined; Blockbench.display_settings = display = {}; Project.name = Project.parent = Project.description = ''; Project.texture_width = Project.texture_height = 16; Project.ambientocclusion = true; Prop.file_path = Prop.file_name = Prop.file_name_alt = ''; Prop.project_saved = true; Prop.animation_path = ''; Prop.added_models = 0; setProjectTitle(); Canvas.updateAll(); outliner.$forceUpdate(); texturelist.$forceUpdate(); Undo.history.length = 0; Undo.index = 0; Painter.current = {}; Animator.animations.length = 1; Animator.animations.splice(0, 1); if (entity_mode) { entityMode.join(); } else { entityMode.leave(); } $('#var_placeholder_area').val('') return true; } else { return false; } } //Import function setupDragHandlers() { Blockbench.addDragHandler( 'model', {extensions: ['json', 'jem', 'jpm']}, function(files) { loadModel(files[0].content, files[0].path || files[0].path) if (isApp) { addRecentProject({name: pathToName(files[0].path, 'mobs_id'), path: files[0].path}) } } ) Blockbench.addDragHandler( 'style', {extensions: ['bbstyle']}, function(files) { applyBBStyle(files[0].content) } ) Blockbench.addDragHandler( 'plugin', {extensions: ['bbplugin', 'js']}, function(files) { loadPluginFromFile(files[0]) } ) Blockbench.addDragHandler( 'texture', {extensions: ['png', 'tga'], element: '#textures', propagate: true, readtype: 'image'}, function(files, event) { var texture_li = $(event.target).parents('li.texture') if (texture_li.length) { var tex = getTextureById(texture_li.attr('texid')) if (tex) { tex.fromFile(files[0]) } } else { files.forEach(function(f) { new Texture().fromFile(f).add().fillParticle() }) } } ) } function loadModel(data, filepath, add) { if (!add) { //Create New Project if (newProject() == false) return; Prop.file_path = filepath setProjectTitle(pathToName(filepath, true)) } Blockbench.addFlag('importing') var model = autoParseJSON(data) var extension = pathToExtension(filepath) if (extension === 'jpm') { loadJPMModel(model) } else if (extension === 'jem') { loadJEMModel(model) } else { //JSON for (var key in model) { if (key.includes('geometry.')) { loadPEModelFile(model) return; } } loadBlockModel(model, filepath, add) } loadTextureDraggable() loadOutlinerDraggable() Canvas.updateAll() Blockbench.removeFlag('importing') if (!add) { Prop.project_saved = true; } } function loadBlockModel(model, filepath, add) { if (!model.elements && !model.parent && !model.display && !model.textures) { Blockbench.showMessageBox({ translateKey: 'invalid_model', icon: 'error', }) return; } Blockbench.entity_mode = false; saveSettings() var previous_length = add ? elements.length : 0 var previous_texture_length = add ? textures.length : 0 if (add) { Prop.added_models++; var import_group = new Group(pathToName(filepath, false)) } //Load if (model.display !== undefined) { display = model.display } var oid = elements.length if (model.elements) { model.elements.forEach(function(obj) { base_cube = new Cube(obj) if (obj.__comment) base_cube.name = obj.__comment //Faces var uv_stated = false; for (var face in base_cube.faces) { if (obj.faces[face] === undefined) { base_cube.faces[face].texture = null base_cube.faces[face].uv = [0,0,0,0] } else if (typeof obj.faces[face].uv === 'object') { uv_stated = true } } if (!uv_stated) { base_cube.autouv = 2 base_cube.mapAutoUV() } else { base_cube.autouv = 0; } elements.push(base_cube); if (!add) { TreeElements.push(base_cube) base_cube.parent = 'root' } else if (import_group) { import_group.children.push(base_cube) base_cube.parent = import_group } }) } if (model.groups && model.groups.length > 0) { if (!add) { parseGroups(model.groups) } else if (import_group) { parseGroups(model.groups, import_group, oid) } } if (import_group) { import_group.addTo() } if ( !model.elements && (model.parent == 'item/generated' || model.parent == 'item/handheld' || model.parent == 'item/handheld_rod') && model.textures && typeof model.textures.layer0 === 'string' ) { base_cube = new Cube() base_cube.extend({ name: model.textures.layer0, from: [0, 0, 7.5], to: [16, 16, 7.8], faces: { north: {uv: [16,0,0,16], texture: 'layer0'}, south: {uv: [16,0,16,0], texture: 'layer0'}, east: {uv: [0,0,0,0], texture: null}, west: {uv: [0,0,0,0], texture: null}, up: {uv: [0,0,0,0], texture: null}, down: {uv: [0,0,0,0], texture: null}, }, autouv: 0, export: false }) elements.push(base_cube); base_cube.addTo() } else if (!model.elements && model.parent) { Blockbench.showMessageBox({ translateKey: 'child_model_only', icon: 'info', message: tl('message.child_model_only.message', [model.parent]) }) } if (model.textures) { //Create Path Array to fetch textures var path_arr = filepath.split(osfs) var index = path_arr.length - path_arr.indexOf('models') path_arr.splice(-index) var texture_arr = model.textures var names = {} for (var tex in texture_arr) { if (texture_arr.hasOwnProperty(tex)) { if (tex != 'particle') { var t = new Texture({id: tex}).fromJavaLink(texture_arr[tex], path_arr.slice()).add() names[texture_arr[tex]] = t } } } if (texture_arr === undefined) texture_arr = {} if (texture_arr.particle) { if (names[texture_arr.particle]) { names[texture_arr.particle].enableParticle() } else { new Texture({id: 'particle'}).fromJavaLink(texture_arr[tex], path_arr.slice()).add().enableParticle() } } //Get Rid Of ID overlapping textures.forEach(function(t, i) { if (i >= previous_texture_length) { if (getTexturesById(t.id).length > 1) { var before = t.id t.id = Prop.added_models + '_' + t.id elements.forEach(function(s, si) { if (si >= previous_length) { for (var face in s.faces) { if (s.faces[face].texture === '#'+before) { s.faces[face].texture = '#'+t.id } } } }) } } }) //Select Last Texture if (textures.length > 0) { textures.forEach(function(s) { s.selected = false; }) textures[textures.length-1].selected = true; } } //Set Parent if (model.parent !== undefined) { Project.parent = model.parent; } //Set Ambient Occlusion if (model.ambientocclusion === false) { Project.ambientocclusion = false; } } function loadJPMModel(model) { function addSubmodel(submodel) { if (submodel.boxes) { submodel.boxes.forEach(function(box) { var cs = box.coordinates if (cs && cs.length >= 6) { base_cube = new Cube({ from: [ cs[0], cs[1], cs[2] ], to: [ cs[0] + cs[3], cs[1] + cs[4], cs[2] + cs[5] ], name: submodel.id, faces: { north: {uv: box.uvNorth}, east: {uv: box.uvEast}, south: {uv: box.uvSouth}, west: {uv: box.uvWest}, up: {uv: box.uvUp}, down: {uv: box.uvDown}, }, rotation: submodel.rotate }) elements.push(base_cube); TreeElements.push(base_cube) } }) } if (submodel.submodels) { submodel.submodels.forEach(addSubmodel) } } addSubmodel(model) Canvas.updateAll() } function loadJEMModel(model) { entityMode.join() if (model.textureSize) { Project.texture_width = parseInt(model.textureSize[0]) Project.texture_height = parseInt(model.textureSize[1]) } if (model.models) { model.models.forEach(function(b) { if (typeof b !== 'object') return; //Bone var group = new Group({ name: b.part, origin: b.translate, rotation: b.rotate, shade: !(b.mirrorTexture && b.mirrorTexture.includes('u')) }) group.origin[1] *= -1 group.origin[2] *= -1 //Cubes if ((b.boxes && b.boxes.length) || (b.submodel && b.submodel.boxes && b.submodel.boxes.length)) { function addBox(box, i, mirrored) { var base_cube = new Cube({ name: box.name || group.name, autouv: 0, uv_offset: box.textureOffset, inflate: box.sizeAdd }) if (box.coordinates) { base_cube.extend({ from: [ box.coordinates[0], box.coordinates[1], box.coordinates[2] ], to: [ box.coordinates[0]+box.coordinates[3], box.coordinates[1]+box.coordinates[4], box.coordinates[2]+box.coordinates[5] ] }) } elements.push(base_cube) base_cube.addTo(group, false) } if (b.boxes && b.boxes.length) { b.boxes.forEach(addBox) } if (b.submodel && b.submodel.boxes && b.submodel.boxes.length) { b.submodel.boxes.forEach(function(box, i) {addBox(box, i, true)}) } } group.addTo(undefined, false) }) } loadOutlinerDraggable() Canvas.updateAll() if (model.texture) { var path = Prop.file_path.replace(/\\[\w .-]+$/, '\\'+model.texture) new Texture().fromPath(path).add() } } function loadPEModelFile(data) { pe_list_data.length = 0 entityMode.join() var geometries = [] for (var key in data) { if (typeof data[key] === 'object') { geometries.push(key); } } if (geometries.length === 1) { loadPEModel({object: data[geometries[0]], name: geometries[0]}) return; } $('#pe_search_bar').val('') if (pe_list && pe_list._data) { pe_list._data.search_text = '' } saveSettings() 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) { model_entry.object.bones.forEach(function(b) { //var rotate_bone = false; //if (b.name === 'body' && // (included_bones.includes('leg3') || model_entry.name.includes('chicken') || model_entry.name.includes('ocelot')) && // included_bones.includes('leg4') === false && // !model_entry.name.includes('creeper') && // ( b.rotation === undefined ||b.rotation.join('_') === '0_0_0') //) { // rotate_bone = true; //} 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) } } } }) } }) //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_text: '', 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 } }, computed: { searched() { var scope = this; return this.list.filter(item => { return item.name.toUpperCase().includes(scope.search_text) }) } } }) } showDialog('entity_import') $('#pe_list').css('max-height', ($(window).height() - 320) +'px') $('input#pe_search_bar').select() //texturelist._data.elements = textures } function loadPEModel(data) { if (data === undefined) { pe_list_data.forEach(function(s) { if (s.selected === true) { data = s } }) if (data == undefined) { data = pe_list_data[0] } } Project.parent = data.name Project.texture_width = 64 Project.texture_height = 64 if (data.object.texturewidth !== undefined) { Project.texture_width = data.object.texturewidth } if (data.object.textureheight !== undefined) { Project.texture_height = data.object.textureheight } entityMode.old_res.x = Project.texture_width entityMode.old_res.y = Project.texture_height 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, material: b.material}) bones[b.name] = group if (b.pivot) { group.origin[0] *= -1 } if (b.rotation && b.rotation.join('_') !== '0_0_0') { group.rotation = b.rotation } else { if (entityMode.hardcodes[data.name] && entityMode.hardcodes[data.name][b.name]) { group.rotation = entityMode.hardcodes[data.name][b.name].rotation } else { if (b.name === 'body' && included_bones.includes('leg3') && included_bones.includes('leg4') === false && !data.name.includes('creeper') && (group.rotation.join('_') === '0_0_0' || group.rotation === undefined) ) { group.rotation = [90, 0, 0] } } } group.rotation.forEach(function(br, ri) { group.rotation[ri] *= -1 }) group.shade = !b.mirror group.reset = b.reset === true if (b.cubes) { b.cubes.forEach(function(s) { var base_cube = new Cube({name: b.name, autouv: 0, color: bi%8}) if (s.origin) { base_cube.from = 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.shade = group.shade } else { base_cube.shade = !s.mirror } elements.push(base_cube) base_cube.addTo(group, false) }) } if (b.children) { b.children.forEach(function(cg) { cg.addTo(group, false) }) } 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, false) }) } pe_list_data.length = 0; hideDialog() loadTextureDraggable() loadOutlinerDraggable() Canvas.updateAll() setProjectTitle() if (isApp && data.name) { findEntityTexture(data.name) } } var Extruder = { drawImage: function(path) { Extruder.canvas = $('#extrusion_canvas').get(0) var ctx = extrusion_canvas.getContext('2d') setProgressBar('extrusion_bar', 0) $('#scan_tolerance').on('input', function() { $('#scan_tolerance_label').text($(this).val()) }) showDialog('image_extruder') Extruder.ext_img = new Image() Extruder.ext_img.src = path Extruder.ext_img.style.imageRendering = 'pixelated' ctx.imageSmoothingEnabled = false; Extruder.ext_img.onload = function() { ctx.clearRect(0, 0, 256, 256); ctx.drawImage(Extruder.ext_img, 0, 0, 256, 256) Extruder.width = Extruder.ext_img.naturalWidth Extruder.height = Extruder.ext_img.naturalHeight if (Extruder.width > 128) return; var g = 256 / Extruder.width; var p = 0 ctx.beginPath(); for (var x = 0; x <= 256; x += g) { ctx.moveTo(0.5 + x + p, p); ctx.lineTo(0.5 + x + p, 256 + p); } for (var x = 0; x <= 256; x += g) { ctx.moveTo(p, 0.5 + x + p); ctx.lineTo(256 + p, 0.5 + x + p); } ctx.strokeStyle = "black"; ctx.stroke(); } //Grid }, startConversion: function() { var scan_mode = $('select#scan_mode option:selected').attr('id') /*areas, lines, columns, pixels*/ var texture_index = '#'+textures[textures.length-1].id var isNewProject = elements.length === 0; var jimage = Jimp.read(Extruder.ext_img.src).then(function(image) { var pixel_opacity_tolerance = $('#scan_tolerance').val() //var ext_x, ext_y; var finished_pixels = {} var cube_nr = 0; var cube_name = textures[textures.length-1].name.split('.')[0] selected = [] //Scale Index var scale_i = 1; if (Extruder.width < Extruder.height) { Extruder.width = Extruder.height; } scale_i = 16 / Extruder.width; function isOpaquePixel(px_x, px_y) { return Math.isBetween(px_x, 0, Extruder.width-1) && Math.isBetween(px_y, 0, Extruder.height-1) && parseInt(image.getPixelColor(px_x, px_y).toString(16).substr(6,2), 16) >= pixel_opacity_tolerance; } function finishPixel(x, y) { if (finished_pixels[x] === undefined) { finished_pixels[x] = {} } finished_pixels[x][y] = true } function isPixelFinished(x, y) { return (finished_pixels[x] !== undefined && finished_pixels[x][y] === true) } //Scanning let ext_y = 0; while (ext_y < Extruder.height) { let ext_x = 0; while (ext_x < Extruder.width) { if (isPixelFinished(ext_x, ext_y) === false && isOpaquePixel(ext_x, ext_y) === true) { //Search From New Pixel var loop = true; var rect = {x: ext_x, y: ext_y, x2: ext_x, y2: ext_y} var safety_limit = 5000 //Expanding Loop while (loop === true && safety_limit) { var y_check, x_check, canExpandX, canExpandY; //Expand X if (scan_mode === 'areas' || scan_mode === 'lines') { y_check = rect.y x_check = rect.x2 + 1 canExpandX = true while (y_check <= rect.y2) { //Check If Row is Free if (isOpaquePixel(x_check, y_check) === false || isPixelFinished(x_check, y_check) === true) { canExpandX = false; } y_check += 1 } if (canExpandX === true) { rect.x2 += 1 } } else { canExpandX = false; } //Expand Y if (scan_mode === 'areas' || scan_mode === 'columns') { x_check = rect.x y_check = rect.y2 + 1 canExpandY = true while (x_check <= rect.x2) { //Check If Row is Free if (isOpaquePixel(x_check, y_check) === false || isPixelFinished(x_check, y_check) === true) { canExpandY = false } x_check += 1 } if (canExpandY === true) { rect.y2 += 1 } } else { canExpandY = false; } //Conclusion if (canExpandX === false && canExpandY === false) { loop = false; } safety_limit--; } //Draw Rectangle var draw_x = rect.x var draw_y = rect.y while (draw_y <= rect.y2) { draw_x = rect.x while (draw_x <= rect.x2) { finishPixel(draw_x, draw_y) draw_x++; } draw_y++; } var current_cube = new Cube({name: cube_name+'_'+cube_nr, autouv: 0}) current_cube.from = [rect.x*scale_i, 0, rect.y*scale_i] current_cube.to = [(rect.x2+1)*scale_i, scale_i, (rect.y2+1)*scale_i] //Sides current_cube.faces.up = {uv:[rect.x*scale_i, rect.y*scale_i, (rect.x2+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index} current_cube.faces.down = {uv:[rect.x*scale_i, (rect.y2+1)*scale_i, (rect.x2+1)*scale_i, rect.y*scale_i], texture: texture_index} current_cube.faces.north = {uv:[(rect.x2+1)*scale_i, rect.y*scale_i, rect.x*scale_i, (rect.y+1)*scale_i], texture: texture_index} current_cube.faces.south = {uv:[rect.x*scale_i, rect.y2*scale_i, (rect.x2+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index} current_cube.faces.east = {uv:[rect.x2*scale_i, rect.y*scale_i, (rect.x2+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index, rotation: 90} current_cube.faces.west = {uv:[rect.x*scale_i, rect.y*scale_i, (rect.x+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index, rotation: 270} elements.push(current_cube) selected.push(elements[elements.length-1]) cube_nr++; } ext_x++; } ext_y++; } var group = new Group(cube_name).addTo() selected.forEach(function(s) { s.addTo(group, false) }) if (Blockbench.hasFlag('new_project') || isNewProject) { setProjectTitle(cube_name) Prop.project_saved = false; } Blockbench.removeFlag('new_project') loadOutlinerDraggable() Canvas.updateAll() hideDialog() }) } } //Export class oneLiner { constructor(data) { if (data !== undefined) { for (var key in data) { if (data.hasOwnProperty(key)) { this[key] = data[key] } } } } } function buildBlockModel(options) { if (options === undefined) options = {} var clear_elements = [] var textures_used = [] var element_index_lut = [] var largerCubesNr = 0; function computeCube(s) { if (s.export == false) return; //Create Element var element = {} element_index_lut[s.index()] = clear_elements.length if ((options.cube_name !== false && !settings.minifiedout.value) || options.cube_name === true) { if (s.name !== 'cube') { element.name = s.name } } element.from = s.from.slice() element.to = s.to.slice() if (s.shade === false) { element.shade = false } if (!s.rotation.equals([0, 0, 0])) { element.rotation = new oneLiner({ angle: s.rotation[getAxisNumber(s.rotationAxis())], axis: s.rotationAxis(), origin: s.origin }) } if (s.rescale) { if (element.rotation) { element.rotation.rescale = true } else { element.rotation = new oneLiner({ angle: 0, axis: s.rotation_axis||'y', origin: s.origin, rescale: true }) } } if (s.rotation.positiveItems() >= 2) { element.rotated = s.rotation } var element_has_texture var e_faces = {} for (var face in s.faces) { if (s.faces.hasOwnProperty(face)) { if (s.faces[face].texture !== null) { var tag = new oneLiner() if (s.faces[face].enabled !== false) { tag.uv = s.faces[face].uv } if (s.faces[face].rotation) { tag.rotation = s.faces[face].rotation } if (s.faces[face].texture) { tag.texture = s.faces[face].texture element_has_texture = true } else { tag.texture = '#missing' } if (s.faces[face].cullface !== undefined) { tag.cullface = s.faces[face].cullface } if (s.faces[face].tintindex !== undefined) { tag.tintindex = s.faces[face].tintindex } e_faces[face] = tag } } } //Gather Textures if (element_has_texture) { for (var face in s.faces) { if (s.faces.hasOwnProperty(face)) { if (!textures_used.includes(s.faces[face].texture)) { textures_used.push(s.faces[face].texture) } } } } else { element.color = s.color } element.faces = e_faces if (checkExport('backup')) { element.uv_offset = s.uv_offset } function inVd(n) { return n > 32 || n < -16 } if (inVd(s.from[0]) || inVd(s.from[1]) || inVd(s.from[2]) || inVd(s.to[0]) || inVd(s.to[1]) || inVd(s.to[2]) ) { largerCubesNr++; } clear_elements.push(element) } function iterate(arr) { var i = 0; if (!arr || !arr.length) { return; } for (i=0; i 0 && settings.dialog_larger_cubes.value) { Blockbench.showMessageBox({ translateKey: 'model_clipping', icon: 'settings_overscan', message: tl('message.model_clipping.message', [largerCubesNr]) }) } var blockmodel = {} if (checkExport('comment', settings.credit.value)) { blockmodel.credit = settings.credit.value } if (checkExport('parent', Project.parent != '')) { blockmodel.parent = Project.parent } if (checkExport('ambientocclusion', Project.ambientocclusion === false)) { blockmodel.ambientocclusion = false } if (checkExport('textures', Object.keys(texturesObj).length >= 1)) { blockmodel.textures = texturesObj } if (checkExport('elements', clear_elements.length >= 1)) { blockmodel.elements = clear_elements } if (checkExport('display', Object.keys(display).length >= 1)) { var new_display = {} var entries = 0; for (var key in display) { if (display.hasOwnProperty(key)) { if ((typeof display[key].scale === 'object' && display[key].scale.join('_') !== '1_1_1') || display[key].rotation || display[key].translation ) { new_display[key] = display[key] entries++; if (new_display[key].scale && new_display[key].scale.join('_') === '1_1_1') { new_display[key].scale = undefined } } } } if (entries) { blockmodel.display = new_display } } if (checkExport('groups', (settings.export_groups.value && getAllOutlinerGroups().length))) { groups = compileGroups(false, element_index_lut) var i = 0; while (i < groups.length) { if (typeof groups[i] === 'object') { i = Infinity } i++ } if (i === Infinity) { blockmodel.groups = groups } } if (checkExport('backup')) { blockmodel.mode = Blockbench.entity_mode ? 'entity' : 'block' } if (options.raw) { return blockmodel } else { return autoStringify(blockmodel) } } function buildEntityModel(options) { if (options === undefined) options = {} var entitymodel = {} entitymodel.texturewidth = parseInt(Project.texture_width); entitymodel.textureheight = parseInt(Project.texture_height); var bones = [] var cube_count = 0; var visible_box = new THREE.Box3() getAllOutlinerGroups().forEach(function(g) { if (g.type !== 'group') 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.join('_') !== '0_0_0') { bone.rotation = g.rotation.slice() bone.rotation.forEach(function(br, ri) { bone.rotation[ri] *= -1 }) } if (g.reset) { bone.reset = true } if (!g.shade) { bone.mirror = true } if (g.material) { bone.material = g.material } //Cubes if (g.children && g.children.length) { bone.cubes = [] var i = 0; while (i < g.children.length) { var s = g.children[i] if (s !== undefined && s.type === 'cube' && s.export !== false) { var cube = new oneLiner() cube.origin = s.from.slice() cube.size = s.size() cube.origin[0] = -(cube.origin[0] + cube.size[0]) cube.uv = s.uv_offset if (s.inflate && typeof s.inflate === 'number') { cube.inflate = s.inflate } if (s.shade === !!bone.mirror) { cube.mirror = !s.shade } //Visible Bounds var mesh = s.getMesh() if (mesh) { visible_box.expandByObject(mesh) } bone.cubes.push(cube) cube_count++; } i++; } } bones.push(bone) }) if (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] } entitymodel.bones = bones if (options.raw) { return entitymodel } else { return autoStringify(entitymodel) } } function buildJPMModel(options) { if (options === undefined) options = {} var jpm = {} if (textures[0]) { jpm.texture = pathToName(textures[0].name, false) } jpm.textureSize = [Project.texture_width, Project.texture_height] if (settings.credit.value) { jpm.credit = settings.credit.value } var submodels = [] var boxes = [] elements.forEach(function(s) { if (s.export === false) return; var box = {} box.coordinates = [s.from[0], s.from[1], s.from[2], s.size(0), s.size(1), s.size(2)] for (var face in s.faces) { if (s.faces.hasOwnProperty(face)) { if (s.faces[face].texture !== undefined && s.faces[face].texture !== null) { box['uv'+capitalizeFirstLetter(face)] = [ s.faces[face].uv[0] / 16 * Project.texture_width, s.faces[face].uv[1] / 16 * Project.texture_height, s.faces[face].uv[2] / 16 * Project.texture_width, s.faces[face].uv[3] / 16 * Project.texture_height ] } } } if (!s.rotation.equals([0, 0, 0])) { var submodel = { boxes: [box], id: s.name, rotate: s.rotation } submodels.push(submodel) } else { boxes.push(box) } submodels.push(submodel) }) if (boxes.length) { jpm.boxes = boxes } if (submodels.length) { jpm.submodels = submodels } if (options.raw) { return jpm } else { return autoStringify(jpm) } } function buildJEMModel(options) { if (options === undefined) options = {} var entitymodel = {} if (textures[0]) { entitymodel.texture = textures[0].name } entitymodel.textureSize = [parseInt(Project.texture_width), parseInt(Project.texture_height)]; var models = [] TreeElements.forEach(function(g) { if (g.type !== 'group') return; //Bone var bone = {} bone.part = g.name bone.invertAxis = 'xy' bone.translate = g.origin.slice() bone.translate[1] *= -1 bone.translate[2] *= -1 if (g.rotation.join('_') !== '0_0_0') { bone.rotate = g.rotation.slice() } if (g.shade === false) { bone.mirrorTexture = 'u' } //Cubes if (g.children && g.children.length) { bone.boxes = [] var mirrored_boxes = [] function iterate(arr) { var i = 0; while (i < arr.length) { if (arr[i].type === 'group') { iterate(arr[i].children) } else if (arr[i].type === 'cube') { var s = arr[i] if (s !== undefined && s.export !== false) { var cube = new oneLiner() var c_pos = s.from.slice() var c_size = s.size() cube.coordinates = [ c_pos[0],//b_translate[0] - c_pos[0] - c_size[0], c_pos[1],//b_translate[1] - c_pos[1] - c_size[1], c_pos[2], c_size[0], c_size[1], c_size[2] ] cube.textureOffset = s.uv_offset if (s.inflate && typeof s.inflate === 'number') { cube.sizeAdd = s.inflate } if (s.shade === g.shade) { bone.boxes.push(cube) } else { mirrored_boxes.push(cube) } } } i++; } } iterate(g.children) if (mirrored_boxes.length) { bone.submodel = { invertAxis: 'xy', boxes: mirrored_boxes } if (g.shade !== false) { bone.submodel.mirrorTexture = 'u' } } } models.push(bone) }) entitymodel.models = models if (options.raw) { return entitymodel } else { return autoStringify(entitymodel) } } function buildClassModel(options) { function F(num) { var s = trimFloatNumber(num) + '' if (!s.includes('.')) { s += '.0' } return s+'F'; } var bones = [] var bone_nr = 1 var model_id = Project.parent.replace('geometry.', '') || 'unknown'; var all_groups = getAllOutlinerGroups() var loose_cubes = [] TreeElements.forEach(obj => { if (obj.type === 'cube') { loose_cubes.push(obj) } }) if (loose_cubes.length) { var group = { 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.type !== 'group', lines: [ `${id} = new ModelRenderer(this);`,//Texture Offset `${id}.setRotationPoint(${F(-g.origin[0])}, ${F(24-g.origin[1])}, ${F(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) { let parent_index = all_groups.indexOf(g.parent) if (parent_index >= 0) { bone.lines.push( `${ g.parent.name }.addChild(${id});` ) } } //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.shade ] bone.lines.push( `${id}.cubeList.add(new ModelBox(${ values.join(', ') }));` ) }) bones.push(bone) }) var model = (settings.credit.value ? '//'+settings.credit.value+'\n' : '')+ '//Paste this code into your mod.\n' + '\nimport org.lwjgl.opengl.GL11;'+ '\nimport net.minecraft.client.model.ModelBase;'+ '\nimport net.minecraft.client.model.ModelBox;'+ '\nimport net.minecraft.client.model.ModelRenderer;'+ '\nimport net.minecraft.client.renderer.GlStateManager;'+ '\nimport net.minecraft.entity.Entity;\n'+ '\npublic class '+model_id+' extends ModelBase {' bones.forEach((bone) => { model += `\n private final ModelRenderer ${bone.id};`; }) model += '\n'+ '\n public '+model_id+'() {'+ '\n textureWidth = '+ (Project.texture_width || 32) +';'+ '\n textureHeight = '+ (Project.texture_height|| 32) +';\n'; bones.forEach((bone) => { model += `\n ${bone.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) {' bones.forEach((bone) => { if (bone.rootBone) { model += `\n ${bone.id}.render(f5);`; } }) model += '\n }'+ '\n public void setRotationAngle(ModelRenderer modelRenderer, float x, float y, float z) {'+ '\n modelRenderer.rotateAngleX = x;'+ '\n modelRenderer.rotateAngleY = y;'+ '\n modelRenderer.rotateAngleZ = z;'+ '\n }'+ '\n}'; return model; } function buildOBJModel(name) { scene.position.set(0,0,0) var exporter = new THREE.OBJExporter(); var content = exporter.parse( scene, name); scene.position.set(-8,-8,-8) return content; } function compileJSON(object, options) { var output = '' if (typeof options !== 'object') options = {} function newLine(tabs) { if (options.small === true) {return '';} var s = '\n' for (var i = 0; i < tabs; i++) { s += '\t' } return s; } function handleVar(o, tabs) { var out = '' if (typeof o === 'string') { //String out += '"' + o.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"' } else if (typeof o === 'boolean') { //Boolean out += (o ? 'true' : 'false') } else if (typeof o === 'number') { //Number o = (Math.round(o*100000)/100000).toString() out += o } else if (o === null || o === Infinity || o === -Infinity) { //Null out += 'null' } else if (typeof o === 'object' && o.constructor.name === 'Array') { //Array var has_content = false out += '[' for (var i = 0; i < o.length; i++) { var compiled = handleVar(o[i], tabs+1) if (compiled) { var breaks = typeof o[i] === 'object' if (has_content) {out += ',' + (breaks || options.small?'':' ')} if (breaks) {out += newLine(tabs)} out += compiled has_content = true } } if (typeof o[o.length-1] === 'object') {out += newLine(tabs-1)} out += ']' } else if (typeof o === 'object') { //Object var breaks = o.constructor.name !== 'oneLiner'; var has_content = false out += '{' for (var key in o) { if (o.hasOwnProperty(key)) { var compiled = handleVar(o[key], tabs+1) if (compiled) { if (has_content) {out += ',' + (breaks || options.small?'':' ')} if (breaks) {out += newLine(tabs)} out += '"' + key + '":' + (options.small === true ? '' : ' ') out += compiled has_content = true } } } if (breaks && has_content) {out += newLine(tabs-1)} out += '}' } return out; } return handleVar(object, 1) } function autoParseJSON(data, feedback) { if (data.charCodeAt(0) === 0xFEFF) { data = data.substr(1) } try { data = JSON.parse(data) } catch (err1) { data = data.replace(/\/\*[^(\*\/)]*\*\/|\/\/.*/g, '') try { data = JSON.parse(data) } catch (err) { if (feedback === false) return; function logErrantPart(whole, start, length) { var line = whole.substr(0, start).match(/\n/gm) line = line ? line.length+1 : 1 var result = ''; var lines = whole.substr(start, length).split(/\n/gm) lines.forEach((s, i) => { result += `#${line+i} ${s}\n` }) console.log(result.substr(0, result.length-1) + ' <-- HERE') } console.error(err) var length = err.toString().split('at position ')[1] if (length) { length = parseInt(length) var start = limitNumber(length-20, 0, Infinity) logErrantPart(data, start, 1+length-start) } else if (err.toString().includes('Unexpected end of JSON input')) { logErrantPart(data, data.length-10, 10) } Blockbench.showMessageBox({ translateKey: 'invalid_file', icon: 'error', message: tl('message.invalid_file.message', [err]) }) return; } } return data; } BARS.defineActions(function() { new Action({ id: 'new_block_model', icon: 'insert_drive_file', category: 'file', keybind: new Keybind({key: 78, ctrl: true}), click: function () {newProject()} }) new Action({ id: 'new_entity_model', icon: 'pets', category: 'file', keybind: new Keybind({key: 78, ctrl: true, shift: true}), click: function () { newProject(true); showDialog('project_settings'); } }) new Action({ id: 'open_model', icon: 'assessment', category: 'file', keybind: new Keybind({key: 79, ctrl: true}), click: function () { Blockbench.import({ extensions: ['json', 'jem', 'jpm'], type: 'JSON Model' }, function(files) { if (isApp) { addRecentProject({name: pathToName(files[0].path, 'mobs_id'), path: files[0].path}) } loadModel(files[0].content, files[0].path) }) } }) new Action({ id: 'add_model', icon: 'assessment', category: 'file', click: function () { Blockbench.import({ extensions: ['json', 'jem', 'jpm'], type: 'JSON Model' }, function(files) { if (isApp) { addRecentProject({name: pathToName(files[0].path, 'mobs_id'), path: files[0].path}) } loadModel(files[0].content, files[0].path, true) }) } }) new Action({ id: 'extrude_texture', icon: 'eject', category: 'file', click: function () { Blockbench.import({ extensions: ['png'], type: 'PNG Texture', readtype: 'image' }, function(files) { if (files.length) { if (isApp) { new Texture().fromPath(files[0].path).add().fillParticle() } else { new Texture().fromDataURL(files[0].content).add().fillParticle() } showDialog('image_extruder') Extruder.drawImage(isApp ? files[0].path : files[0].content) } }) } }) new Action({ id: 'export_blockmodel', icon: 'insert_drive_file', category: 'file', keybind: new Keybind({key: 83, ctrl: true, shift: true}), condition: function() {return !Blockbench.entity_mode}, click: function () { var content = buildBlockModel() Blockbench.export({ type: 'JSON Model', extensions: ['json'], name: Project.name||'model', startpath: Prop.file_path, content: content }, (path) => { Prop.project_saved = true if (isApp && path) { Prop.file_path = path setProjectTitle(pathToName(Prop.file_path, true)) addRecentProject({name: pathToName(path, true), path: path}) } }) } }) new Action({ id: 'export_entity', icon: 'pets', category: 'file', keybind: new Keybind({key: 83, ctrl: true, shift: true}), condition: function() {return Blockbench.entity_mode}, click: function () { var content = buildEntityModel({raw: true}); Blockbench.export({ type: 'JSON Entity Model', extensions: ['json'], name: Project.name, startpath: Prop.file_path, content: content, custom_writer: writeFileEntity }) } }) new Action({ id: 'export_class_entity', icon: 'free_breakfast', category: 'file', condition: function() {return Blockbench.entity_mode}, click: function () { var content = buildClassModel(); Blockbench.export({ type: 'Java Class', extensions: ['java'], name: Project.name, startpath: Prop.file_path, content: content }) } }) new Action({ id: 'export_optifine_part', icon: 'icon-optifine_file', category: 'file', condition: function() {return !Blockbench.entity_mode}, click: function () { var content = buildJPMModel() Blockbench.export({ type: 'Optifine Part Model', extensions: ['jpm'], name: Project.name, startpath: Prop.file_path, content: content }) } }) new Action({ id: 'export_optifine_full', icon: 'icon-optifine_file', category: 'file', condition: function() {return Blockbench.entity_mode}, click: function () { var content = buildJEMModel() Blockbench.export({ type: 'Optifine Entity Model', extensions: ['jem'], startpath: Prop.file_path, content: content }) } }) new Action({ id: 'export_obj', icon: 'icon-objects', category: 'file', click: function () { Blockbench.export({ type: 'Alias Wavefront', extensions: ['obj'], startpath: Prop.file_path, custom_writer: writeFileObj }) } }) new Action({ id: 'save', icon: 'save', category: 'file', keybind: new Keybind({key: 83, ctrl: true}), click: function () {saveFile();saveTextures();} }) })