Reads numbers from .usda and .usdc files, in the type each value is stored as.
How the precision is kept
Float values are held in 32-bit: the text reader applies Math.fround for float types, arrays of float and half types become Float32Array, and in the binary reader a float array is a view of the file bytes as Float32Array. Double arrays are Float64Array.
Open item. Read double arrays and time values into Float64Array wherever the file holds 64-bit, and keep the 32-bit type only for attributes that are declared float.
Calculations under this policy
5 calculations in 2 source files. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.
usd/usdc-read.jsCadCraft 0.8.2 32-bit in part3 calculationsReviewed
TestsNone found by the review
Inline values
32-bit in part
A value that the file stores inside its 32-bit payload word.
Float, double and timecode share one branch: the payload bits are set into a DataView and read with getFloat32, so the value is 32-bit even for double. Half goes through halfToFloat; ints are the payload as signed or unsigned 32-bit.
usd/usdc-read.js
lines 305 to 331
CadCraft 0.8.2
inline(base, payload) {
const c = this.c, d = TYPES[base];
const u = payload >>> 0;
const s = u | 0;
switch (base) {
case 'bool': return !!(u & 0xff);
case 'uchar': return u & 0xff;
case 'int': return s;
case 'uint': return u;
case 'int64': return s;
case 'uint64': return u;
case 'half': return halfToFloat(u & 0xffff);
case 'float': case 'double': case 'timecode': { F32B.setUint32(0, u, true); return F32B.getFloat32(0, true); }
case 'string': return c.str(u);
case 'token': case 'asset': return c.tok(u);
default: break;
}
const i8 = (k) => { const x = (u >>> (8 * k)) & 0xff; return x > 127 ? x - 256 : x; };
if (d.mat) {
const m = d.mat, out = new Array(m * m).fill(0);
for (let k = 0; k < m; k++) out[k * m + k] = i8(k);
return out;
}
const out = new Array(d.n);
for (let k = 0; k < d.n; k++) out[k] = i8(k);
return out;
}
Raw arrays
32-bit in part
A packed array of numbers of one type.
A float array is a Float32Array over a copy of the file bytes (no conversion), half is converted to Float32Array through halfToFloat, and double is a Float64Array over the bytes.
usd/usdc-read.js
lines 401 to 417
CadCraft 0.8.2
/** n raw little-endian values of kind k → a typed array (half → Float32Array). */
raw(k, n) {
const r = this.r;
const size = { bool: 1, u8: 1, i32: 4, u32: 4, i64: 8, u64: 8, f16: 2, f32: 4, f64: 8 }[k];
const bytes = r.bytes(n * size).slice(); // a copy: aligned, and free of the file buffer
switch (k) {
case 'bool': return Array.from(bytes, (x) => !!x);
case 'u8': return bytes;
case 'i32': return new Int32Array(bytes.buffer);
case 'u32': return new Uint32Array(bytes.buffer);
case 'i64': return new BigInt64Array(bytes.buffer);
case 'u64': return new BigUint64Array(bytes.buffer);
case 'f16': { const h = new Uint16Array(bytes.buffer), out = new Float32Array(n); for (let i = 0; i < n; i++) out[i] = halfToFloat(h[i]); return out; }
case 'f32': return new Float32Array(bytes.buffer);
default: return new Float64Array(bytes.buffer);
}
}
Compressed float arrays
32-bit in part
An array stored as whole numbers or as a lookup table and indexes.
The output array is a Float64Array for double and a Float32Array otherwise; the whole-number form assigns decoded integers into it, and the table form copies table entries, so a float array holds 32-bit values.
usd/usdc-read.js
lines 372 to 389
CadCraft 0.8.2
if (compressed && d.n === 1 && (k === 'f16' || k === 'f32' || k === 'f64') && vcmp(c.ver, [0, 6, 0]) >= 0) {
if (n < MIN_COMPRESSED) return this.raw(k, n);
const code = r.u8();
const out = k === 'f64' ? new Float64Array(n) : new Float32Array(n);
if (code === 105) { // 'i': every value a whole number
const size = r.u64();
const ints = decodeInts(r.bytes(size), n);
for (let i = 0; i < n; i++) out[i] = ints[i];
} else if (code === 116) { // 't': a lookup table and indices
const lutN = r.u32();
if (lutN > n) throw damaged('ccusd.damaged.value');
const lut = this.raw(k, lutN);
const size = r.u64();
const ix = decodeInts(r.bytes(size), n, { unsigned: true });
for (let i = 0; i < n; i++) { if (ix[i] >= lutN) throw damaged('ccusd.damaged.value'); out[i] = lut[ix[i]]; }
} else throw damaged('ccusd.damaged.value');
return out;
}
usd/usda-read.jsCadCraft 0.8.2 32-bit in part2 calculationsReviewed
TestsNone found by the review
Float text rounding
32-bit in part
A float or half value read from .usda text.
The parsed 64-bit number is passed through Math.fround for float, and through floatToHalf then halfToFloat for half, so the value is rounded to the stored type when it is read.
usd/usda-read.js
lines 486 to 487
CadCraft 0.8.2
case 'f16': return halfToFloat(floatToHalf(this.number()));
case 'f32': return Math.fround(this.number());
Arrays from text
32-bit in part
A list of parsed numbers as a typed array of the right type.
f32 and f16 lists become Float32Array.from, f64 a Float64Array, and the integer types Int32Array, Uint32Array or Uint8Array; Float32Array.from rounds each number to 32 bits.
usd/usda-read.js
lines 560 to 571
CadCraft 0.8.2
function typedArray(k, items) {
switch (k) {
case 'f32': case 'f16': return Float32Array.from(items);
case 'f64': return Float64Array.from(items);
case 'i32': return Int32Array.from(items);
case 'u32': return Uint32Array.from(items);
case 'u8': return Uint8Array.from(items);
case 'i64': return BigInt64Array.from(items, (x) => BigInt(x));
case 'u64': return BigUint64Array.from(items, (x) => BigInt(x));
default: return items;
}
}
In detail
Method
Text: parse, then Math.fround or half rounding by type. Binary: decode the inline payload, the raw array, or the compressed integer or lookup-table array.
Number types
Float32Array for f32 and f16 data (half converted with a 65536 entry table), Float64Array for f64; inline values in the binary reader are read as a 32-bit float; integers up to 2^53 stay numbers and larger ones are BigInt.
Tolerances
None.
Limits
In the binary reader an inline float, double or timecode is read from the 32-bit payload with getFloat32, so an inline double carries 32-bit precision. Compressed float arrays that store whole numbers are written into a Float32Array when the type is float, so whole numbers above 2^24 would round.
Approach: 32-bit step, flagged
One step stores or exchanges 32-bit values that reach a number a person reads. It is listed here with its open item, and the step is either moved to 64-bit or the app will warn where the number is read.