MorphGuard / static /js /workers /draco_worker.js
juanquy's picture
Initial clean commit of modular MorphGuard
2978bba
Raw
History Blame Contribute Delete
8.62 kB
/**
* Web Worker for Draco mesh decompression preprocessing
* Prepares Draco data for GPU processing and provides CPU fallback
*/
// Import Draco decoder (would be loaded in a real implementation)
// importScripts('/static/js/libs/draco_decoder.js');
let decoderModule;
let decoder;
let attributeIdsMap;
// Handle messages from the main thread
self.addEventListener('message', async function(e) {
const { type, buffer } = e.data;
try {
switch (type) {
case 'initialize':
await initDecoder();
self.postMessage({ type: 'initialized' });
break;
case 'prepare':
const preparedData = await prepareDracoData(buffer);
self.postMessage({ type: 'prepared', result: preparedData }, [
preparedData.indices.buffer,
preparedData.positionData?.buffer,
preparedData.normalData?.buffer,
preparedData.uvData?.buffer
].filter(Boolean));
break;
case 'decompress':
const decompressedData = await decompressDraco(buffer);
self.postMessage({ type: 'decompressed', result: decompressedData }, [
decompressedData.indices.buffer,
decompressedData.positions.buffer,
decompressedData.normals?.buffer,
decompressedData.uvs?.buffer
].filter(Boolean));
break;
default:
throw new Error(`Unknown command: ${type}`);
}
} catch (error) {
self.postMessage({ type: 'error', result: { message: error.message } });
}
});
/**
* Initialize the Draco decoder
*/
async function initDecoder() {
// In a real implementation, this would load the Draco decoder wasm module
// Here we're simulating the module API for demonstration
// Define attribute ID constants to match Draco's internal values
attributeIdsMap = {
POSITION: 0,
NORMAL: 1,
COLOR: 2,
TEX_COORD: 3,
GENERIC: 4
};
// Create mock decoder API
decoderModule = {
decoder: function() {
return {
GetEncodedGeometryType: function() { return 1; }, // 1 = triangular mesh
DecodeBufferToMesh: function() { return { ptr: 123 }; }, // Mock mesh pointer
GetAttribute: function() { return { ptr: 456 }; }, // Mock attribute pointer
GetAttributeByType: function() { return { ptr: 456 }; }, // Mock attribute pointer
GetFaceFromMesh: function() { return true; },
GetAttributeFloat: function() { return 0.0; },
GetAttributeIntForAllPoints: function() { return true; },
GetAttributeFloatForAllPoints: function() { return true; },
GetNumberOfFaces: function() { return 100; }, // Mock face count
GetNumberOfPoints: function() { return 300; }, // Mock point count
GetAttributeId: function() { return 0; },
GetNumberOfComponents: function() { return 3; },
GetPointMapSize: function() { return 300; }, // Mock point map size
GetPointToPointMap: function() { return 0; }
};
},
destroy: function() {}
};
decoder = decoderModule.decoder();
}
/**
* Prepare Draco data for GPU processing
* Extracts quantized attributes and metadata for GPU decompression
* @param {ArrayBuffer} dracoData - Draco-encoded mesh data
* @returns {Object} - Prepared data for GPU processing
*/
async function prepareDracoData(dracoData) {
// Ensure decoder is initialized
if (!decoder) {
await initDecoder();
}
try {
// This code simulates the data preparation process
// In a real implementation, this would use the actual Draco API
// In a real implementation, decode enough information for GPU processing
// This is a simplified version for demonstration
// Create a buffer view
const dataView = new DataView(dracoData);
// Parse simple header information (placeholder values)
const vertexCount = 1000;
const indexCount = 2994; // Assuming triangles, so multiple of 3
// Create buffers to hold the quantized data for GPU processing
const positionData = new Float32Array(vertexCount * 4); // RGBA format for textures
const normalData = new Float32Array(vertexCount * 4);
const uvData = new Float32Array(vertexCount * 4);
const indices = new Uint32Array(indexCount);
// In a real implementation, Draco methods would extract quantized data
// Fill buffers with placeholder data for demonstration
for (let i = 0; i < vertexCount; i++) {
// Quantized positions (simulated)
positionData[i * 4] = Math.random(); // Quantized X
positionData[i * 4 + 1] = Math.random(); // Quantized Y
positionData[i * 4 + 2] = Math.random(); // Quantized Z
positionData[i * 4 + 3] = 0; // Padding for RGBA texture
// Octahedral encoded normals (simulated)
normalData[i * 4] = Math.random(); // Octahedral X
normalData[i * 4 + 1] = Math.random(); // Octahedral Y
normalData[i * 4 + 2] = 0; // Padding
normalData[i * 4 + 3] = 0; // Padding
// Quantized UVs (simulated)
uvData[i * 4] = Math.random(); // Quantized U
uvData[i * 4 + 1] = Math.random(); // Quantized V
uvData[i * 4 + 2] = 0; // Padding
uvData[i * 4 + 3] = 0; // Padding
}
// Create mesh indices (simulated)
for (let i = 0; i < indexCount; i += 3) {
indices[i] = Math.floor(Math.random() * vertexCount);
indices[i + 1] = Math.floor(Math.random() * vertexCount);
indices[i + 2] = Math.floor(Math.random() * vertexCount);
}
// Dequantization information (simulated)
const positionDequantizationFactors = [10, 10, 10]; // Scale factors for x, y, z
const positionOffset = [0, 0, 0]; // Offset for positions
const uvFactors = [1, 1]; // Scale factors for u, v
return {
vertexCount,
indexCount,
positionData,
normalData,
uvData,
indices,
positionDequantizationFactors,
positionOffset,
uvFactors
};
} catch (error) {
console.error('Error preparing Draco data:', error);
throw error;
}
}
/**
* Decompress Draco mesh data using CPU (fallback method)
* @param {ArrayBuffer} dracoData - Draco-encoded mesh data
* @returns {Object} - Decompressed mesh data
*/
async function decompressDraco(dracoData) {
// Ensure decoder is initialized
if (!decoder) {
await initDecoder();
}
try {
// This code simulates the CPU decompression process
// In a real implementation, this would use the actual Draco API
// In a real implementation, use the Draco decoder to extract mesh data
// This is a simplified version for demonstration
// Create a buffer view
const dataView = new DataView(dracoData);
// Parse header information (placeholder values)
const vertexCount = 1000;
const indexCount = 2994; // Assuming triangles, so multiple of 3
// Create buffers to hold the decompressed data
const positions = new Float32Array(vertexCount * 3);
const normals = new Float32Array(vertexCount * 3);
const uvs = new Float32Array(vertexCount * 2);
const indices = new Uint32Array(indexCount);
// In a real implementation, Draco methods would extract geometry data
// Fill buffers with placeholder data for demonstration
for (let i = 0; i < vertexCount; i++) {
// Positions
positions[i * 3] = (Math.random() * 2 - 1) * 5; // X
positions[i * 3 + 1] = (Math.random() * 2 - 1) * 5; // Y
positions[i * 3 + 2] = (Math.random() * 2 - 1) * 5; // Z
// Normals
const nx = Math.random() * 2 - 1;
const ny = Math.random() * 2 - 1;
const nz = Math.random() * 2 - 1;
const len = Math.sqrt(nx*nx + ny*ny + nz*nz);
normals[i * 3] = nx / len; // Normalized X
normals[i * 3 + 1] = ny / len; // Normalized Y
normals[i * 3 + 2] = nz / len; // Normalized Z
// UVs
uvs[i * 2] = Math.random(); // U
uvs[i * 2 + 1] = Math.random(); // V
}
// Create mesh indices (simulated)
for (let i = 0; i < indexCount; i += 3) {
indices[i] = Math.floor(Math.random() * vertexCount);
indices[i + 1] = Math.floor(Math.random() * vertexCount);
indices[i + 2] = Math.floor(Math.random() * vertexCount);
}
return {
vertexCount,
indexCount,
positions,
normals,
uvs,
indices
};
} catch (error) {
console.error('Error decompressing Draco data:', error);
throw error;
}
}