| 3549 | // Inverse of _packStructArray reads packed buffer back into plain JS objects |
| 3550 | // using the same schema layout - fields, stride and offsets |
| 3551 | _unpackStructArray(floatView, schema) { |
| 3552 | const { fields, stride } = schema; |
| 3553 | const dataView = new DataView(floatView.buffer); |
| 3554 | const count = Math.floor(floatView.byteLength / stride); |
| 3555 | const result = []; |
| 3556 | |
| 3557 | for (let i = 0; i < count; i++) { |
| 3558 | const item = {}; |
| 3559 | const baseOffset = i * stride; |
| 3560 | for (const field of fields) { |
| 3561 | const byteOffset = baseOffset + field.offset; |
| 3562 | const n = field.size / 4; |
| 3563 | |
| 3564 | if (field.baseType === 'u32') { |
| 3565 | if (n === 1) { |
| 3566 | item[field.name] = dataView.getUint32(byteOffset, true); |
| 3567 | } else { |
| 3568 | item[field.name] = Array.from({ length: n }, (_, j) => |
| 3569 | dataView.getUint32(byteOffset + j * 4, true) |
| 3570 | ); |
| 3571 | } |
| 3572 | } else if (field.baseType === 'i32') { |
| 3573 | if (n === 1) { |
| 3574 | item[field.name] = dataView.getInt32(byteOffset, true); |
| 3575 | } else { |
| 3576 | item[field.name] = Array.from({ length: n }, (_, j) => |
| 3577 | dataView.getInt32(byteOffset + j * 4, true) |
| 3578 | ); |
| 3579 | } |
| 3580 | } else { |
| 3581 | const idx = byteOffset / 4; |
| 3582 | if (n === 1) { |
| 3583 | item[field.name] = floatView[idx]; |
| 3584 | } else { |
| 3585 | const values = Array.from(floatView.slice(idx, idx + n)); |
| 3586 | if (field.kind === 'vector') { |
| 3587 | item[field.name] = this._pInst.createVector(...values); |
| 3588 | } else if (field.kind === 'color') { |
| 3589 | // Color was packed as normalized RGBA [0-1] via _getRGBA([1,1,1,1]) |
| 3590 | // Scale back to the current colorMode range |
| 3591 | const maxes = this.states.colorMaxes[this.states.colorMode]; |
| 3592 | item[field.name] = this._pInst.color( |
| 3593 | values[0] * maxes[0], values[1] * maxes[1], |
| 3594 | values[2] * maxes[2], values[3] * maxes[3] |
| 3595 | ); |
| 3596 | } else { |
| 3597 | item[field.name] = values; |
| 3598 | } |
| 3599 | } |
| 3600 | } |
| 3601 | } |
| 3602 | result.push(item); |
| 3603 | } |
| 3604 | |
| 3605 | return result; |
| 3606 | } |
| 3607 | |
| 3608 | createStorage(dataOrCount) { |