/
input-assembler.ts
302 lines (259 loc) · 7.59 KB
/
input-assembler.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/**
* @category gfx
*/
import { writeBuffer } from '../3d/misc/buffer';
import { GFXBuffer, GFXBufferSource, IGFXDrawInfo } from './buffer';
import { GFXFormat, GFXFormatInfos, GFXObject, GFXObjectType } from './define';
import { GFXDevice } from './device';
/**
* @zh
* GFX顶点属性。
*/
export interface IGFXAttribute {
name: string;
format: GFXFormat;
isNormalized?: boolean;
stream?: number;
isInstanced?: boolean;
}
/**
* @zh
* GFX输入汇集器描述信息。
*/
export interface IGFXInputAssemblerInfo {
attributes: IGFXAttribute[];
vertexBuffers: GFXBuffer[];
indexBuffer?: GFXBuffer;
indirectBuffer?: GFXBuffer;
}
/**
* @zh
* GFX输入汇集器。
*/
export abstract class GFXInputAssembler extends GFXObject {
/**
* @zh
* 顶点缓冲数组。
*/
public get vertexBuffers (): GFXBuffer[] {
return this._vertexBuffers;
}
/**
* @zh
* 索引缓冲。
*/
public get indexBuffer (): GFXBuffer | null {
return this._indexBuffer;
}
/**
* @zh
* 顶点属性数组。
*/
public get attributes (): IGFXAttribute[] {
return this._attributes;
}
/**
* @zh
* 顶点数量。
*/
public get vertexCount (): number {
return this._vertexCount;
}
public set vertexCount (count: number) {
this._vertexCount = count;
}
/**
* @zh
* 起始顶点。
*/
public get firstVertex (): number {
return this._firstVertex;
}
public set firstVertex (first: number) {
this._firstVertex = first;
}
/**
* @zh
* 索引数量。
*/
public get indexCount (): number {
return this._indexCount;
}
public set indexCount (count: number) {
this._indexCount = count;
}
/**
* @zh
* 起始索引。
*/
public get firstIndex (): number {
return this._firstIndex;
}
public set firstIndex (first: number) {
this._firstIndex = first;
}
/**
* @zh
* 顶点偏移量。
*/
public get vertexOffset (): number {
return this._vertexOffset;
}
public set vertexOffset (offset: number) {
this._vertexOffset = offset;
}
/**
* @zh
* 实例数量。
*/
public get instanceCount (): number {
return this._instanceCount;
}
public set instanceCount (count: number) {
this._instanceCount = count;
}
/**
* @zh
* 起始实例。
*/
public get firstInstance (): number {
return this._firstInstance;
}
public set firstInstance (first: number) {
this._firstInstance = first;
}
/**
* @zh
* 是否间接绘制。
*/
public get isIndirect (): boolean {
return this._isIndirect;
}
/**
* @zh
* 间接绘制缓冲。
*/
public get indirectBuffer (): GFXBuffer | null {
return this._indirectBuffer;
}
/**
* @zh
* GFX设备。
*/
protected _device: GFXDevice;
protected _attributes: IGFXAttribute[] = [];
protected _vertexBuffers: GFXBuffer[] = [];
protected _indexBuffer: GFXBuffer | null = null;
protected _vertexCount: number = 0;
protected _firstVertex: number = 0;
protected _indexCount: number = 0;
protected _firstIndex: number = 0;
protected _vertexOffset: number = 0;
protected _instanceCount: number = 0;
protected _firstInstance: number = 0;
protected _isIndirect: boolean = false;
protected _indirectBuffer: GFXBuffer | null = null;
/**
* 构造函数。
* @param device GFX设备。
*/
constructor (device: GFXDevice) {
super(GFXObjectType.INPUT_ASSEMBLER);
this._device = device;
}
/**
* @zh
* 初始化函数。
* @param info GFX汇集器描述信息。
*/
public abstract initialize (info: IGFXInputAssemblerInfo): boolean;
/**
* @zh
* 销毁函数。
*/
public abstract destroy (): void;
/**
* @zh
* 得到顶点缓冲。
* @param stream 顶点流索引。
*/
public getVertexBuffer (stream: number = 0): GFXBuffer | null {
if (stream < this._vertexBuffers.length) {
return this._vertexBuffers[stream];
} else {
return null;
}
}
/**
* @zh
* 提取绘制信息。
* @param drawInfo 绘制信息。
*/
public extractDrawInfo (drawInfo: IGFXDrawInfo) {
drawInfo.vertexCount = this._vertexCount;
drawInfo.firstVertex = this._firstVertex;
drawInfo.indexCount = this._indexCount;
drawInfo.firstIndex = this._firstIndex;
drawInfo.vertexOffset = this._vertexOffset;
drawInfo.instanceCount = this._instanceCount;
drawInfo.firstInstance = this._firstInstance;
}
/**
* @en
* update VB data on the fly.
* @zh
* 根据顶点属性名称更新顶点缓冲数据。
* @param vbuffer 缓冲数据源。
* @param attr 属性名。
* @param data 更新数据。
* @param index 要更新第几号顶点缓冲?(默认为 0)
* @param final 是否立即更新?(默认为 true,需要一次修改多个属性时可以使用)
* @example
* ```typescript
* // get VB array buffer from mesh, better to cache this somewhere convenient
* const vbInfo = mesh.struct.vertexBundles[mesh.struct.primitives[0].vertexBundelIndices[0]].view;
* const vbuffer = mesh.data.buffer.slice(vbInfo.offset, vbInfo.offset + vbInfo.length);
* const submodel = someModelComponent.model.getSubModel(0);
* // say the new positions is stored in 'data' as a plain array
* submodel.inputAssembler.updateVertexBuffer(vbuffer, cc.GFXAttributeName.ATTR_POSITION, data);
* ```
*/
public updateVertexAttr (vbuffer: GFXBufferSource, attr: string, data: number[], index = 0, final = true) {
let offset = 0;
let format = GFXFormat.UNKNOWN;
for (const a of this._attributes) {
if (a.name === attr) { format = a.format; break; }
offset += GFXFormatInfos[a.format].size;
}
const vb = this._vertexBuffers[index];
if (!format || !vb) { return; }
writeBuffer(new DataView(vbuffer as ArrayBuffer), data, format, offset, vb.stride);
if (final) { vb.update(vbuffer, 0, vb.stride * vb.count); }
}
/**
* @en
* update IB data on the fly.
* need to call `submodel.updateCommandBuffer` after this if index count changed
* @zh
* 更新索引缓冲数据,如果索引数量改变了,需要在此函数后调用 `submodel.updateCommandBuffer`。
* @param ibuffer 缓冲数据源。
* @param data 更新数据。
* @example
* ```typescript
* // get IB array buffer from mesh, better to cache this somewhere convenient
* const ibInfo = mesh.struct.primitives[0].indexView;
* const ibuffer = mesh.data.buffer.slice(ibInfo.offset, ibInfo.offset + ibInfo.length);
* const submodel = someModelComponent.model.getSubModel(0);
* submodel.inputAssembler.updateIndexBuffer(ibuffer, [0, 1, 2]);
* submodel.updateCommandBuffer(); // index count changed
* ```
*/
public updateIndexBuffer (ibuffer: GFXBufferSource, data: number[]) {
const count = this._indexCount;
const ib = this._indexBuffer;
if (!count || !ib) { return; }
writeBuffer(new DataView(ibuffer as ArrayBuffer), data, GFXFormat[`R${ib.stride * 8}UI`]);
ib.update(ibuffer, 0, ib.stride * ib.count);
this._indexCount = data.length;
}
}