-
Notifications
You must be signed in to change notification settings - Fork 0
/
stream.ts
145 lines (127 loc) · 4.73 KB
/
stream.ts
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import GL from 'luma.gl/constants'
import { Buffer, _Accessor as Accessor } from 'luma.gl'
import { Unsubscribable } from 'rxjs';
declare interface Buffer {
byteLength: number
subData: Function
copyData: Function
setByteLength(byteLength: number): void
_deleteHandle: () => void
}
import { Node, Read } from 'parcel-plugin-writable/var.d'
import { Peer } from 'parcel-plugin-writable/src/peer'
import createEvent from 'parcel-plugin-writable/src/event'
export type StreamNode = { stream: Stream, push: Node, subscription: Unsubscribable }
export const sync = (gl: any, accessor: any, didChange=() => {}) =>
(push: Node, read: Read): StreamNode => {
const stream = new Stream(gl, accessor);
const subscription = read(m => {
m.type === 'clear'
? stream.clear()
: stream.push(m.data)
didChange && didChange()
})
return {
push: push.withElementSize(stream.elementSize),
stream,
subscription
}
}
export class Stream {
constructor(private gl: any, private accessor: any, count?: number) {
count && this.allocBuffer(count * this.elementSize)
}
public buffer: Buffer
public array: Uint8Array
get elementSize(): number {
return Accessor.getBytesPerVertex(this.accessor)
}
get count() {
return Math.ceil(this.offset / this.elementSize)
}
public push(data: ArrayBuffer | ArrayBufferView) {
const neededBytes = data.byteLength + this.offset
if (!this.buffer || this.buffer.byteLength < neededBytes || !this.array || this.array.byteLength < neededBytes) {
// console.log('alloc', neededBytes * 2)
this.allocBuffer(neededBytes * 2)
// console.log('this.buffer.byteLength=', this.buffer.byteLength)
}
const newOffset = set(this.buffer, data, this.offset)
if (data instanceof Uint8Array) {
// console.log('data is a Uint8Array')
this.array.set(data, this.offset)
} else {
// console.log('data is something else')
const buf = ArrayBuffer.isView(data) ? data.buffer : data
const offset = ArrayBuffer.isView(data) ? data.byteOffset : 0
// console.log('buffer=', buf, 'array=', this.array.byteLength)
this.array.set(new Uint8Array(buf, offset, data.byteLength), this.offset)
}
// console.log('did push', data.byteLength, ' bytes into ', this.array.byteLength, 'offset:', this.offset)
// console.log(this.array)
// console.log(this, 'new offset=', newOffset, 'count=', this.count)
this.offset = newOffset
}
public clear() {
this.buffer && this.buffer.setByteLength(0)
this.array && (this.array = new Uint8Array(0))
this.offset = 0
}
private offset: number = 0
private allocBuffer(byteLength: number) {
const array = concatArrays(byteLength, this.array)
const { buffer, offset } = concat(this.gl, byteLength, this.accessor, this.array)
if (this.buffer) this.buffer._deleteHandle()
this.buffer = buffer
this.array = array
this.offset = offset
}
}
function concatArrays(byteLength: number, ...srcs: Uint8Array[]) {
byteLength = Math.max(byteLength, srcs.reduce((total, s) => total + (s ? s.byteLength : 0), 0))
// console.log('concatArrays byteLength=', byteLength)
const array = new Uint8Array(byteLength)
// console.log('creating array of size', array.byteLength)
let offset = 0
srcs.forEach(s => {
if (!s) return
// console.log('set', s.byteLength, 'at offset', offset, 'in array of byteLength=', array.byteLength, 'source:', s)
array.set(s, offset)
offset += s.byteLength
})
// console.log('copied data into new array', array)
return array
}
type DataSource = ArrayBuffer | ArrayBufferView | Buffer
function concat(gl: any, byteLength: number, accessor: any, ...srcs: (DataSource | undefined)[]) {
byteLength = Math.max(byteLength, srcs.reduce((total, s) => total + (s ? s.byteLength : 0), 0))
const buffer = new Buffer(gl, { byteLength, accessor })
let offset = 0
srcs.forEach(s => {
if (!s) return
offset = set(buffer, s, offset)
})
return {buffer, offset}
}
function set(buffer: Buffer, data: DataSource, offset: number) {
if (!data.byteLength) { return offset }
// console.log('set(buffer:', buffer, ', data.byteLength:', data.byteLength, 'offset: ', offset, ')')
if (ArrayBuffer.isView(data) || data instanceof ArrayBuffer) {
data instanceof ArrayBuffer
? buffer.subData({data: new Uint8Array(data), offset})
: buffer.subData({
data,
offset
})
} else {
console.log('copying from', data, 'to', buffer)
// buffer.copyData({
// sourceBuffer: data,
// readOffset: 0,
// writeOffset: offset,
// size: data.byteLength
// })
console.error('WebGL1 Unsupported code path')
}
return offset + data.byteLength
}