UNPKG

13.7 kBPlain TextView Raw
1import Color from '../style-spec/util/color';
2
3import type Context from './context';
4import type {
5 BlendFuncType,
6 BlendEquationType,
7 ColorMaskType,
8 DepthRangeType,
9 DepthMaskType,
10 StencilFuncType,
11 StencilOpType,
12 DepthFuncType,
13 TextureUnitType,
14 ViewportType,
15 CullFaceModeType,
16 FrontFaceType,
17} from './types';
18
19export interface IValue<T> {
20 current: T;
21 default: T;
22 dirty: boolean;
23 get(): T;
24 setDefault(): void;
25 set(value: T): void;
26}
27
28class BaseValue<T> implements IValue<T> {
29 gl: WebGLRenderingContext;
30 current: T;
31 default: T;
32 dirty: boolean;
33
34 constructor(context: Context) {
35 this.gl = context.gl;
36 this.default = this.getDefault();
37 this.current = this.default;
38 this.dirty = false;
39 }
40
41 get(): T {
42 return this.current;
43 }
44 set(value: T) { // eslint-disable-line
45 // overridden in child classes;
46 }
47
48 getDefault(): T {
49 return this.default; // overriden in child classes
50 }
51 setDefault() {
52 this.set(this.default);
53 }
54}
55
56export class ClearColor extends BaseValue<Color> {
57 getDefault(): Color {
58 return Color.transparent;
59 }
60 set(v: Color) {
61 const c = this.current;
62 if (v.r === c.r && v.g === c.g && v.b === c.b && v.a === c.a && !this.dirty) return;
63 this.gl.clearColor(v.r, v.g, v.b, v.a);
64 this.current = v;
65 this.dirty = false;
66 }
67}
68
69export class ClearDepth extends BaseValue<number> {
70 getDefault(): number {
71 return 1;
72 }
73 set(v: number) {
74 if (v === this.current && !this.dirty) return;
75 this.gl.clearDepth(v);
76 this.current = v;
77 this.dirty = false;
78 }
79}
80
81export class ClearStencil extends BaseValue<number> {
82 getDefault(): number {
83 return 0;
84 }
85 set(v: number) {
86 if (v === this.current && !this.dirty) return;
87 this.gl.clearStencil(v);
88 this.current = v;
89 this.dirty = false;
90 }
91}
92
93export class ColorMask extends BaseValue<ColorMaskType> {
94 getDefault(): ColorMaskType {
95 return [true, true, true, true];
96 }
97 set(v: ColorMaskType) {
98 const c = this.current;
99 if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && v[3] === c[3] && !this.dirty) return;
100 this.gl.colorMask(v[0], v[1], v[2], v[3]);
101 this.current = v;
102 this.dirty = false;
103 }
104}
105
106export class DepthMask extends BaseValue<DepthMaskType> {
107 getDefault(): DepthMaskType {
108 return true;
109 }
110 set(v: DepthMaskType): void {
111 if (v === this.current && !this.dirty) return;
112 this.gl.depthMask(v);
113 this.current = v;
114 this.dirty = false;
115 }
116}
117
118export class StencilMask extends BaseValue<number> {
119 getDefault(): number {
120 return 0xFF;
121 }
122 set(v: number): void {
123 if (v === this.current && !this.dirty) return;
124 this.gl.stencilMask(v);
125 this.current = v;
126 this.dirty = false;
127 }
128}
129
130export class StencilFunc extends BaseValue<StencilFuncType> {
131 getDefault(): StencilFuncType {
132 return {
133 func: this.gl.ALWAYS,
134 ref: 0,
135 mask: 0xFF
136 };
137 }
138 set(v: StencilFuncType): void {
139 const c = this.current;
140 if (v.func === c.func && v.ref === c.ref && v.mask === c.mask && !this.dirty) return;
141 this.gl.stencilFunc(v.func, v.ref, v.mask);
142 this.current = v;
143 this.dirty = false;
144 }
145}
146
147export class StencilOp extends BaseValue<StencilOpType> {
148 getDefault(): StencilOpType {
149 const gl = this.gl;
150 return [gl.KEEP, gl.KEEP, gl.KEEP];
151 }
152 set(v: StencilOpType) {
153 const c = this.current;
154 if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && !this.dirty) return;
155 this.gl.stencilOp(v[0], v[1], v[2]);
156 this.current = v;
157 this.dirty = false;
158 }
159}
160
161export class StencilTest extends BaseValue<boolean> {
162 getDefault(): boolean {
163 return false;
164 }
165 set(v: boolean) {
166 if (v === this.current && !this.dirty) return;
167 const gl = this.gl;
168 if (v) {
169 gl.enable(gl.STENCIL_TEST);
170 } else {
171 gl.disable(gl.STENCIL_TEST);
172 }
173 this.current = v;
174 this.dirty = false;
175 }
176}
177
178export class DepthRange extends BaseValue<DepthRangeType> {
179 getDefault(): DepthRangeType {
180 return [0, 1];
181 }
182 set(v: DepthRangeType) {
183 const c = this.current;
184 if (v[0] === c[0] && v[1] === c[1] && !this.dirty) return;
185 this.gl.depthRange(v[0], v[1]);
186 this.current = v;
187 this.dirty = false;
188 }
189}
190
191export class DepthTest extends BaseValue<boolean> {
192 getDefault(): boolean {
193 return false;
194 }
195 set(v: boolean) {
196 if (v === this.current && !this.dirty) return;
197 const gl = this.gl;
198 if (v) {
199 gl.enable(gl.DEPTH_TEST);
200 } else {
201 gl.disable(gl.DEPTH_TEST);
202 }
203 this.current = v;
204 this.dirty = false;
205 }
206}
207
208export class DepthFunc extends BaseValue<DepthFuncType> {
209 getDefault(): DepthFuncType {
210 return this.gl.LESS;
211 }
212 set(v: DepthFuncType) {
213 if (v === this.current && !this.dirty) return;
214 this.gl.depthFunc(v);
215 this.current = v;
216 this.dirty = false;
217 }
218}
219
220export class Blend extends BaseValue<boolean> {
221 getDefault(): boolean {
222 return false;
223 }
224 set(v: boolean) {
225 if (v === this.current && !this.dirty) return;
226 const gl = this.gl;
227 if (v) {
228 gl.enable(gl.BLEND);
229 } else {
230 gl.disable(gl.BLEND);
231 }
232 this.current = v;
233 this.dirty = false;
234 }
235}
236
237export class BlendFunc extends BaseValue<BlendFuncType> {
238 getDefault(): BlendFuncType {
239 const gl = this.gl;
240 return [gl.ONE, gl.ZERO];
241 }
242 set(v: BlendFuncType) {
243 const c = this.current;
244 if (v[0] === c[0] && v[1] === c[1] && !this.dirty) return;
245 this.gl.blendFunc(v[0], v[1]);
246 this.current = v;
247 this.dirty = false;
248 }
249}
250
251export class BlendColor extends BaseValue<Color> {
252 getDefault(): Color {
253 return Color.transparent;
254 }
255 set(v: Color) {
256 const c = this.current;
257 if (v.r === c.r && v.g === c.g && v.b === c.b && v.a === c.a && !this.dirty) return;
258 this.gl.blendColor(v.r, v.g, v.b, v.a);
259 this.current = v;
260 this.dirty = false;
261 }
262}
263
264export class BlendEquation extends BaseValue<BlendEquationType> {
265 getDefault(): BlendEquationType {
266 return this.gl.FUNC_ADD;
267 }
268 set(v: BlendEquationType) {
269 if (v === this.current && !this.dirty) return;
270 this.gl.blendEquation(v);
271 this.current = v;
272 this.dirty = false;
273 }
274}
275
276export class CullFace extends BaseValue<boolean> {
277 getDefault(): boolean {
278 return false;
279 }
280 set(v: boolean) {
281 if (v === this.current && !this.dirty) return;
282 const gl = this.gl;
283 if (v) {
284 gl.enable(gl.CULL_FACE);
285 } else {
286 gl.disable(gl.CULL_FACE);
287 }
288 this.current = v;
289 this.dirty = false;
290 }
291}
292
293export class CullFaceSide extends BaseValue<CullFaceModeType> {
294 getDefault(): CullFaceModeType {
295 return this.gl.BACK;
296 }
297 set(v: CullFaceModeType) {
298 if (v === this.current && !this.dirty) return;
299 this.gl.cullFace(v);
300 this.current = v;
301 this.dirty = false;
302 }
303}
304
305export class FrontFace extends BaseValue<FrontFaceType> {
306 getDefault(): FrontFaceType {
307 return this.gl.CCW;
308 }
309 set(v: FrontFaceType) {
310 if (v === this.current && !this.dirty) return;
311 this.gl.frontFace(v);
312 this.current = v;
313 this.dirty = false;
314 }
315}
316
317export class ProgramValue extends BaseValue<WebGLProgram> {
318 getDefault(): WebGLProgram {
319 return null;
320 }
321 set(v?: WebGLProgram | null) {
322 if (v === this.current && !this.dirty) return;
323 this.gl.useProgram(v);
324 this.current = v;
325 this.dirty = false;
326 }
327}
328
329export class ActiveTextureUnit extends BaseValue<TextureUnitType> {
330 getDefault(): TextureUnitType {
331 return this.gl.TEXTURE0;
332 }
333 set(v: TextureUnitType) {
334 if (v === this.current && !this.dirty) return;
335 this.gl.activeTexture(v);
336 this.current = v;
337 this.dirty = false;
338 }
339}
340
341export class Viewport extends BaseValue<ViewportType> {
342 getDefault(): ViewportType {
343 const gl = this.gl;
344 return [0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight];
345 }
346 set(v: ViewportType) {
347 const c = this.current;
348 if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && v[3] === c[3] && !this.dirty) return;
349 this.gl.viewport(v[0], v[1], v[2], v[3]);
350 this.current = v;
351 this.dirty = false;
352 }
353}
354
355export class BindFramebuffer extends BaseValue<WebGLFramebuffer> {
356 getDefault(): WebGLFramebuffer {
357 return null;
358 }
359 set(v?: WebGLFramebuffer | null) {
360 if (v === this.current && !this.dirty) return;
361 const gl = this.gl;
362 gl.bindFramebuffer(gl.FRAMEBUFFER, v);
363 this.current = v;
364 this.dirty = false;
365 }
366}
367
368export class BindRenderbuffer extends BaseValue<WebGLRenderbuffer> {
369 getDefault(): WebGLRenderbuffer {
370 return null;
371 }
372 set(v?: WebGLRenderbuffer | null) {
373 if (v === this.current && !this.dirty) return;
374 const gl = this.gl;
375 gl.bindRenderbuffer(gl.RENDERBUFFER, v);
376 this.current = v;
377 this.dirty = false;
378 }
379}
380
381export class BindTexture extends BaseValue<WebGLTexture> {
382 getDefault(): WebGLTexture {
383 return null;
384 }
385 set(v?: WebGLTexture | null) {
386 if (v === this.current && !this.dirty) return;
387 const gl = this.gl;
388 gl.bindTexture(gl.TEXTURE_2D, v);
389 this.current = v;
390 this.dirty = false;
391 }
392}
393
394export class BindVertexBuffer extends BaseValue<WebGLBuffer> {
395 getDefault(): WebGLBuffer {
396 return null;
397 }
398 set(v?: WebGLBuffer | null) {
399 if (v === this.current && !this.dirty) return;
400 const gl = this.gl;
401 gl.bindBuffer(gl.ARRAY_BUFFER, v);
402 this.current = v;
403 this.dirty = false;
404 }
405}
406
407export class BindElementBuffer extends BaseValue<WebGLBuffer> {
408 getDefault(): WebGLBuffer {
409 return null;
410 }
411 set(v?: WebGLBuffer | null) {
412 // Always rebind
413 const gl = this.gl;
414 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, v);
415 this.current = v;
416 this.dirty = false;
417 }
418}
419
420export class BindVertexArrayOES extends BaseValue<any> {
421 vao: any;
422
423 constructor(context: Context) {
424 super(context);
425 this.vao = context.extVertexArrayObject;
426 }
427 getDefault(): any {
428 return null;
429 }
430 set(v: any) {
431 if (!this.vao || v === this.current && !this.dirty) return;
432 this.vao.bindVertexArrayOES(v);
433 this.current = v;
434 this.dirty = false;
435 }
436}
437
438export class PixelStoreUnpack extends BaseValue<number> {
439 getDefault(): number {
440 return 4;
441 }
442 set(v: number) {
443 if (v === this.current && !this.dirty) return;
444 const gl = this.gl;
445 gl.pixelStorei(gl.UNPACK_ALIGNMENT, v);
446 this.current = v;
447 this.dirty = false;
448 }
449}
450
451export class PixelStoreUnpackPremultiplyAlpha extends BaseValue<boolean> {
452 getDefault(): boolean {
453 return false;
454 }
455 set(v: boolean): void {
456 if (v === this.current && !this.dirty) return;
457 const gl = this.gl;
458 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, ((v as any)));
459 this.current = v;
460 this.dirty = false;
461 }
462}
463
464export class PixelStoreUnpackFlipY extends BaseValue<boolean> {
465 getDefault(): boolean {
466 return false;
467 }
468 set(v: boolean): void {
469 if (v === this.current && !this.dirty) return;
470 const gl = this.gl;
471 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, ((v as any)));
472 this.current = v;
473 this.dirty = false;
474 }
475}
476
477class FramebufferAttachment<T> extends BaseValue<T> {
478 parent: WebGLFramebuffer;
479 context: Context;
480
481 constructor(context: Context, parent: WebGLFramebuffer) {
482 super(context);
483 this.context = context;
484 this.parent = parent;
485 }
486 getDefault() {
487 return null;
488 }
489}
490
491export class ColorAttachment extends FramebufferAttachment<WebGLTexture> {
492 setDirty() {
493 this.dirty = true;
494 }
495 set(v?: WebGLTexture | null): void {
496 if (v === this.current && !this.dirty) return;
497 this.context.bindFramebuffer.set(this.parent);
498 // note: it's possible to attach a renderbuffer to the color
499 // attachment point, but thus far MBGL only uses textures for color
500 const gl = this.gl;
501 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, v, 0);
502 this.current = v;
503 this.dirty = false;
504 }
505}
506
507export class DepthAttachment extends FramebufferAttachment<WebGLRenderbuffer> {
508 set(v?: WebGLRenderbuffer | null): void {
509 if (v === this.current && !this.dirty) return;
510 this.context.bindFramebuffer.set(this.parent);
511 // note: it's possible to attach a texture to the depth attachment
512 // point, but thus far MBGL only uses renderbuffers for depth
513 const gl = this.gl;
514 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, v);
515 this.current = v;
516 this.dirty = false;
517 }
518}