121 lines
4.3 KiB
JavaScript
121 lines
4.3 KiB
JavaScript
// renderang_preview.js — Blockbench plugin: PS1-ify the viewport + one-click
|
|
// "walk my model in renderang".
|
|
// Install: Blockbench > File > Plugins > Load Plugin from File > pick this file.
|
|
(function () {
|
|
const RENDERANG_DIR = '/Users/jing/Documents/renderang';
|
|
const RENDERANG_URL = 'http://localhost:8930';
|
|
|
|
let ps1On = false;
|
|
const saved = { pixelRatios: new Map(), canvasCss: new Map() };
|
|
|
|
function eachPreview(fn) {
|
|
try { (Preview.all || []).forEach(fn); } catch (e) {}
|
|
}
|
|
|
|
function patchMaterials(on) {
|
|
// Best-effort: Blockbench cube shaders are custom, but mesh/gltf-style
|
|
// materials accept onBeforeCompile. Failures are silently fine — the
|
|
// pixelation + nearest textures carry most of the look regardless.
|
|
try {
|
|
scene.traverse((obj) => {
|
|
if (!obj.isMesh || !obj.material) return;
|
|
const mats = Array.isArray(obj.material) ? obj.material : [obj.material];
|
|
mats.forEach((m) => {
|
|
if (!m || typeof m.onBeforeCompile === 'undefined') return;
|
|
if (on && !m.userData.__renderang) {
|
|
m.userData.__renderang = true;
|
|
m.onBeforeCompile = (shader) => {
|
|
shader.vertexShader = shader.vertexShader.replace(
|
|
'#include <project_vertex>',
|
|
`#include <project_vertex>
|
|
{
|
|
vec2 grid = vec2(160.0, 120.0);
|
|
vec2 ndc = gl_Position.xy / gl_Position.w;
|
|
gl_Position.xy = (floor(ndc * grid + 0.5) / grid) * gl_Position.w;
|
|
}`);
|
|
};
|
|
m.needsUpdate = true;
|
|
} else if (!on && m.userData.__renderang) {
|
|
delete m.userData.__renderang;
|
|
m.onBeforeCompile = () => {};
|
|
m.needsUpdate = true;
|
|
}
|
|
});
|
|
});
|
|
} catch (e) { console.warn('renderang: material patch skipped', e); }
|
|
}
|
|
|
|
function setPS1(on) {
|
|
ps1On = on;
|
|
eachPreview((p) => {
|
|
try {
|
|
const r = p.renderer;
|
|
if (on) {
|
|
if (!saved.pixelRatios.has(p)) saved.pixelRatios.set(p, r.getPixelRatio());
|
|
r.setPixelRatio(0.28);
|
|
saved.canvasCss.set(p, p.canvas.style.imageRendering);
|
|
p.canvas.style.imageRendering = 'pixelated';
|
|
} else {
|
|
r.setPixelRatio(saved.pixelRatios.get(p) || window.devicePixelRatio);
|
|
p.canvas.style.imageRendering = saved.canvasCss.get(p) || '';
|
|
}
|
|
} catch (e) {}
|
|
});
|
|
patchMaterials(on);
|
|
try { Canvas.updateAll(); } catch (e) {}
|
|
Blockbench.showQuickMessage(on ? 'PS1 preview ON' : 'PS1 preview OFF', 1200);
|
|
}
|
|
|
|
async function openInRenderang() {
|
|
try {
|
|
const codec = Codecs.gltf;
|
|
if (!codec) throw new Error('gltf codec not found');
|
|
const content = await codec.compile({ binary: true });
|
|
const dest = RENDERANG_DIR + '/assets/preview.glb';
|
|
if (typeof require === 'function') {
|
|
require('fs').writeFileSync(dest, Buffer.from(content));
|
|
Blockbench.showQuickMessage('sent to renderang', 1500);
|
|
Blockbench.openLink(RENDERANG_URL + '/?model=preview.glb');
|
|
} else {
|
|
// web app fallback: download, user drops it into renderang/assets
|
|
Blockbench.export({
|
|
resource_id: 'gltf', type: 'GLB model', extensions: ['glb'],
|
|
name: 'preview', savetype: 'binary', content,
|
|
});
|
|
}
|
|
} catch (e) {
|
|
Blockbench.showQuickMessage('renderang export failed: ' + e.message, 3000);
|
|
console.error(e);
|
|
}
|
|
}
|
|
|
|
let togglePS1, sendAction;
|
|
Plugin.register('renderang_preview', {
|
|
title: 'renderang preview',
|
|
author: 'MonsterRobot',
|
|
description: 'PS1-ify the viewport, and open the current model walking in renderang.',
|
|
icon: 'videogame_asset',
|
|
version: '0.1.0',
|
|
variant: 'both',
|
|
onload() {
|
|
togglePS1 = new Action('renderang_ps1_toggle', {
|
|
name: 'PS1 Preview',
|
|
icon: 'tv',
|
|
click: () => setPS1(!ps1On),
|
|
});
|
|
sendAction = new Action('renderang_send', {
|
|
name: 'Open in renderang',
|
|
icon: 'videogame_asset',
|
|
click: openInRenderang,
|
|
});
|
|
MenuBar.addAction(togglePS1, 'view');
|
|
MenuBar.addAction(sendAction, 'file.export');
|
|
},
|
|
onunload() {
|
|
if (ps1On) setPS1(false);
|
|
togglePS1 && togglePS1.delete();
|
|
sendAction && sendAction.delete();
|
|
},
|
|
});
|
|
})();
|