Skip to content

Commit

Permalink
stencilBuffer chunk first pass not test
Browse files Browse the repository at this point in the history
  • Loading branch information
shrekshao committed Jul 15, 2016
1 parent 4a64ac0 commit 2c9ad57
Show file tree
Hide file tree
Showing 3 changed files with 323 additions and 13 deletions.
49 changes: 49 additions & 0 deletions src/core/display/chunks/stencilBufferChunk.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
*
*/
SceneJS_ChunkFactory.createChunkType({

type: "stencilBuffer",

// Avoid reapplication of a chunk after a program switch.
programGlobal: true,

drawAndPick: function (frameCtx) {

var gl = this.program.gl;

var enabled = this.core.enabled;

if (frameCtx.stencilbufEnabled != enabled) {
if (enabled) {
gl.enable(gl.STENCIL_TEST);
} else {
gl.disable(gl.STENCIL_TEST);
}
frameCtx.stencilbufEnabled = enabled;
}

var clearStencil = this.core.clearStencil;

if (frameCtx.clearStencil != clearStencil) {
gl.clearStencil(clearStencil);
frameCtx.clearStencil = clearStencil;
}

var stencilFunc = this.core.stencilFunc;

if (frameCtx.stencilFunc != stencilFunc) {
gl.stencilFunc(stencilFunc.func, stencilFunc.ref, stencilFunc.mask);
frameCtx.stencilFunc = stencilFunc;
}

if (frameCtx.stencilOp != stencilOp) {
gl.stencilOp(stencilOp.sfail, stencilOp.dpfail, stencilOp.dppass);
frameCtx.stencilOp = stencilOp;
}

if (this.core.clear) {
gl.clear(gl.STENCIL_BUFFER_BIT);
}
}
});
37 changes: 24 additions & 13 deletions src/core/display/display.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ var SceneJS_Display = function (cfg) {
*/
this.depthBuffer = null;

/**
* Node state core for the last {@link SceneJS.StencilBuf} visited during scene graph compilation traversal
* @type Object
*/
this.stencilBuffer = null;

/**
* Node state core for the last {@link SceneJS.ColorBuf} visited during scene graph compilation traversal
* @type Object
Expand Down Expand Up @@ -444,19 +450,20 @@ SceneJS_Display.prototype.buildObject = function (objectId) {
this._setChunk(object, 6, "shaderParams", this.shaderParams);
this._setChunk(object, 7, "style", this.style);
this._setChunk(object, 8, "depthBuffer", this.depthBuffer);
this._setChunk(object, 9, "colorBuffer", this.colorBuffer);
this._setChunk(object, 10, "view", this.view);
this._setChunk(object, 11, "lights", this.lights);
this._setChunk(object, 12, "material", this.material);
this._setChunk(object, 13, "texture", this.texture);
this._setChunk(object, 14, "regionMap", this.regionMap);
this._setChunk(object, 15, "fresnel", this.fresnel);
this._setChunk(object, 16, "cubemap", this.cubemap);
this._setChunk(object, 17, "clips", this.clips);
this._setChunk(object, 18, "renderer", this.renderer);
this._setChunk(object, 19, "geometry", this.morphGeometry, this.geometry);
this._setChunk(object, 20, "listeners", this.renderListeners); // Must be after the above chunks
this._setChunk(object, 21, "draw", this.geometry); // Must be last
this._setChunk(object, 9, "stencilBuffer", this.stencilBuffer);
this._setChunk(object, 10, "colorBuffer", this.colorBuffer);
this._setChunk(object, 11, "view", this.view);
this._setChunk(object, 12, "lights", this.lights);
this._setChunk(object, 13, "material", this.material);
this._setChunk(object, 14, "texture", this.texture);
this._setChunk(object, 15, "regionMap", this.regionMap);
this._setChunk(object, 16, "fresnel", this.fresnel);
this._setChunk(object, 17, "cubemap", this.cubemap);
this._setChunk(object, 18, "clips", this.clips);
this._setChunk(object, 19, "renderer", this.renderer);
this._setChunk(object, 20, "geometry", this.morphGeometry, this.geometry);
this._setChunk(object, 21, "listeners", this.renderListeners); // Must be after the above chunks
this._setChunk(object, 22, "draw", this.geometry); // Must be last

// At the very least, the object sort order
// will need be recomputed
Expand Down Expand Up @@ -1504,6 +1511,10 @@ SceneJS_Display.prototype._doDrawList = function (params) {
frameCtx.depthbufEnabled = null;
frameCtx.clearDepth = null;
frameCtx.depthFunc = gl.LESS;
frameCtx.stencilbufEnabled = null;
frameCtx.clearStencil = null;
frameCtx.stencilFunc = {func: gl.ALWAYS, ref: 1, mask: 0xff};
frameCtx.stencilOp = {sfail: gl.KEEP, dpfail: gl.KEEP, dppass: gl.KEEP};
frameCtx.scissorTestEnabled = false;
frameCtx.blendEnabled = false;
frameCtx.backfaces = true;
Expand Down
250 changes: 250 additions & 0 deletions src/core/scene/stencilBuffer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
(function () {

var lookup = {
// stencilFunc.func
never: "NEVER",
less: "LESS",
equal: "EQUAL",
lequal: "LEQUAL",
greater: "GREATER",
notequal: "NOTEQUAL",
gequal: "GEQUAL",
always: "ALWAYS",

// stencilOp
keep: "KEEP",
zero: "ZERO",
replace: "REPLACE",
incr: "INCR",
incr_wrap: "INCR_WRAP",
decr: "DECR",
decr_wrap: "DECR_WRAP",
invert: "INVERT"
};

// The default state core singleton for {@link SceneJS.StencilBuf} nodes
var defaultCore = {
type: "stencilBuffer",
stateId: SceneJS._baseStateId++,
enabled: true,
clearStencil: 1,
stencilFunc: {func: null, ref: 1, mask: 0xff}, // Lazy init stencilFunc when we can get a context
stencilOp: {sfail: null, dpfail: null, dppass: null},
_stencilFuncState: {func: "always", ref: 1, mask: 0xff},
_stencilOpState: {sfail: "keep", dpfail: "keep", dppass: "keep"}
};

var coreStack = [];
var stackLen = 0;

SceneJS_events.addListener(
SceneJS_events.SCENE_COMPILING,
function (params) {
if (defaultCore.stencilFunc === null) { // Lazy-init stencilFunc now we can get a context
defaultCore.stencilFunc.func = params.engine.canvas.gl.ALWAYS;

defaultCore.stencilFunc.sfail = params.engine.canvas.gl.KEEP;
defaultCore.stencilFunc.dpfail = params.engine.canvas.gl.KEEP;
defaultCore.stencilFunc.dppass = params.engine.canvas.gl.KEEP;
}
params.engine.display.stencilBuffer = defaultCore;
stackLen = 0;
});

/**
* @class Scene graph node which configures the stencil buffer for its subgraph
* @extends SceneJS.Node
*/
SceneJS.StencilBuf = SceneJS_NodeFactory.createNodeType("stencilBuffer");

SceneJS.StencilBuf.prototype._init = function (params) {

if (params.enabled != undefined) {
this.setEnabled(params.enabled);
} else if (this._core.useCount == 1) { // This node defines the core
this.setEnabled(true);
}

if (params.clearStencil != undefined) {
this.setClearStencil(params.clearStencil);
} else if (this._core.useCount == 1) {
this.setClearStencil(1);
}

if (params.stencilFunc != undefined) {
this.setStencilFunc(params.stencilFunc);
} else if (this._core.useCount == 1) {
this.setStencilFunc({
func: "always",
ref: 1,
mask: 0xff
});
}

if (params.stencilOp != undefined) {
this.setStencilOp(params.stencilOp);
} else if (this._core.useCount == 1) {
this.setStencilOp({
sfail: "keep",
dpfail: "keep",
dppass: "keep"
});
}

if (params.clear != undefined) {
this.setClear(params.clear);
} else if (this._core.useCount == 1) {
this.setClear(true);
}
};

/**
* Enable or disable the stencil buffer
*
* @param enabled Specifies whether stencil buffer is enabled or not
* @return {*}
*/
SceneJS.StencilBuf.prototype.setEnabled = function (enabled) {
if (this._core.enabled != enabled) {
this._core.enabled = enabled;
this._engine.display.imageDirty = true;
}
return this;
};

/**
* Get whether or not the stencil buffer is enabled
*
* @return Boolean
*/
SceneJS.StencilBuf.prototype.getEnabled = function () {
return this._core.enabled;
};

/**
* Sets whether or not to clear the stencil buffer before each render
*
* @param clear
* @return {*}
*/
SceneJS.StencilBuf.prototype.setClear = function (clear) {
if (this._core.clear != clear) {
this._core.clear = clear;
this._engine.display.imageDirty = true;
}
return this;
};

/**
* Get whether or not the stencil buffer is cleared before each render
*
* @return Boolean
*/
SceneJS.StencilBuf.prototype.getClear = function () {
return this._core.clear;
};

/**
* Specify the clear value for the stencil buffer.
* Initial value is 1, and the given value will be clamped to [0..1].
* @param clearStencil
* @return {*}
*/
SceneJS.StencilBuf.prototype.setClearStencil = function (clearStencil) {
if (this._core.clearStencil != clearStencil) {
this._core.clearStencil = clearStencil;
this._engine.display.imageDirty = true;
}
return this;
};

/**
* Get the clear value for the stencil buffer
*
* @return Number
*/
SceneJS.StencilBuf.prototype.getClearStencil = function () {
return this._core.clearStencil;
};

/**
* Sets the stencil comparison function.
* Supported values are 'keep', 'always', 'less', 'equal', 'lequal', 'greater', 'notequal' and 'gequal'
* @param {String} stencilFunc The stencil comparison function
* @return {*}
*/
SceneJS.StencilBuf.prototype.setStencilFunc = function (stencilFunc) {
stencilFunc.ref = stencilFunc.ref || 1;
stencilFunc.mask = stencilFunc.mask || 0xff;

if (this._core._stencilFuncState.func != stencilFunc.func ||
this._core._stencilFuncState.ref != stencilFunc.ref ||
this._core._stencilFuncState.mask != stencilFunc.mask
) {

var funcEnumName = lookup[stencilFunc.func];
if (funcEnumName == undefined) {
throw "unsupported value for 'clearFunc' attribute on stencilBuffer node: '" + stencilFunc.func
+ "' - supported values are 'keep', 'always', 'less', 'equal', 'lequal', 'greater', 'notequal' and 'gequal'";
}
this._core.stencilFunc.func = this._engine.canvas.gl[funcEnumName];
this._core.stencilFunc.ref = stencilFunc.ref;
this._core.stencilFunc.mask = stencilFunc.mask;
this._core._stencilFuncState = stencilFunc; // state map
this._engine.display.imageDirty = true;
}
return this;
};

/**
* Sets the stencil comparison function.
* Supported values are 'keep', 'zero', 'replace', 'incr', 'incr_wrap', 'decr', 'decr_wrap', 'invert'
* @param {String} stencilFunc The stencil comparison function
* @return {*}
*/
SceneJS.StencilBuf.prototype.setStencilOp = function (stencilOp) {
if (
this._core._stencilOpState.sfail != stencilOp.sfail ||
this._core._stencilOpState.dpfail != stencilOp.dpfail ||
this._core._stencilOpState.dppass != stencilOp.dppass
) {
var sfail = lookup[stencilOp.sfail];
var dpfail = lookup[stencilOp.dpfail];
var dppass = lookup[stencilOp.dppass];
if (sfail == undefined || dpfail == undefined || dppass == undefined) {
throw "unsupported value for 'clearFunc' attribute on stencilBuffer node: '" + stencilFunc
+ "' - supported values are 'keep', 'zero', 'replace', 'incr', 'incr_wrap', 'decr', 'decr_wrap', 'invert'";
}
this._core.stencilOp.sfail = this._engine.canvas.gl[sfail];
this._core.stencilOp.dpfail = this._engine.canvas.gl[dpfail];
this._core.stencilOp.dppass = this._engine.canvas.gl[dppass];
this._core._stencilOpState = stencilOp;
this._engine.display.imageDirty = true;
}
return this;
};

/**
* Returns the stencilFunc State
* @return {*}
*/
SceneJS.StencilBuf.prototype.getStencilFunc = function () {
return this._core._stencilFuncState;
};

/**
* Returns the stencilOp State
* @return {*}
*/
SceneJS.StencilBuf.prototype.getStencilState = function () {
return this._core._stencilOpState;
};

SceneJS.StencilBuf.prototype._compile = function (ctx) {
this._engine.display.stencilBuffer = coreStack[stackLen++] = this._core;
this._compileNodes(ctx);
this._engine.display.stencilBuffer = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore;
coreStack[stackLen] = null; // Release memory
};

})();

0 comments on commit 2c9ad57

Please sign in to comment.