mirror of
https://github.com/JannisX11/blockbench.git
synced 2024-12-03 04:40:46 +08:00
66f7ec2b44
Improve array export of JSON compiler Stop texture animations playing when switching tab Fix duplicate keybinding from add mesh button Improve transform space normal calculation Fix interface issues Add "Instance" property type
692 lines
20 KiB
JavaScript
692 lines
20 KiB
JavaScript
//Import
|
|
function setupDragHandlers() {
|
|
Blockbench.addDragHandler(
|
|
'model',
|
|
{extensions: Codec.getAllExtensions},
|
|
function(files) {
|
|
files.forEach(file => {
|
|
loadModelFile(file);
|
|
})
|
|
}
|
|
)
|
|
Blockbench.addDragHandler(
|
|
'style',
|
|
{extensions: ['bbtheme']},
|
|
function(files) {
|
|
CustomTheme.import(files[0]);
|
|
}
|
|
)
|
|
Blockbench.addDragHandler(
|
|
'settings',
|
|
{extensions: ['bbsettings']},
|
|
function(files) {
|
|
Settings.import(files[0]);
|
|
}
|
|
)
|
|
Blockbench.addDragHandler(
|
|
'plugin',
|
|
{extensions: ['bbplugin', 'js']},
|
|
function(files) {
|
|
files.forEach(file => {
|
|
new Plugin().loadFromFile(file, true);
|
|
})
|
|
}
|
|
)
|
|
Blockbench.addDragHandler(
|
|
'texture',
|
|
{extensions: ['png', 'tga'], propagate: true, readtype: 'image'},
|
|
function(files, event) {
|
|
var texture_li = $(event.target).parents('li.texture')
|
|
if (texture_li.length) {
|
|
var tex = Texture.all.findInArray('uuid', texture_li.attr('texid'))
|
|
if (tex) {
|
|
tex.fromFile(files[0])
|
|
TickUpdates.selection = true;
|
|
return;
|
|
}
|
|
}
|
|
files.forEach(function(f) {
|
|
new Texture().fromFile(f).add().fillParticle()
|
|
})
|
|
}
|
|
)
|
|
}
|
|
|
|
function loadModelFile(file) {
|
|
|
|
let existing_tab = isApp && ModelProject.all.find(project => (
|
|
project.save_path == file.path || project.export_path == file.path
|
|
))
|
|
if (existing_tab) {
|
|
existing_tab.select();
|
|
return;
|
|
}
|
|
|
|
let extension = pathToExtension(file.path);
|
|
// Text
|
|
for (let id in Codecs) {
|
|
let codec = Codecs[id];
|
|
if (codec.load_filter && codec.load_filter.type == 'text') {
|
|
if (codec.load_filter.extensions.includes(extension) && Condition(codec.load_filter.condition, file.content)) {
|
|
codec.load(file.content, file);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// JSON
|
|
let model = autoParseJSON(file.content);
|
|
for (let id in Codecs) {
|
|
let codec = Codecs[id];
|
|
if (codec.load_filter && codec.load_filter.type == 'json') {
|
|
if (codec.load_filter.extensions.includes(extension) && Condition(codec.load_filter.condition, model)) {
|
|
codec.load(model, file);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Extruder
|
|
var Extruder = {
|
|
drawImage: function(file) {
|
|
Extruder.canvas = $('#extrusion_canvas').get(0)
|
|
var ctx = Extruder.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 = isApp ? file.path.replace(/#/g, '%23') : file.content
|
|
Extruder.image_file = file
|
|
Extruder.ext_img.style.imageRendering = 'pixelated'
|
|
Extruder.canvas.style.imageRendering = 'pixelated'
|
|
|
|
Extruder.ext_img.onload = function() {
|
|
let ratio = Extruder.ext_img.naturalWidth / Extruder.ext_img.naturalHeight;
|
|
Extruder.canvas.width = 256;
|
|
Extruder.canvas.height = 256 / ratio;
|
|
ctx.clearRect(0, 0, Extruder.canvas.width, Extruder.canvas.height);
|
|
ctx.imageSmoothingEnabled = false;
|
|
ctx.drawImage(Extruder.ext_img, 0, 0, Extruder.canvas.width, Extruder.canvas.height);
|
|
Extruder.width = Extruder.ext_img.naturalWidth;
|
|
Extruder.height = Extruder.ext_img.naturalHeight;
|
|
|
|
if (Extruder.width > 128) return;
|
|
|
|
var p = 0
|
|
ctx.beginPath();
|
|
|
|
for (var x = 0; x < Extruder.canvas.width; x += 256 / Extruder.width) {
|
|
ctx.moveTo(0.5 + x + p, p);
|
|
ctx.lineTo(0.5 + x + p, 256 + p);
|
|
}
|
|
for (var x = 0; x < Extruder.canvas.height; x += 256 / Extruder.width) {
|
|
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 isNewProject = elements.length === 0;
|
|
|
|
var pixel_opacity_tolerance = parseInt($('#scan_tolerance').val())
|
|
|
|
|
|
//Undo
|
|
Undo.initEdit({elements: selected, outliner: true, textures: []})
|
|
var texture = new Texture().fromFile(Extruder.image_file).add(false).fillParticle()
|
|
|
|
//var ext_x, ext_y;
|
|
var ctx = Painter.getCanvas(texture).getContext('2d')
|
|
|
|
var c = document.createElement('canvas')
|
|
var ctx = c.getContext('2d');
|
|
c.width = Extruder.ext_img.naturalWidth;
|
|
c.height = Extruder.ext_img.naturalHeight;
|
|
ctx.drawImage(Extruder.ext_img, 0, 0)
|
|
var image_data = ctx.getImageData(0, 0, c.width, c.height).data
|
|
|
|
var finished_pixels = {}
|
|
var cube_nr = 0;
|
|
var cube_name = texture.name.split('.')[0]
|
|
selected.empty()
|
|
|
|
//Scale Index
|
|
var scale_i = 1;
|
|
scale_i = 16 / Extruder.width;
|
|
let uv_scale_x = Project.texture_width / Extruder.width;
|
|
let uv_scale_y = Project.texture_height / Extruder.height;
|
|
|
|
function isOpaquePixel(px_x, px_y) {
|
|
var opacity = image_data[(px_x + ctx.canvas.width * px_y) * 4 + 3]
|
|
return Math.isBetween(px_x, 0, Extruder.width-1)
|
|
&& Math.isBetween(px_y, 0, Extruder.height-1)
|
|
&& opacity >= 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,
|
|
from: [rect.x*scale_i, 0, rect.y*scale_i],
|
|
to: [(rect.x2+1)*scale_i, scale_i, (rect.y2+1)*scale_i],
|
|
faces: {
|
|
up: {uv:[rect.x*uv_scale_x, rect.y*uv_scale_y, (rect.x2+1)*uv_scale_x, (rect.y2+1)*uv_scale_y], texture: texture},
|
|
down: {uv:[rect.x*uv_scale_x, (rect.y2+1)*uv_scale_y, (rect.x2+1)*uv_scale_x, rect.y*uv_scale_y], texture: texture},
|
|
north: {uv:[(rect.x2+1)*uv_scale_x, rect.y*uv_scale_y, rect.x*uv_scale_x, (rect.y+1)*uv_scale_y], texture: texture},
|
|
south: {uv:[rect.x*uv_scale_x, rect.y2*uv_scale_y, (rect.x2+1)*uv_scale_x, (rect.y2+1)*uv_scale_y], texture: texture},
|
|
east: {uv:[rect.x2*uv_scale_x, rect.y*uv_scale_y, (rect.x2+1)*uv_scale_x, (rect.y2+1)*uv_scale_y], texture: texture, rotation: 90},
|
|
west: {uv:[rect.x*uv_scale_x, rect.y*uv_scale_y, (rect.x+1)*uv_scale_x, (rect.y2+1)*uv_scale_y], texture: texture, rotation: 270},
|
|
}
|
|
}).init()
|
|
selected.push(current_cube)
|
|
cube_nr++;
|
|
}
|
|
|
|
ext_x++;
|
|
}
|
|
ext_y++;
|
|
}
|
|
|
|
var group = new Group(cube_name).init().addTo()
|
|
selected.forEach(function(s) {
|
|
s.addTo(group).init()
|
|
})
|
|
|
|
Undo.finishEdit('Add extruded texture', {elements: selected, outliner: true, textures: [Texture.all[Texture.all.length-1]]})
|
|
|
|
hideDialog()
|
|
}
|
|
}
|
|
//Export
|
|
function uploadSketchfabModel() {
|
|
if (elements.length === 0) {
|
|
return;
|
|
}
|
|
var dialog = new Dialog({
|
|
id: 'sketchfab_uploader',
|
|
title: 'dialog.sketchfab_uploader.title',
|
|
width: 540,
|
|
form: {
|
|
token: {label: 'dialog.sketchfab_uploader.token', value: settings.sketchfab_token.value, type: 'password'},
|
|
about_token: {type: 'info', text: tl('dialog.sketchfab_uploader.about_token', ['[sketchfab.com/settings/password](https://sketchfab.com/settings/password)'])},
|
|
name: {label: 'dialog.sketchfab_uploader.name'},
|
|
description: {label: 'dialog.sketchfab_uploader.description', type: 'textarea'},
|
|
tags: {label: 'dialog.sketchfab_uploader.tags', placeholder: 'Tag1 Tag2'},
|
|
animations: {label: 'dialog.sketchfab_uploader.animations', value: true, type: 'checkbox', condition: (Format.animation_mode && Animator.animations.length)},
|
|
//color: {type: 'color', label: 'dialog.sketchfab_uploader.color'},
|
|
draft: {label: 'dialog.sketchfab_uploader.draft', type: 'checkbox'},
|
|
// Category
|
|
divider: '_',
|
|
private: {label: 'dialog.sketchfab_uploader.private', type: 'checkbox'},
|
|
password: {label: 'dialog.sketchfab_uploader.password'},
|
|
},
|
|
onConfirm: function(formResult) {
|
|
|
|
if (formResult.token && !formResult.name) {
|
|
Blockbench.showQuickMessage('message.sketchfab.name_or_token', 1800)
|
|
return;
|
|
}
|
|
if (!formResult.tags.split(' ').includes('blockbench')) {
|
|
formResult.tags += ' blockbench';
|
|
}
|
|
var data = new FormData()
|
|
data.append('token', formResult.token)
|
|
data.append('name', formResult.name)
|
|
data.append('description', formResult.description)
|
|
data.append('tags', formResult.tags)
|
|
data.append('isPublished', !formResult.draft)
|
|
//data.append('background', JSON.stringify({color: formResult.color.toHexString()}))
|
|
data.append('private', formResult.private)
|
|
data.append('password', formResult.password)
|
|
data.append('source', 'blockbench')
|
|
|
|
settings.sketchfab_token.value = formResult.token
|
|
|
|
Codecs.gltf.compile({animations: formResult.animations}, (content) => {
|
|
|
|
var blob = new Blob([content], {type: "text/plain;charset=utf-8"});
|
|
var file = new File([blob], 'model.gltf')
|
|
|
|
data.append('modelFile', file)
|
|
|
|
$.ajax({
|
|
url: 'https://api.sketchfab.com/v3/models',
|
|
data: data,
|
|
cache: false,
|
|
contentType: false,
|
|
processData: false,
|
|
type: 'POST',
|
|
success: function(response) {
|
|
Blockbench.showMessageBox({
|
|
title: tl('message.sketchfab.success'),
|
|
message:
|
|
`[${formResult.name} on Sketchfab](https://sketchfab.com/models/${response.uid})`, //\n\n \n\n`+
|
|
icon: 'icon-sketchfab',
|
|
})
|
|
},
|
|
error: function(response) {
|
|
Blockbench.showQuickMessage('message.sketchfab.error', 1500)
|
|
console.error(response);
|
|
}
|
|
})
|
|
})
|
|
|
|
dialog.hide()
|
|
}
|
|
})
|
|
dialog.show()
|
|
}
|
|
//Json
|
|
function compileJSON(object, options) {
|
|
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 escape(string) {
|
|
return string.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n|\r\n/g, '\\n').replace(/\t/g, '\\t')
|
|
}
|
|
function handleVar(o, tabs) {
|
|
var out = ''
|
|
if (typeof o === 'string') {
|
|
//String
|
|
out += '"' + escape(o) + '"'
|
|
} else if (typeof o === 'boolean') {
|
|
//Boolean
|
|
out += (o ? 'true' : 'false')
|
|
} else if (o === null || o === Infinity || o === -Infinity) {
|
|
//Null
|
|
out += 'null'
|
|
} else if (typeof o === 'number') {
|
|
//Number
|
|
o = (Math.round(o*100000)/100000).toString()
|
|
out += o
|
|
} else if (o instanceof Array) {
|
|
//Array
|
|
let has_content = false
|
|
let has_objects = !!o.find(item => typeof item === 'object');
|
|
out += '['
|
|
for (var i = 0; i < o.length; i++) {
|
|
var compiled = handleVar(o[i], tabs+1)
|
|
if (compiled) {
|
|
if (has_content) {out += ',' + (breaks || options.small?'':' ')}
|
|
if (has_objects) {out += newLine(tabs)}
|
|
out += compiled
|
|
has_content = true
|
|
}
|
|
}
|
|
if (has_objects) {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 += '"' + escape(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.substr(0, 4) === '<lz>') {
|
|
data = LZUTF8.decompress(data.substr(4), {inputEncoding: 'StorageBinaryString'})
|
|
}
|
|
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() {
|
|
//Import
|
|
new Action('open_model', {
|
|
icon: 'assessment',
|
|
category: 'file',
|
|
keybind: new Keybind({key: 'o', ctrl: true}),
|
|
click: function () {
|
|
var startpath;
|
|
if (isApp && recent_projects && recent_projects.length) {
|
|
startpath = recent_projects[0].path;
|
|
if (typeof startpath == 'string') {
|
|
startpath = startpath.split(osfs);
|
|
startpath.pop();
|
|
startpath = startpath.join(osfs);
|
|
}
|
|
}
|
|
Blockbench.import({
|
|
resource_id: 'model',
|
|
extensions: Codec.getAllExtensions(),
|
|
type: 'Model',
|
|
startpath,
|
|
multiple: true
|
|
}, function(files) {
|
|
files.forEach(file => {
|
|
loadModelFile(file);
|
|
})
|
|
})
|
|
}
|
|
})
|
|
new Action('open_from_link', {
|
|
icon: 'link',
|
|
category: 'file',
|
|
click() {
|
|
Blockbench.textPrompt('action.open_from_link', '', link => {
|
|
if (link.match(/https:\/\/blckbn.ch\//) || link.length == 4) {
|
|
let code = link.replace(/[/]+/g, '').substr(-4);
|
|
$.getJSON(`https://blckbn.ch/api/models/${code}`, (model) => {
|
|
Codecs.project.load(model, {path: ''});
|
|
}).fail(error => {
|
|
Blockbench.showQuickMessage('message.invalid_link')
|
|
})
|
|
} else {
|
|
$.getJSON(link, (model) => {
|
|
Codecs.project.load(model, {path: ''});
|
|
}).fail(error => {
|
|
Blockbench.showQuickMessage('message.invalid_link')
|
|
})
|
|
}
|
|
}, 'https://blckbn.ch/1234')
|
|
}
|
|
})
|
|
new Action('extrude_texture', {
|
|
icon: 'eject',
|
|
category: 'file',
|
|
condition: _ => Format && !Project.box_uv,
|
|
click: function () {
|
|
Blockbench.import({
|
|
resource_id: 'texture',
|
|
extensions: ['png'],
|
|
type: 'PNG Texture',
|
|
readtype: 'image'
|
|
}, function(files) {
|
|
if (files.length) {
|
|
showDialog('image_extruder')
|
|
Extruder.drawImage(files[0])
|
|
}
|
|
})
|
|
}
|
|
})
|
|
//Export
|
|
new Action('export_over', {
|
|
icon: 'save',
|
|
category: 'file',
|
|
keybind: new Keybind({key: 's', ctrl: true}),
|
|
click: function () {
|
|
if (isApp) {
|
|
saveTextures()
|
|
if (Format) {
|
|
if (Project.export_path && Format.codec && Format.codec.compile) {
|
|
Format.codec.write(Format.codec.compile(), Project.export_path)
|
|
} else if (Project.save_path) {
|
|
Codecs.project.write(Codecs.project.compile(), Project.save_path);
|
|
} else if (Format.codec && Format.codec.export) {
|
|
Format.codec.export()
|
|
} else {
|
|
Project.saved = true;
|
|
}
|
|
}
|
|
if (Format.animation_mode && Format.animation_files && Animation.all.length) {
|
|
BarItems.save_all_animations.trigger();
|
|
}
|
|
} else {
|
|
saveTextures()
|
|
if (Format.codec && Format.codec.export) {
|
|
Format.codec.export()
|
|
}
|
|
}
|
|
}
|
|
})
|
|
if (!isApp) {
|
|
new Action('export_asset_archive', {
|
|
icon: 'archive',
|
|
category: 'file',
|
|
condition: _ => Format && Format.codec,
|
|
click: function() {
|
|
var archive = new JSZip();
|
|
var content = Format.codec.compile()
|
|
var name = `${Format.codec.fileName()}.${Format.codec.extension}`
|
|
archive.file(name, content)
|
|
Texture.all.forEach(tex => {
|
|
if (tex.mode === 'bitmap') {
|
|
archive.file(pathToName(tex.name) + '.png', tex.source.replace('data:image/png;base64,', ''), {base64: true});
|
|
}
|
|
})
|
|
archive.generateAsync({type: 'blob'}).then(content => {
|
|
Blockbench.export({
|
|
type: 'Zip Archive',
|
|
extensions: ['zip'],
|
|
name: 'assets',
|
|
startpath: Project.export_path,
|
|
content: content,
|
|
savetype: 'zip'
|
|
})
|
|
Project.saved = true;
|
|
})
|
|
}
|
|
})
|
|
}
|
|
new Action('upload_sketchfab', {
|
|
icon: 'icon-sketchfab',
|
|
category: 'file',
|
|
click: function(ev) {
|
|
uploadSketchfabModel()
|
|
}
|
|
})
|
|
|
|
|
|
new Action('share_model', {
|
|
icon: 'share',
|
|
condition: () => Cube.all.length,
|
|
click() {
|
|
var dialog = new Dialog({
|
|
id: 'share_model',
|
|
title: 'dialog.share_model.title',
|
|
form: {
|
|
expire_time: {label: 'dialog.share_model.expire_time', type: 'select', default: '2d', options: {
|
|
'10m': tl('dates.minutes', [10]),
|
|
'1h': tl('dates.hour', [1]),
|
|
'1d': tl('dates.day', [1]),
|
|
'2d': tl('dates.days', [2]),
|
|
'1w': tl('dates.week', [1]),
|
|
'2w': tl('dates.weeks', [2]),
|
|
}},
|
|
info: {type: 'info', text: 'The model will be stored on the Blockbench servers for the duration specified above. [Learn more](https://blockbench.net/blockbench-model-sharing-service/)'}
|
|
},
|
|
buttons: ['generic.share', 'dialog.cancel'],
|
|
onConfirm: function(formResult) {
|
|
|
|
let expire_time = formResult.expire_time;
|
|
let model = Codecs.project.compile({compressed: false});
|
|
|
|
$.ajax({
|
|
url: 'https://blckbn.ch/api/model',
|
|
data: JSON.stringify({ expire_time, model }),
|
|
cache: false,
|
|
contentType: 'application/json; charset=utf-8',
|
|
dataType: 'json',
|
|
type: 'POST',
|
|
success: function(response) {
|
|
let link = `https://blckbn.ch/${response.id}`
|
|
|
|
let link_dialog = new Dialog({
|
|
id: 'share_model_link',
|
|
title: 'dialog.share_model.title',
|
|
form: {
|
|
link: {type: 'text', value: link}
|
|
},
|
|
buttons: ['action.copy', 'dialog.close'],
|
|
onConfirm() {
|
|
link_dialog.hide();
|
|
if (isApp || navigator.clipboard) {
|
|
Clipbench.setText(link);
|
|
Blockbench.showQuickMessage('dialog.share_model.copied_to_clipboard');
|
|
} else {
|
|
Blockbench.showMessageBox({
|
|
title: 'dialog.share_model.title',
|
|
message: `[${link}](${link})`,
|
|
})
|
|
}
|
|
}
|
|
}).show();
|
|
|
|
},
|
|
error: function(response) {
|
|
Blockbench.showQuickMessage('dialog.share_model.failed', 1500)
|
|
console.error(response);
|
|
}
|
|
})
|
|
|
|
dialog.hide()
|
|
}
|
|
})
|
|
dialog.show()
|
|
}
|
|
})
|
|
|
|
|
|
|
|
})
|