perf: Optimize STL chunk transfer to 1 MB and primitive spatial hashing for instant auto-loading
This commit is contained in:
+1
-1
@@ -30,7 +30,7 @@ const modelInput=$('#model-input'),modelButton=$('#load-model');
|
||||
modelButton.onclick=()=>{modelInput.value='';modelInput.click()};
|
||||
function bytesToBase64(bytes){let value='';for(let i=0;i<bytes.length;i+=0x8000)value+=String.fromCharCode(...bytes.subarray(i,i+0x8000));return btoa(value)}
|
||||
async function cacheModel(file){const token=await api('begin_model_save',file.name,file.size),chunk=196608;for(let offset=0;offset<file.size;offset+=chunk){const bytes=new Uint8Array(await file.slice(offset,offset+chunk).arrayBuffer());await api('append_model_chunk',token,bytesToBase64(bytes));if(offset% (chunk*4)===0)await new Promise(requestAnimationFrame)}await api('finish_model_save',token)}
|
||||
async function loadCachedModel(info){const bytes=new Uint8Array(info.size),chunk=196608;for(let offset=0;offset<info.size;offset+=chunk){const response=await api('read_saved_model_chunk',offset,chunk),part=atob(response.data);for(let i=0;i<part.length;i++)bytes[offset+i]=part.charCodeAt(i);if(offset%(chunk*4)===0)await new Promise(requestAnimationFrame)}return window.rovModel.loadBuffer(bytes.buffer,info.name)}
|
||||
async function loadCachedModel(info){const bytes=new Uint8Array(info.size),chunk=1048576;for(let offset=0;offset<info.size;offset+=chunk){const response=await api('read_saved_model_chunk',offset,chunk),part=atob(response.data);for(let i=0;i<part.length;i++)bytes[offset+i]=part.charCodeAt(i);if(offset%(chunk*4)===0)await new Promise(requestAnimationFrame)}return window.rovModel.loadBuffer(bytes.buffer,info.name)}
|
||||
modelInput.onchange=async()=>{const file=modelInput.files?.[0],old=modelButton.textContent;if(!file)return;try{if(!file.name.toLowerCase().endsWith('.stl'))throw new Error('Choose an STL mesh');if(file.size>30*1024*1024)throw new Error('The STL is larger than 30 MB; export a lighter mesh');modelButton.disabled=true;modelButton.textContent='Loading…';await new Promise(requestAnimationFrame);const buffer=await file.arrayBuffer(),result=window.rovModel.loadBuffer(buffer,file.name);modelButton.textContent='Replace STL';toast(`Loaded ${result.name} • ${result.triangles.toLocaleString()} triangles`);if(bridgeReady)cacheModel(file).then(()=>toast('STL saved for the next launch')).catch(error=>toast(`Model loaded, but could not be saved: ${error.message}`,true))}catch(error){toast(`STL import failed: ${error.message}`,true)}finally{modelButton.disabled=false;if(modelButton.textContent==='Loading…')modelButton.textContent=old}};
|
||||
$('#refresh').onclick=async()=>populatePorts(await api('refresh_ports'));$('#connect').onclick=async()=>{try{if(connected)await api('disconnect');else await api('connect',$('#port').value,+$('#baud').value,+$('#rate').value)}catch(e){toast(e.message,true)}};
|
||||
$('#manual').onclick=()=>api('command','manual').catch(e=>toast(e.message,true));$('#arm').onclick=()=>openModal('arm-dialog');$('#confirm-arm').onclick=()=>{api('command','arm').catch(e=>toast(e.message,true));$('#arm-dialog').close()};$('#disarm').onclick=()=>api('command','disarm').catch(e=>toast(e.message,true));$('#logs').onclick=()=>api('open_logs');
|
||||
|
||||
+2
-1
@@ -283,7 +283,8 @@
|
||||
const numTriangles = Math.floor(rawTriangles.length / 9);
|
||||
const posMap = new Map();
|
||||
const getVertexIndex = (x, y, z) => {
|
||||
const key = `${Math.round(x * 10000)},${Math.round(y * 10000)},${Math.round(z * 10000)}`;
|
||||
const ix = (x * 2000) | 0, iy = (y * 2000) | 0, iz = (z * 2000) | 0;
|
||||
const key = (ix * 73856093 ^ iy * 19349663 ^ iz * 83492791) >>> 0;
|
||||
let idx = posMap.get(key);
|
||||
if (idx === undefined) {
|
||||
idx = posMap.size;
|
||||
|
||||
Reference in New Issue
Block a user