diff --git a/src/gl/context.js b/src/gl/context.js index 24ed780d0b1..04f84290a91 100644 --- a/src/gl/context.js +++ b/src/gl/context.js @@ -7,7 +7,7 @@ import DepthMode from './depth_mode'; import StencilMode from './stencil_mode'; import ColorMode from './color_mode'; import { deepEqual } from '../util/util'; -import { ClearColor, ClearDepth, ClearStencil, ColorMask, DepthMask, StencilMask, StencilFunc, StencilOp, StencilTest, DepthRange, DepthTest, DepthFunc, Blend, BlendFunc, BlendColor, Program, ActiveTextureUnit, Viewport, BindFramebuffer, BindRenderbuffer, BindTexture, BindVertexBuffer, BindElementBuffer, BindVertexArrayOES, PixelStoreUnpack, PixelStoreUnpackPremultiplyAlpha } from './value'; +import { ClearColor, ClearDepth, ClearStencil, ColorMask, DepthMask, StencilMask, StencilFunc, StencilOp, StencilTest, DepthRange, DepthTest, DepthFunc, Blend, BlendFunc, BlendColor, CullFace, CullFaceMode, FrontFace, Program, ActiveTextureUnit, Viewport, BindFramebuffer, BindRenderbuffer, BindTexture, BindVertexBuffer, BindElementBuffer, BindVertexArrayOES, PixelStoreUnpack, PixelStoreUnpackPremultiplyAlpha } from './value'; import type {TriangleIndexArray, LineIndexArray, LineStripIndexArray} from '../data/index_array_type'; @@ -16,6 +16,10 @@ import type { StructArrayMember } from '../util/struct_array'; import type Color from '../style-spec/util/color'; +import type { + CullFaceModeType, + FrontFaceType, +} from './types'; type ClearArgs = { color?: Color, @@ -44,6 +48,9 @@ class Context { blend: Blend; blendFunc: BlendFunc; blendColor: BlendColor; + cullFace: CullFace; + cullFaceMode: CullFaceMode; + frontFace: FrontFace; program: Program; activeTexture: ActiveTextureUnit; viewport: Viewport; @@ -79,6 +86,9 @@ class Context { this.blend = new Blend(this); this.blendFunc = new BlendFunc(this); this.blendColor = new BlendColor(this); + this.cullFace = new CullFace(this); + this.cullFaceMode = new CullFaceMode(this); + this.frontFace = new FrontFace(this); this.program = new Program(this); this.activeTexture = new ActiveTextureUnit(this); this.viewport = new Viewport(this); @@ -156,6 +166,13 @@ class Context { gl.clear(mask); } + setCullFace(cullFace: boolean, cullFaceMode?: CullFaceModeType, frontFace?: FrontFaceType) { + const gl = this.gl; + this.cullFace.set(cullFace); + this.cullFaceMode.set(cullFaceMode ? cullFaceMode : gl.BACK); + this.frontFace.set(frontFace ? frontFace : gl.CCW); + } + setDepthMode(depthMode: $ReadOnly) { if (depthMode.func === this.gl.ALWAYS && !depthMode.mask) { this.depthTest.set(false); diff --git a/src/gl/types.js b/src/gl/types.js index 01449372bbe..e89ead63183 100644 --- a/src/gl/types.js +++ b/src/gl/types.js @@ -68,3 +68,12 @@ export type StencilTest = | { func: $PropertyType, mask: number } | { func: $PropertyType, mask: number } | { func: $PropertyType, mask: 0 }; + +export type CullFaceModeType = + | $PropertyType + | $PropertyType + | $PropertyType + +export type FrontFaceType = + | $PropertyType + | $PropertyType diff --git a/src/gl/value.js b/src/gl/value.js index 7e42bad7d45..860285a1094 100644 --- a/src/gl/value.js +++ b/src/gl/value.js @@ -13,6 +13,8 @@ import type { DepthFuncType, TextureUnitType, ViewportType, + CullFaceModeType, + FrontFaceType, } from './types'; export interface Value { @@ -335,6 +337,72 @@ export class BlendColor implements Value { } } +export class CullFace implements Value { + context: Context; + current: boolean; + + constructor(context: Context) { + this.context = context; + this.current = false; + } + + get(): boolean { return this.current; } + + set(v: boolean): void { + if (this.current !== v) { + const gl = this.context.gl; + if (v) { + gl.enable(gl.CULL_FACE); + } else { + gl.disable(gl.CULL_FACE); + } + this.current = v; + } + } +} + +export class CullFaceMode implements Value { + context: Context; + current: CullFaceModeType; + + constructor(context: Context) { + this.context = context; + const gl = this.context.gl; + this.current = gl.BACK; + } + + get(): CullFaceModeType { return this.current; } + + set(v: CullFaceModeType): void { + if (this.current !== v) { + const gl = this.context.gl; + gl.cullFace(v); + this.current = v; + } + } +} + +export class FrontFace implements Value { + context: Context; + current: FrontFaceType; + + constructor(context: Context) { + this.context = context; + const gl = this.context.gl; + this.current = gl.CCW; + } + + get(): FrontFaceType { return this.current; } + + set(v: FrontFaceType): void { + if (this.current !== v) { + const gl = this.context.gl; + gl.frontFace(v); + this.current = v; + } + } +} + export class Program implements Value { context: Context; current: ?WebGLProgram; diff --git a/src/render/painter.js b/src/render/painter.js index 7041ab9bbde..4f6c011ebd1 100644 --- a/src/render/painter.js +++ b/src/render/painter.js @@ -332,6 +332,11 @@ class Painter { this.renderPass = 'offscreen'; this.depthRboNeedsClear = true; + // Clockwise winding order for culling front-facing triangles when + // rendering offscreen. + const gl = this.context.gl; + this.context.setCullFace(true, gl.FRONT, gl.CCW); + for (const layerId of layerIds) { const layer = this.style._layers[layerId]; if (!layer.hasOffscreenPass() || layer.isHidden(this.transform.zoom)) continue; @@ -348,6 +353,10 @@ class Painter { // Clear buffers in preparation for drawing to the main framebuffer this.context.clear({ color: options.showOverdrawInspector ? Color.black : Color.transparent, depth: 1 }); + // Counter-clockwise winding order for culling back-facing triangles + // when rendering on the main buffer. + this.context.setCullFace(true, gl.BACK, gl.CCW); + this._showOverdrawInspector = options.showOverdrawInspector; this.depthRange = (style._order.length + 2) * this.numSublayers * this.depthEpsilon;