mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
optimzie base64
mcp w.i.p.
This commit is contained in:
@@ -36,7 +36,7 @@ sleep 1
|
||||
# remove '\r'
|
||||
sess_id=`cat sess_id.txt | tr -d '\r'`
|
||||
sess_header="mcp-session-id: ${sess_id}"
|
||||
echo $sess_header
|
||||
#echo $sess_header
|
||||
|
||||
curl -v -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
sess_id=`cat sess_id.txt | tr -d '\r'`
|
||||
sess_header="mcp-session-id: ${sess_id}"
|
||||
|
||||
curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json, text/event-stream" \
|
||||
-H "${sess_header}" \
|
||||
-d '{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "tools/call",
|
||||
|
||||
134
src/str-util.cc
134
src/str-util.cc
@@ -5,6 +5,10 @@
|
||||
#include "unicode-xid.hh"
|
||||
#include "common-macros.inc"
|
||||
|
||||
#ifdef __SSE2__
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
namespace tinyusdz {
|
||||
|
||||
std::string buildEscapedAndQuotedStringForUSDA(const std::string &str) {
|
||||
@@ -749,9 +753,12 @@ double atof(const std::string &s) {
|
||||
#pragma clang diagnostic ignored "-Wconversion"
|
||||
#endif
|
||||
|
||||
#ifdef __SSE2__
|
||||
#else
|
||||
static inline bool is_base64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string base64_encode(unsigned char const *bytes_to_encode,
|
||||
unsigned int in_len) {
|
||||
@@ -798,7 +805,133 @@ std::string base64_encode(unsigned char const *bytes_to_encode,
|
||||
return ret;
|
||||
}
|
||||
|
||||
// SSE2-optimized base64 decode implementation
|
||||
#ifdef __SSE2__
|
||||
static std::string base64_decode_sse(std::string const &encoded_string) {
|
||||
const size_t input_len = encoded_string.size();
|
||||
if (input_len == 0) return std::string();
|
||||
|
||||
// Lookup table for base64 decoding (256 entries, -1 for invalid chars)
|
||||
static const int8_t decode_table[256] = {
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
|
||||
52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-2,-1,-1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
|
||||
15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
|
||||
-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
|
||||
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
|
||||
};
|
||||
|
||||
// Calculate output size (remove padding)
|
||||
size_t padding = 0;
|
||||
if (input_len >= 1 && encoded_string[input_len - 1] == '=') padding++;
|
||||
if (input_len >= 2 && encoded_string[input_len - 2] == '=') padding++;
|
||||
|
||||
const size_t output_len = (input_len * 3) / 4 - padding;
|
||||
std::string result;
|
||||
result.reserve(output_len);
|
||||
|
||||
const uint8_t* input = reinterpret_cast<const uint8_t*>(encoded_string.data());
|
||||
size_t input_pos = 0;
|
||||
|
||||
// Process 16 bytes at a time using SSE2
|
||||
while (input_pos + 16 <= input_len) {
|
||||
// Load 16 input bytes
|
||||
__m128i input_chunk = _mm_loadu_si128(reinterpret_cast<const __m128i*>(input + input_pos));
|
||||
|
||||
// Decode using lookup table (split into two 8-byte chunks for table lookup)
|
||||
alignas(16) uint8_t input_bytes[16];
|
||||
_mm_store_si128(reinterpret_cast<__m128i*>(input_bytes), input_chunk);
|
||||
|
||||
alignas(16) int8_t decoded[16];
|
||||
bool valid = true;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
decoded[i] = decode_table[input_bytes[i]];
|
||||
if (decoded[i] < 0 && input_bytes[i] != '=') {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) break; // Fall back to scalar processing for invalid chars
|
||||
|
||||
// Pack groups of 4 decoded bytes into 3 output bytes
|
||||
for (int group = 0; group < 4; group++) {
|
||||
if (input_pos + group * 4 + 3 >= input_len) break;
|
||||
|
||||
int base_idx = group * 4;
|
||||
if (decoded[base_idx] >= 0 && decoded[base_idx + 1] >= 0 &&
|
||||
decoded[base_idx + 2] >= 0 && decoded[base_idx + 3] >= 0) {
|
||||
|
||||
uint32_t combined = (static_cast<uint32_t>(decoded[base_idx]) << 18) |
|
||||
(static_cast<uint32_t>(decoded[base_idx + 1]) << 12) |
|
||||
(static_cast<uint32_t>(decoded[base_idx + 2]) << 6) |
|
||||
static_cast<uint32_t>(decoded[base_idx + 3]);
|
||||
|
||||
result.push_back(static_cast<char>((combined >> 16) & 0xFF));
|
||||
result.push_back(static_cast<char>((combined >> 8) & 0xFF));
|
||||
result.push_back(static_cast<char>(combined & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
input_pos += 16;
|
||||
}
|
||||
|
||||
// Process remaining bytes with scalar code
|
||||
while (input_pos + 4 <= input_len) {
|
||||
uint8_t a = input[input_pos];
|
||||
uint8_t b = input[input_pos + 1];
|
||||
uint8_t c = input[input_pos + 2];
|
||||
uint8_t d = input[input_pos + 3];
|
||||
|
||||
if (a == '=' || b == '=') break;
|
||||
|
||||
int8_t da = decode_table[a];
|
||||
int8_t db = decode_table[b];
|
||||
int8_t dc = decode_table[c];
|
||||
int8_t dd = decode_table[d];
|
||||
|
||||
if (da < 0 || db < 0) break;
|
||||
|
||||
uint32_t combined = (static_cast<uint32_t>(da) << 18) |
|
||||
(static_cast<uint32_t>(db) << 12);
|
||||
|
||||
result.push_back(static_cast<char>((combined >> 16) & 0xFF));
|
||||
|
||||
if (c != '=' && dc >= 0) {
|
||||
combined |= static_cast<uint32_t>(dc) << 6;
|
||||
result.push_back(static_cast<char>((combined >> 8) & 0xFF));
|
||||
|
||||
if (d != '=' && dd >= 0) {
|
||||
combined |= static_cast<uint32_t>(dd);
|
||||
result.push_back(static_cast<char>(combined & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
input_pos += 4;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif // __SSE2__
|
||||
|
||||
// Fallback implementation (original)
|
||||
std::string base64_decode(std::string const &encoded_string) {
|
||||
#ifdef __SSE2__
|
||||
// Use SSE2 optimized version if available
|
||||
return base64_decode_sse(encoded_string);
|
||||
#else
|
||||
// Original scalar implementation
|
||||
int in_len = static_cast<int>(encoded_string.size());
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
@@ -847,6 +980,7 @@ std::string base64_decode(std::string const &encoded_string) {
|
||||
}
|
||||
|
||||
return ret;
|
||||
#endif // __SSE2__
|
||||
}
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
@@ -71,7 +71,7 @@ source_group("Source Files" FILES ${SOURCES})
|
||||
if (EMSCRIPTEN)
|
||||
|
||||
if (TINYUSDZ_WASM_DEMODEV)
|
||||
set(OUTPUT_WASM_DIR ${PROJECT_SOURCE_DIR}/demo/node_modules/tinyusdz/)
|
||||
set(OUTPUT_WASM_DIR ${PROJECT_SOURCE_DIR}/mcp-server/node_modules/tinyusdz/)
|
||||
else()
|
||||
set(OUTPUT_WASM_DIR ${PROJECT_SOURCE_DIR}/js/src/tinyusdz/)
|
||||
endif()
|
||||
|
||||
107
web/demo/main.js
107
web/demo/main.js
@@ -6,6 +6,81 @@ import { GUI } from 'https://cdn.jsdelivr.net/npm/dat.gui@0.7.9/build/dat.gui.mo
|
||||
import { TinyUSDZLoader } from 'tinyusdz/TinyUSDZLoader.js'
|
||||
import { TinyUSDZLoaderUtils } from 'tinyusdz/TinyUSDZLoaderUtils.js'
|
||||
|
||||
// Loading bar elements
|
||||
const loadingContainer = document.createElement('div');
|
||||
loadingContainer.id = 'loading-container';
|
||||
loadingContainer.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
font-family: Arial, sans-serif;
|
||||
color: white;
|
||||
`;
|
||||
|
||||
const loadingText = document.createElement('div');
|
||||
loadingText.id = 'loading-text';
|
||||
loadingText.textContent = 'Loading...';
|
||||
loadingText.style.cssText = `
|
||||
font-size: 24px;
|
||||
margin-bottom: 20px;
|
||||
`;
|
||||
|
||||
const progressBarContainer = document.createElement('div');
|
||||
progressBarContainer.style.cssText = `
|
||||
width: 300px;
|
||||
height: 20px;
|
||||
background: #333;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 10px;
|
||||
`;
|
||||
|
||||
const progressBar = document.createElement('div');
|
||||
progressBar.id = 'progress-bar';
|
||||
progressBar.style.cssText = `
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #4CAF50, #8BC34A);
|
||||
border-radius: 10px;
|
||||
transition: width 0.3s ease;
|
||||
`;
|
||||
|
||||
const progressText = document.createElement('div');
|
||||
progressText.id = 'progress-text';
|
||||
progressText.textContent = '0%';
|
||||
progressText.style.cssText = `
|
||||
font-size: 14px;
|
||||
color: #ccc;
|
||||
`;
|
||||
|
||||
progressBarContainer.appendChild(progressBar);
|
||||
loadingContainer.appendChild(loadingText);
|
||||
loadingContainer.appendChild(progressBarContainer);
|
||||
loadingContainer.appendChild(progressText);
|
||||
document.body.appendChild(loadingContainer);
|
||||
|
||||
// Function to update loading progress
|
||||
function updateLoadingProgress(progress, message = 'Loading...') {
|
||||
loadingText.textContent = message;
|
||||
progressBar.style.width = `${progress}%`;
|
||||
progressText.textContent = `${Math.round(progress)}%`;
|
||||
}
|
||||
|
||||
// Function to hide loading screen
|
||||
function hideLoadingScreen() {
|
||||
loadingContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
|
||||
|
||||
const gui = new GUI();
|
||||
|
||||
let ui_state = {}
|
||||
@@ -17,6 +92,7 @@ ui_state['ambient'] = 0.4;
|
||||
let ambientLight = new THREE.AmbientLight(0x404040, ui_state['ambient']);
|
||||
ui_state['camera_z'] = 3.14; // TODO: Compute best fit from scene's bbox.
|
||||
ui_state['needsMtlUpdate'] = false;
|
||||
ui_state['renderer'] = null;
|
||||
|
||||
|
||||
// Create a parameters object
|
||||
@@ -24,6 +100,7 @@ const params = {
|
||||
envMapIntensity: ui_state['envMapIntensity'],
|
||||
rotationSpeed: ui_state['rot_scale'],
|
||||
camera_z: ui_state['camera_z'],
|
||||
take_screenshot: takeScreenshot
|
||||
};
|
||||
|
||||
// Add controls
|
||||
@@ -38,31 +115,48 @@ gui.add(params, 'camera_z', 0, 20).name('Camera Z').onChange((value) => {
|
||||
gui.add(params, 'rotationSpeed', 0, 10).name('Rotation Speed').onChange((value) => {
|
||||
ui_state['rot_scale'] = value;
|
||||
});
|
||||
gui.add(params, 'take_screenshot').name('Take Screenshot');
|
||||
|
||||
|
||||
function takeScreenshot() {
|
||||
|
||||
const renderer = ui_state['renderer'];
|
||||
const quality = 0.92; // JPEG quality, if you want to use JPEG format
|
||||
|
||||
const img = renderer.domElement.toDataURL('image/jpeg', quality)
|
||||
console.log('Screenshot taken:', img);
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
async function loadScenes() {
|
||||
|
||||
updateLoadingProgress(20, 'Initializing TinyUSDZLoader...');
|
||||
|
||||
const loader = new TinyUSDZLoader();
|
||||
|
||||
// it is recommended to call init() before loadAsync()
|
||||
// (wait loading/compiling wasm module in the early stage))
|
||||
//await loader.init();
|
||||
await loader.init();
|
||||
|
||||
// Use zstd compressed tinyusdz.wasm to save the bandwidth.
|
||||
await loader.init({useZstdCompressedWasm: true});
|
||||
//await loader.init({useZstdCompressedWasm: true});
|
||||
|
||||
const suzanne_filename = "./assets/suzanne-pbr.usda";
|
||||
const texcat_filename = "./assets/texture-cat-plane.usdz";
|
||||
const cookie_filename = "./assets/UsdCookie.usdz";
|
||||
const usd_filename = "./assets/suzanne-pbr.usda";
|
||||
|
||||
var threeScenes = []
|
||||
|
||||
const usd_scenes = await Promise.all([
|
||||
//loader.loadAsync(texcat_filename),
|
||||
loader.loadAsync(cookie_filename),
|
||||
loader.loadAsync(usd_filename),
|
||||
//loader.loadAsync(suzanne_filename),
|
||||
]);
|
||||
|
||||
hideLoadingScreen();
|
||||
|
||||
const defaultMtl = ui_state['defaultMtl'];
|
||||
|
||||
const options = {
|
||||
@@ -114,8 +208,13 @@ async function initScene() {
|
||||
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||
camera.position.z = ui_state['camera_z'];
|
||||
|
||||
const renderer = new THREE.WebGLRenderer();
|
||||
const renderer = new THREE.WebGLRenderer({
|
||||
preserveDrawingBuffer: true, // for screenshot
|
||||
alpha: true, // Enable transparency
|
||||
antialias: true
|
||||
});
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
ui_state['renderer'] = renderer; // Store renderer in ui_state
|
||||
document.body.appendChild(renderer.domElement);
|
||||
|
||||
const rootNodes = await loadScenes();
|
||||
|
||||
1333
web/demo/package-lock.json
generated
1333
web/demo/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,7 @@
|
||||
"vite": "^6.1.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.15.1",
|
||||
"fzstd": "^0.1.1",
|
||||
"gsap": "^3.13.0",
|
||||
"lil-gui": "^0.19.2",
|
||||
|
||||
Reference in New Issue
Block a user