/*
This file is part of jpcsp.
Jpcsp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jpcsp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jpcsp. If not, see <http://www.gnu.org/licenses/>.
*/
package jpcsp.graphics.RE;
import static jpcsp.graphics.VideoEngine.SIZEOF_FLOAT;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import jpcsp.graphics.Uniforms;
import jpcsp.settings.Settings;
/**
* @author gid15
*
* Implementation of the ShaderContext using Uniform Buffer Object (UBO)
* to allow a faster shader program switch.
*/
public class ShaderContextUBO extends ShaderContext {
private ShaderUniformInfo lightType;
private ShaderUniformInfo lightKind;
private ShaderUniformInfo lightEnabled;
private ShaderUniformInfo vertexColor;
private ShaderUniformInfo colorMask;
private ShaderUniformInfo notColorMask;
private ShaderUniformInfo matFlags;
private ShaderUniformInfo ctestRef;
private ShaderUniformInfo ctestMsk;
private ShaderUniformInfo texShade;
private ShaderUniformInfo texEnvMode;
private ShaderUniformInfo ctestFunc;
private ShaderUniformInfo texMapMode;
private ShaderUniformInfo texMapProj;
private ShaderUniformInfo vinfoColor;
private ShaderUniformInfo vinfoPosition;
private ShaderUniformInfo vinfoTexture;
private ShaderUniformInfo vinfoNormal;
private ShaderUniformInfo positionScale;
private ShaderUniformInfo normalScale;
private ShaderUniformInfo textureScale;
private ShaderUniformInfo weightScale;
private ShaderUniformInfo colorDoubling;
private ShaderUniformInfo texEnable;
private ShaderUniformInfo lightingEnable;
private ShaderUniformInfo vinfoTransform2D;
private ShaderUniformInfo ctestEnable;
private ShaderUniformInfo lightMode;
private ShaderUniformInfo clutShift;
private ShaderUniformInfo clutMask;
private ShaderUniformInfo clutOffset;
private ShaderUniformInfo mipmapShareClut;
private ShaderUniformInfo texPixelFormat;
private ShaderUniformInfo stencilTestEnable;
private ShaderUniformInfo stencilFunc;
private ShaderUniformInfo stencilRef;
private ShaderUniformInfo stencilMask;
private ShaderUniformInfo stencilOpFail;
private ShaderUniformInfo stencilOpZFail;
private ShaderUniformInfo stencilOpZPass;
private ShaderUniformInfo depthTestEnable;
private ShaderUniformInfo depthFunc;
private ShaderUniformInfo depthMask;
private ShaderUniformInfo alphaTestEnable;
private ShaderUniformInfo alphaTestFunc;
private ShaderUniformInfo alphaTestRef;
private ShaderUniformInfo alphaTestMask;
private ShaderUniformInfo blendTestEnable;
private ShaderUniformInfo blendEquation;
private ShaderUniformInfo blendSrc;
private ShaderUniformInfo blendDst;
private ShaderUniformInfo blendSFix;
private ShaderUniformInfo blendDFix;
private ShaderUniformInfo colorMaskEnable;
private ShaderUniformInfo wrapModeS;
private ShaderUniformInfo wrapModeT;
private ShaderUniformInfo copyRedToAlpha;
private ShaderUniformInfo fogEnable;
private ShaderUniformInfo fogColor;
private ShaderUniformInfo fogEnd;
private ShaderUniformInfo fogScale;
private ShaderUniformInfo numberBones;
private ShaderUniformInfo boneMatrix;
private ShaderUniformInfo endOfUBO;
private int bufferSize;
protected static final int bindingPoint = 1;
protected static final String uniformBlockName = "psp";
protected static final String uniformMemoryLayout = "std140";
protected int buffer;
protected ByteBuffer data;
private int startUpdate;
private int endUpdate;
private String shaderUniformText;
private ArrayList<ShaderUniformInfo> shaderUniformInfos;
private static class ShaderUniformInfo {
private String name;
private String structureName;
private String type;
private int offset;
private int matrixSize;
private boolean used;
public ShaderUniformInfo(Uniforms uniform, String type) {
name = uniform.getUniformString();
structureName = this.name;
this.type = type;
used = true;
matrixSize = 0;
}
public ShaderUniformInfo(Uniforms uniform, String type, int matrixSize) {
name = uniform.getUniformString();
structureName = String.format("%s[%d]", name, matrixSize);
this.type = type;
this.matrixSize = matrixSize;
used = true;
}
public String getName() {
return name;
}
public String getStructureName() {
return structureName;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
private String getType() {
return type;
}
public boolean isUsed() {
return used;
}
public void setUnused() {
used = false;
}
public int getMatrixSize() {
return matrixSize;
}
@Override
public String toString() {
if (!isUsed()) {
return String.format("%s(unused)", getName());
}
return String.format("%s(offset=%d)", getName(), getOffset());
}
}
public static boolean useUBO(IRenderingEngine re) {
return !Settings.getInstance().readBool("emu.disableubo")
&& re.isExtensionAvailable("GL_ARB_uniform_buffer_object");
}
public ShaderContextUBO(IRenderingEngine re) {
shaderUniformInfos = new ArrayList<ShaderUniformInfo>();
// Add all the shader uniform objects
// in the order they have to be defined in the shader structure
lightType = addShaderUniform(Uniforms.lightType, "ivec4");
lightKind = addShaderUniform(Uniforms.lightKind, "ivec4");
lightEnabled = addShaderUniform(Uniforms.lightEnabled, "ivec4");
vertexColor = addShaderUniform(Uniforms.vertexColor, "vec4");
colorMask = addShaderUniform(Uniforms.colorMask, "ivec4");
notColorMask = addShaderUniform(Uniforms.notColorMask, "ivec4");
blendSFix = addShaderUniform(Uniforms.blendSFix, "vec3");
blendDFix = addShaderUniform(Uniforms.blendDFix, "vec3");
matFlags = addShaderUniform(Uniforms.matFlags, "ivec3");
ctestRef = addShaderUniform(Uniforms.ctestRef, "ivec3");
ctestMsk = addShaderUniform(Uniforms.ctestMsk, "ivec3");
texShade = addShaderUniform(Uniforms.texShade, "ivec2");
texEnvMode = addShaderUniform(Uniforms.texEnvMode, "ivec2");
ctestFunc = addShaderUniform(Uniforms.ctestFunc, "int");
texMapMode = addShaderUniform(Uniforms.texMapMode, "int");
texMapProj = addShaderUniform(Uniforms.texMapProj, "int");
vinfoColor = addShaderUniform(Uniforms.vinfoColor, "int");
vinfoPosition = addShaderUniform(Uniforms.vinfoPosition, "int");
vinfoTexture = addShaderUniform(Uniforms.vinfoTexture, "int");
vinfoNormal = addShaderUniform(Uniforms.vinfoNormal, "int");
positionScale = addShaderUniform(Uniforms.positionScale, "float");
normalScale = addShaderUniform(Uniforms.normalScale, "float");
textureScale = addShaderUniform(Uniforms.textureScale, "float");
weightScale = addShaderUniform(Uniforms.weightScale, "float");
colorDoubling = addShaderUniform(Uniforms.colorDoubling, "float");
texEnable = addShaderUniform(Uniforms.texEnable, "bool");
lightingEnable = addShaderUniform(Uniforms.lightingEnable, "bool");
vinfoTransform2D = addShaderUniform(Uniforms.vinfoTransform2D, "bool");
ctestEnable = addShaderUniform(Uniforms.ctestEnable, "bool");
lightMode = addShaderUniform(Uniforms.lightMode, "bool");
clutShift = addShaderUniform(Uniforms.clutShift, "int");
clutMask = addShaderUniform(Uniforms.clutMask, "int");
clutOffset = addShaderUniform(Uniforms.clutOffset, "int");
mipmapShareClut = addShaderUniform(Uniforms.mipmapShareClut, "bool");
texPixelFormat = addShaderUniform(Uniforms.texPixelFormat, "int");
stencilTestEnable = addShaderUniform(Uniforms.stencilTestEnable, "bool");
stencilFunc = addShaderUniform(Uniforms.stencilFunc, "int");
stencilRef = addShaderUniform(Uniforms.stencilRef, "int");
stencilMask = addShaderUniform(Uniforms.stencilMask, "int");
stencilOpFail = addShaderUniform(Uniforms.stencilOpFail, "int");
stencilOpZFail = addShaderUniform(Uniforms.stencilOpZFail, "int");
stencilOpZPass = addShaderUniform(Uniforms.stencilOpZPass, "int");
depthTestEnable = addShaderUniform(Uniforms.depthTestEnable, "bool");
depthFunc = addShaderUniform(Uniforms.depthFunc, "int");
depthMask = addShaderUniform(Uniforms.depthMask, "int");
alphaTestEnable = addShaderUniform(Uniforms.alphaTestEnable, "bool");
alphaTestFunc = addShaderUniform(Uniforms.alphaTestFunc, "int");
alphaTestRef = addShaderUniform(Uniforms.alphaTestRef, "int");
alphaTestMask = addShaderUniform(Uniforms.alphaTestMask, "int");
blendTestEnable = addShaderUniform(Uniforms.blendTestEnable, "bool");
blendEquation = addShaderUniform(Uniforms.blendEquation, "int");
blendSrc = addShaderUniform(Uniforms.blendSrc, "int");
blendDst = addShaderUniform(Uniforms.blendDst, "int");
colorMaskEnable = addShaderUniform(Uniforms.colorMaskEnable, "bool");
wrapModeS = addShaderUniform(Uniforms.wrapModeS, "int");
wrapModeT = addShaderUniform(Uniforms.wrapModeT, "int");
copyRedToAlpha = addShaderUniform(Uniforms.copyRedToAlpha, "bool");
fogEnable = addShaderUniform(Uniforms.fogEnable, "bool");
fogColor = addShaderUniform(Uniforms.fogColor, "vec3");
fogEnd = addShaderUniform(Uniforms.fogEnd, "float");
fogScale = addShaderUniform(Uniforms.fogScale, "float");
numberBones = addShaderUniform(Uniforms.numberBones, "int");
boneMatrix = addShaderUniform(Uniforms.boneMatrix, "mat4", 8);
// The following entry has always to be the last one
endOfUBO = addShaderUniform(Uniforms.endOfUBO, "int");
StringBuilder s = new StringBuilder();
s.append(String.format("layout(%s) uniform %s\n", uniformMemoryLayout, uniformBlockName));
s.append(String.format("{\n"));
for (ShaderUniformInfo shaderUniformInfo : shaderUniformInfos) {
s.append(String.format(" %s %s;\n", shaderUniformInfo.getType(), shaderUniformInfo.getStructureName()));
}
s.append(String.format("};\n"));
shaderUniformText = s.toString();
}
protected ShaderUniformInfo addShaderUniform(Uniforms uniform, String type) {
ShaderUniformInfo shaderUniformInfo = new ShaderUniformInfo(uniform, type);
shaderUniformInfos.add(shaderUniformInfo);
return shaderUniformInfo;
}
protected ShaderUniformInfo addShaderUniform(Uniforms uniform, String type, int matrixSize) {
ShaderUniformInfo shaderUniformInfo = new ShaderUniformInfo(uniform, type, matrixSize);
shaderUniformInfos.add(shaderUniformInfo);
return shaderUniformInfo;
}
public String getShaderUniformText() {
return shaderUniformText;
}
@Override
public void initShaderProgram(IRenderingEngine re, int shaderProgram) {
int blockIndex = re.getUniformBlockIndex(shaderProgram, uniformBlockName);
// The uniform block might have been eliminated by the shader compiler
// if it was not used at all.
if (blockIndex >= 0) {
re.setUniformBlockBinding(shaderProgram, blockIndex, bindingPoint);
}
if (data == null) {
int previousOffset = -1;
for (ShaderUniformInfo shaderUniformInfo : shaderUniformInfos) {
int index = re.getUniformIndex(shaderProgram, shaderUniformInfo.getName());
int offset = re.getActiveUniformOffset(shaderProgram, index);
// Nvidia workaround: the offset of the first uniform is returned as 1 instead of 0.
if (offset == 1) {
offset = 0;
}
shaderUniformInfo.setOffset(offset);
// An unused uniform has the same offset as its previous uniform.
// An unused uniform should not be copied into the UBO buffer,
// otherwise it would overwrite the previous uniform value.
if (offset < 0 || offset == previousOffset) {
shaderUniformInfo.setUnused();
}
if (log.isDebugEnabled()) {
log.debug(String.format("Uniform %s", shaderUniformInfo));
}
previousOffset = offset;
}
// The size returned by
// glGetActiveUniformBlock(program, blockIndex, ARBUniformBufferObject.GL_UNIFORM_BLOCK_DATA_SIZE)
// is not reliable as the driver is free to reduce array sizes when they
// are not used in the shader.
// Use a dummy element of the structure to find the total structure size.
int lastOffset;
if (endOfUBO.getOffset() <= 0 || !endOfUBO.isUsed()) {
// If the endOfUBO uniform has been eliminated by the shader compiler,
// estimate the end of the buffer by using the offset of the boneMatrix uniform.
lastOffset = boneMatrix.getOffset() + boneMatrix.getMatrixSize() * 4 * 4 * SIZEOF_FLOAT;
} else {
lastOffset = endOfUBO.getOffset();
}
bufferSize = lastOffset + 4;
if (log.isDebugEnabled()) {
log.debug(String.format("UBO Structure size: %d (including endOfUBO)", bufferSize));
}
buffer = re.genBuffer();
re.bindBuffer(IRenderingEngine.RE_UNIFORM_BUFFER, buffer);
data = ByteBuffer.allocateDirect(bufferSize).order(ByteOrder.nativeOrder());
// Initialize the buffer to 0's
for (int i = 0; i < bufferSize; i++) {
data.put(i, (byte) 0);
}
re.setBufferData(IRenderingEngine.RE_UNIFORM_BUFFER, bufferSize, data, IRenderingEngine.RE_DYNAMIC_DRAW);
// On AMD hardware, the buffer data has to be set (setBufferData) before calling bindBufferBase
re.bindBufferBase(IRenderingEngine.RE_UNIFORM_BUFFER, bindingPoint, buffer);
startUpdate = 0;
endUpdate = bufferSize;
}
super.initShaderProgram(re, shaderProgram);
}
@Override
public void setUniforms(IRenderingEngine re, int shaderProgram) {
if (startUpdate < endUpdate) {
re.bindBuffer(IRenderingEngine.RE_UNIFORM_BUFFER, buffer);
data.position(startUpdate);
re.setBufferSubData(IRenderingEngine.RE_UNIFORM_BUFFER, startUpdate, endUpdate - startUpdate, data);
data.limit(data.capacity());
startUpdate = bufferSize;
endUpdate = 0;
}
// Samplers can only be passed as uniforms
setUniformsSamplers(re, shaderProgram);
}
protected void prepareCopy(int offset, int length) {
data.position(offset);
if (offset < startUpdate) {
startUpdate = offset;
}
if (offset + length > endUpdate) {
endUpdate = offset + length;
}
}
protected void copy(int value, ShaderUniformInfo shaderUniformInfo) {
// Do not copy unused uniform, to avoid overwriting other used uniforms
if (shaderUniformInfo.isUsed()) {
prepareCopy(shaderUniformInfo.getOffset(), 4);
data.putInt(value);
}
}
protected void copy(int value, ShaderUniformInfo shaderUniformInfo, int index) {
if (shaderUniformInfo.isUsed()) {
prepareCopy(shaderUniformInfo.getOffset() + index * 4, 4);
data.putInt(value);
}
}
protected void copy(float value, ShaderUniformInfo shaderUniformInfo) {
if (shaderUniformInfo.isUsed()) {
prepareCopy(shaderUniformInfo.getOffset(), 4);
data.putFloat(value);
}
}
protected void copy(float value, ShaderUniformInfo shaderUniformInfo, int index) {
if (shaderUniformInfo.isUsed()) {
prepareCopy(shaderUniformInfo.getOffset() + index * 4, 4);
data.putFloat(value);
}
}
protected void copy(float[] values, ShaderUniformInfo shaderUniformInfo, int start, int end) {
if (shaderUniformInfo.isUsed()) {
prepareCopy(shaderUniformInfo.getOffset() + start * 4, (end - start) * 4);
for (int i = start; i < end; i++) {
float value = values[i];
if (Float.isNaN(value)) {
value = 0f;
}
data.putFloat(value);
}
}
}
protected void copy(int[] values, ShaderUniformInfo shaderUniformInfo, int start, int end) {
if (shaderUniformInfo.isUsed()) {
prepareCopy(shaderUniformInfo.getOffset() + start * 4, (end - start) * 4);
for (int i = start; i < end; i++) {
data.putInt(values[i]);
}
}
}
protected void copy(boolean value, ShaderUniformInfo shaderUniformInfo) {
copy(value ? 1 : 0, shaderUniformInfo);
}
@Override
public void setTexEnable(int texEnable) {
if (texEnable != getTexEnable()) {
copy(texEnable, this.texEnable);
super.setTexEnable(texEnable);
}
}
@Override
public void setBoneMatrix(final int count, final float[] boneMatrix) {
if (count > 0) {
final float[] previousBoneMatrix = getBoneMatrix();
final int length = 16 * count;
int start = -1;
for (int i = 0; i < length; i++) {
if (previousBoneMatrix[i] != boneMatrix[i]) {
start = i;
break;
}
}
if (start >= 0) {
int end = start + 1;
for (int i = length - 1; i > start; i--) {
if (previousBoneMatrix[i] != boneMatrix[i]) {
end = i + 1;
break;
}
}
copy(boneMatrix, this.boneMatrix, start, end);
super.setBoneMatrix(count, boneMatrix);
}
}
}
@Override
public void setColorDoubling(float colorDoubling) {
if (colorDoubling != getColorDoubling()) {
copy(colorDoubling, this.colorDoubling);
super.setColorDoubling(colorDoubling);
}
}
@Override
public void setCtestEnable(int ctestEnable) {
if (ctestEnable != getCtestEnable()) {
copy(ctestEnable, this.ctestEnable);
super.setCtestEnable(ctestEnable);
}
}
@Override
public void setCtestFunc(int ctestFunc) {
if (ctestFunc != getCtestFunc()) {
copy(ctestFunc, this.ctestFunc);
super.setCtestFunc(ctestFunc);
}
}
@Override
public void setCtestMsk(int index, int ctestMsk) {
if (ctestMsk != getCtestMsk(index)) {
copy(ctestMsk, this.ctestMsk, index);
super.setCtestMsk(index, ctestMsk);
}
}
@Override
public void setCtestRef(int index, int ctestRef) {
if (ctestRef != getCtestRef(index)) {
copy(ctestRef, this.ctestRef, index);
super.setCtestRef(index, ctestRef);
}
}
@Override
public void setLightEnabled(int light, int lightEnabled) {
if (lightEnabled != getLightEnabled(light)) {
copy(lightEnabled, this.lightEnabled, light);
super.setLightEnabled(light, lightEnabled);
}
}
@Override
public void setLightingEnable(int lightingEnable) {
if (lightingEnable != getLightingEnable()) {
copy(lightingEnable, this.lightingEnable);
super.setLightingEnable(lightingEnable);
}
}
@Override
public void setLightKind(int light, int lightKind) {
if (lightKind != getLightKind(light)) {
copy(lightKind, this.lightKind, light);
super.setLightKind(light, lightKind);
}
}
@Override
public void setLightMode(int lightMode) {
if (lightMode != getLightMode()) {
copy(lightMode, this.lightMode);
super.setLightMode(lightMode);
}
}
@Override
public void setLightType(int light, int lightType) {
if (lightType != getLightType(light)) {
copy(lightType, this.lightType, light);
super.setLightType(light, lightType);
}
}
@Override
public void setMatFlags(int index, int matFlags) {
if (matFlags != getMatFlags(index)) {
copy(matFlags, this.matFlags, index);
super.setMatFlags(index, matFlags);
}
}
@Override
public void setNormalScale(float normalScale) {
if (normalScale != getNormalScale()) {
copy(normalScale, this.normalScale);
super.setNormalScale(normalScale);
}
}
@Override
public void setNumberBones(int numberBones) {
if (numberBones != getNumberBones()) {
copy(numberBones, this.numberBones);
super.setNumberBones(numberBones);
}
}
@Override
public void setPositionScale(float positionScale) {
if (positionScale != getPositionScale()) {
copy(positionScale, this.positionScale);
super.setPositionScale(positionScale);
}
}
@Override
public void setTexEnvMode(int index, int texEnvMode) {
if (texEnvMode != getTexEnvMode(index)) {
copy(texEnvMode, this.texEnvMode, index);
super.setTexEnvMode(index, texEnvMode);
}
}
@Override
public void setTexMapMode(int texMapMode) {
if (texMapMode != getTexMapMode()) {
copy(texMapMode, this.texMapMode);
super.setTexMapMode(texMapMode);
}
}
@Override
public void setTexMapProj(int texMapProj) {
if (texMapProj != getTexMapProj()) {
copy(texMapProj, this.texMapProj);
super.setTexMapProj(texMapProj);
}
}
@Override
public void setTexShade(int index, int texShade) {
if (texShade != getTexShade(index)) {
copy(texShade, this.texShade, index);
super.setTexShade(index, texShade);
}
}
@Override
public void setTextureScale(float textureScale) {
if (textureScale != getTextureScale()) {
copy(textureScale, this.textureScale);
super.setTextureScale(textureScale);
}
}
@Override
public void setVinfoColor(int vinfoColor) {
if (vinfoColor != getVinfoColor()) {
copy(vinfoColor, this.vinfoColor);
super.setVinfoColor(vinfoColor);
}
}
@Override
public void setVinfoPosition(int vinfoPosition) {
if (vinfoPosition != getVinfoPosition()) {
copy(vinfoPosition, this.vinfoPosition);
super.setVinfoPosition(vinfoPosition);
}
}
@Override
public void setVinfoTransform2D(int vinfoTransform2D) {
if (vinfoTransform2D != getVinfoTransform2D()) {
copy(vinfoTransform2D, this.vinfoTransform2D);
super.setVinfoTransform2D(vinfoTransform2D);
}
}
@Override
public void setWeightScale(float weightScale) {
if (weightScale != getWeightScale()) {
copy(weightScale, this.weightScale);
super.setWeightScale(weightScale);
}
}
@Override
public void setClutShift(int clutShift) {
if (clutShift != getClutShift()) {
copy(clutShift, this.clutShift);
super.setClutShift(clutShift);
}
}
@Override
public void setClutMask(int clutMask) {
if (clutMask != getClutMask()) {
copy(clutMask, this.clutMask);
super.setClutMask(clutMask);
}
}
@Override
public void setClutOffset(int clutOffset) {
if (clutOffset != getClutOffset()) {
copy(clutOffset, this.clutOffset);
super.setClutOffset(clutOffset);
}
}
@Override
public void setMipmapShareClut(boolean mipmapShareClut) {
if (mipmapShareClut != isMipmapShareClut()) {
copy(mipmapShareClut, this.mipmapShareClut);
super.setMipmapShareClut(mipmapShareClut);
}
}
@Override
public void setTexPixelFormat(int texPixelFormat) {
if (texPixelFormat != getTexPixelFormat()) {
copy(texPixelFormat, this.texPixelFormat);
super.setTexPixelFormat(texPixelFormat);
}
}
@Override
public void setVertexColor(float[] vertexColor) {
float[] currentVertexColor = getVertexColor();
if (vertexColor[0] != currentVertexColor[0] || vertexColor[1] != currentVertexColor[1] || vertexColor[2] != currentVertexColor[2] || vertexColor[3] != currentVertexColor[3]) {
copy(vertexColor, this.vertexColor, 0, 4);
super.setVertexColor(vertexColor);
}
}
@Override
public void setVinfoTexture(int vinfoTexture) {
if (vinfoTexture != getVinfoTexture()) {
copy(vinfoTexture, this.vinfoTexture);
super.setVinfoTexture(vinfoTexture);
}
}
@Override
public void setVinfoNormal(int vinfoNormal) {
if (vinfoNormal != getVinfoNormal()) {
copy(vinfoNormal, this.vinfoNormal);
super.setVinfoNormal(vinfoNormal);
}
}
@Override
public void setStencilTestEnable(int stencilTestEnable) {
if (stencilTestEnable != getStencilTestEnable()) {
copy(stencilTestEnable, this.stencilTestEnable);
super.setStencilTestEnable(stencilTestEnable);
}
}
@Override
public void setStencilFunc(int stencilFunc) {
if (stencilFunc != getStencilFunc()) {
copy(stencilFunc, this.stencilFunc);
super.setStencilFunc(stencilFunc);
}
}
@Override
public void setStencilMask(int stencilMask) {
if (stencilMask != getStencilMask()) {
copy(stencilMask, this.stencilMask);
super.setStencilMask(stencilMask);
}
}
@Override
public void setStencilOpFail(int stencilOpFail) {
if (stencilOpFail != getStencilOpFail()) {
copy(stencilOpFail, this.stencilOpFail);
super.setStencilOpFail(stencilOpFail);
}
}
@Override
public void setStencilOpZFail(int stencilOpZFail) {
if (stencilOpZFail != getStencilOpZFail()) {
copy(stencilOpZFail, this.stencilOpZFail);
super.setStencilOpZFail(stencilOpZFail);
}
}
@Override
public void setStencilOpZPass(int stencilOpZPass) {
if (stencilOpZPass != getStencilOpZPass()) {
copy(stencilOpZPass, this.stencilOpZPass);
super.setStencilOpZPass(stencilOpZPass);
}
}
@Override
public void setDepthTestEnable(int depthTestEnable) {
if (depthTestEnable != getDepthTestEnable()) {
copy(depthTestEnable, this.depthTestEnable);
super.setDepthTestEnable(depthTestEnable);
}
}
@Override
public void setDepthFunc(int depthFunc) {
if (depthFunc != getDepthFunc()) {
copy(depthFunc, this.depthFunc);
super.setDepthFunc(depthFunc);
}
}
@Override
public void setDepthMask(int depthMask) {
if (depthMask != getDepthMask()) {
copy(depthMask, this.depthMask);
super.setDepthMask(depthMask);
}
}
@Override
public void setStencilRef(int stencilRef) {
if (stencilRef != getStencilRef()) {
copy(stencilRef, this.stencilRef);
super.setStencilRef(stencilRef);
}
}
@Override
public void setColorMaskEnable(int colorMaskEnable) {
if (colorMaskEnable != getColorMaskEnable()) {
copy(colorMaskEnable, this.colorMaskEnable);
super.setColorMaskEnable(colorMaskEnable);
}
}
@Override
public void setColorMask(int redMask, int greenMask, int blueMask, int alphaMask) {
int[] currentColorMask = getColorMask();
if (redMask != currentColorMask[0] || greenMask != currentColorMask[1] || blueMask != currentColorMask[2] || alphaMask != currentColorMask[3]) {
copy(new int[] { redMask, greenMask, blueMask, alphaMask }, this.colorMask, 0, 4);
super.setColorMask(redMask, greenMask, blueMask, alphaMask);
}
}
@Override
public void setNotColorMask(int notRedMask, int notGreenMask, int notBlueMask, int notAlphaMask) {
int[] currentNotColorMask = getNotColorMask();
if (notRedMask != currentNotColorMask[0] || notGreenMask != currentNotColorMask[1] || notBlueMask != currentNotColorMask[2] || notAlphaMask != currentNotColorMask[3]) {
copy(new int[] { notRedMask, notGreenMask, notBlueMask, notAlphaMask }, this.notColorMask, 0, 4);
super.setNotColorMask(notRedMask, notGreenMask, notBlueMask, notAlphaMask);
}
}
@Override
public void setAlphaTestEnable(int alphaTestEnable) {
if (alphaTestEnable != getAlphaTestEnable()) {
copy(alphaTestEnable, this.alphaTestEnable);
super.setAlphaTestEnable(alphaTestEnable);
}
}
@Override
public void setAlphaTestFunc(int alphaTestFunc) {
if (alphaTestFunc != getAlphaTestFunc()) {
copy(alphaTestFunc, this.alphaTestFunc);
super.setAlphaTestFunc(alphaTestFunc);
}
}
@Override
public void setAlphaTestRef(int alphaTestRef) {
if (alphaTestRef != getAlphaTestRef()) {
copy(alphaTestRef, this.alphaTestRef);
super.setAlphaTestRef(alphaTestRef);
}
}
@Override
public void setAlphaTestMask(int alphaTestMask) {
if (alphaTestMask != getAlphaTestMask()) {
copy(alphaTestMask, this.alphaTestMask);
super.setAlphaTestMask(alphaTestMask);
}
}
@Override
public void setBlendTestEnable(int blendTestEnable) {
if (blendTestEnable != getBlendTestEnable()) {
copy(blendTestEnable, this.blendTestEnable);
super.setBlendTestEnable(blendTestEnable);
}
}
@Override
public void setBlendEquation(int blendEquation) {
if (blendEquation != getBlendEquation()) {
copy(blendEquation, this.blendEquation);
super.setBlendEquation(blendEquation);
}
}
@Override
public void setBlendSrc(int blendSrc) {
if (blendSrc != getBlendSrc()) {
copy(blendSrc, this.blendSrc);
super.setBlendSrc(blendSrc);
}
}
@Override
public void setBlendDst(int blendDst) {
if (blendDst != getBlendDst()) {
copy(blendDst, this.blendDst);
super.setBlendDst(blendDst);
}
}
@Override
public void setBlendSFix(float[] blendSFix) {
float[] sfix = getBlendSFix();
if (blendSFix[0] != sfix[0] || blendSFix[1] != sfix[1] || blendSFix[2] != sfix[2]) {
copy(blendSFix, this.blendSFix, 0, 3);
super.setBlendSFix(blendSFix);
}
}
@Override
public void setBlendDFix(float[] blendDFix) {
float[] dfix = getBlendDFix();
if (blendDFix[0] != dfix[0] || blendDFix[1] != dfix[1] || blendDFix[2] != dfix[2]) {
copy(blendDFix, this.blendDFix, 0, 3);
super.setBlendDFix(blendDFix);
}
}
@Override
public void setCopyRedToAlpha(int copyRedToAlpha) {
if (copyRedToAlpha != getCopyRedToAlpha()) {
copy(copyRedToAlpha, this.copyRedToAlpha);
super.setCopyRedToAlpha(copyRedToAlpha);
}
}
@Override
public void setWrapModeS(int wrapModeS) {
if (wrapModeS != getWrapModeS()) {
copy(wrapModeS, this.wrapModeS);
super.setWrapModeS(wrapModeS);
}
}
@Override
public void setWrapModeT(int wrapModeT) {
if (wrapModeT != getWrapModeT()) {
copy(wrapModeT, this.wrapModeT);
super.setWrapModeT(wrapModeT);
}
}
@Override
public void setFogEnable(int fogEnable) {
if (fogEnable != getFogEnable()) {
copy(fogEnable, this.fogEnable);
super.setFogEnable(fogEnable);
}
}
@Override
public void setFogColor(float[] fogColor) {
float[] currentFogColor = getFogColor();
if (fogColor[0] != currentFogColor[0] || fogColor[1] != currentFogColor[1] || fogColor[2] != currentFogColor[2]) {
copy(fogColor, this.fogColor, 0, 3);
super.setFogColor(fogColor);
}
}
@Override
public void setFogEnd(float fogEnd) {
if (fogEnd != getFogEnd()) {
copy(fogEnd, this.fogEnd);
super.setFogEnd(fogEnd);
}
}
@Override
public void setFogScale(float fogScale) {
if (fogScale != getFogScale()) {
copy(fogScale, this.fogScale);
super.setFogScale(fogScale);
}
}
}