/*
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 java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import jpcsp.graphics.GeCommands;
import jpcsp.graphics.VideoEngine;
/**
* @author gid15
*
* RenderingEngine Proxy class removing redundant calls.
* E.g. calls setting multiple times the same value,
* or calls with an invalid parameter (e.g. for unused shader uniforms).
* This class implements no rendering logic, it just skips unnecessary calls.
*/
public class StateProxy extends BaseRenderingEngineProxy {
protected boolean[] flags;
protected float[][] matrix;
protected static final int RE_BONES_MATRIX = 4;
protected static final int matrix4Size = 4 * 4;
public static final int maxProgramId = 5000;
public static final int maxUniformId = 200;
protected int[][] uniformInt;
protected int[][][] uniformIntArray;
protected float[][] uniformFloat;
protected float[][][] uniformFloatArray;
protected StateBoolean[] clientState;
protected StateBoolean[] vertexAttribArray;
protected boolean colorMaskRed;
protected boolean colorMaskGreen;
protected boolean colorMaskBlue;
protected boolean colorMaskAlpha;
protected int[] colorMask;
protected boolean depthMask;
protected int textureFunc;
protected boolean textureFuncAlpha;
protected boolean textureFuncColorDouble;
protected boolean frontFace;
protected int stencilFunc;
protected int stencilFuncRef;
protected int stencilFuncMask;
protected int stencilOpFail;
protected int stencilOpZFail;
protected int stencilOpZPass;
protected int depthFunc;
protected int[] bindTexture;
protected int[] bindBuffer;
protected int useProgram;
protected int textureMapMode;
protected int textureProjMapMode;
protected int viewportX;
protected int viewportY;
protected int viewportWidth;
protected int viewportHeight;
protected HashMap<Integer, int[]> bufferDataInt;
protected HashMap<Integer, TextureState> textureStates;
protected TextureState currentTextureState;
protected int matrixMode;
protected boolean fogHintSet;
protected boolean lineSmoothHintSet;
protected float[] texEnvf;
protected int[] texEnvi;
protected int pixelStoreRowLength;
protected int pixelStoreAlignment;
protected int scissorX;
protected int scissorY;
protected int scissorWidth;
protected int scissorHeight;
protected int blendEquation;
protected int shadeModel;
protected int alphaFunc;
protected int alphaFuncRef;
protected int alphaFuncMask;
protected float depthRangeZpos;
protected float depthRangeZscale;
protected int depthRangeNear;
protected int depthRangeFar;
protected float[] vertexColor;
protected float[][] lightAmbientColor;
protected float[][] lightDiffuseColor;
protected float[][] lightSpecularColor;
protected float[] lightModelAmbientColor;
protected int lightMode;
protected float[] materialAmbientColor;
protected float[] materialDiffuseColor;
protected float[] materialSpecularColor;
protected float[] materialEmissiveColor;
protected StateBoolean colorMaterialAmbient;
protected StateBoolean colorMaterialDiffuse;
protected StateBoolean colorMaterialSpecular;
protected int bindVertexArray;
protected int activeTextureUnit;
protected boolean useTextureAnisotropicFilter;
protected int dfix;
protected int sfix;
protected int bindFramebufferRead;
protected int bindFramebufferDraw;
protected static class StateBoolean {
private boolean undefined = true;
private boolean value;
public boolean isUndefined() {
return undefined;
}
public void setUndefined() {
undefined = true;
}
public boolean getValue() {
return value;
}
public void setValue(boolean value) {
this.value = value;
undefined = false;
}
public boolean isTrue() {
return !undefined && value;
}
public boolean isFalse() {
return !undefined && !value;
}
public boolean isValue(boolean value) {
return !undefined && this.value == value;
}
@Override
public String toString() {
if (isUndefined()) {
return "Undefined";
}
return Boolean.toString(getValue());
}
}
protected static class TextureState {
public int textureWrapModeS = -1;
public int textureWrapModeT = -1;
public int textureMipmapMinFilter = GeCommands.TFLT_NEAREST_MIPMAP_LINEAR;
public int textureMipmapMagFilter = GeCommands.TFLT_LINEAR;
public int textureMipmapMinLevel = 0;
public int textureMipmapMaxLevel = 1000;
public float textureAnisotropy = 0;
}
public StateProxy(IRenderingEngine proxy) {
super(proxy);
init();
}
protected void init() {
flags = new boolean[RE_NUMBER_FLAGS];
uniformInt = new int[maxProgramId][maxUniformId];
uniformFloat = new float[maxProgramId][maxUniformId];
uniformIntArray = new int[maxProgramId][maxUniformId][];
uniformFloatArray = new float[maxProgramId][maxUniformId][];
for (int i = 0; i < maxProgramId; i++) {
for (int j = 0; j < maxUniformId; j++) {
uniformInt[i][j] = -1;
uniformFloat[i][j] = -1f;
}
}
matrix = new float[RE_BONES_MATRIX + 1][];
matrix[GU_PROJECTION] = new float[matrix4Size];
matrix[GU_VIEW] = new float[matrix4Size];
matrix[GU_MODEL] = new float[matrix4Size];
matrix[GU_TEXTURE] = new float[matrix4Size];
matrix[RE_BONES_MATRIX] = new float[8 * matrix4Size];
clientState = new StateBoolean[4];
for (int i = 0; i < clientState.length; i++) {
clientState[i] = new StateBoolean();
}
vertexAttribArray = new StateBoolean[maxUniformId];
for (int i = 0; i < vertexAttribArray.length; i++) {
vertexAttribArray[i] = new StateBoolean();
}
colorMask = new int[4];
bufferDataInt = new HashMap<Integer, int[]>();
textureStates = new HashMap<Integer, TextureState>();
currentTextureState = new TextureState();
textureStates.put(0, currentTextureState);
texEnvf = new float[17];
texEnvi = new int[17];
vertexColor = new float[4];
bindBuffer = new int[3];
lightAmbientColor = new float[4][4];
lightSpecularColor = new float[4][4];
lightDiffuseColor = new float[4][4];
lightModelAmbientColor = new float[4];
materialAmbientColor = new float[4];
materialSpecularColor = new float[4];
materialDiffuseColor = new float[4];
materialEmissiveColor = new float[4];
bindTexture = new int[4]; // assume max 4 active texture units
colorMaterialAmbient = new StateBoolean();
colorMaterialDiffuse = new StateBoolean();
colorMaterialSpecular = new StateBoolean();
}
@Override
public void startDisplay() {
// The following properties are lost when starting a new display
for (int i = 0; i < clientState.length; i++) {
clientState[i].setUndefined();
}
for (int i = 0; i < flags.length; i++) {
flags[i] = true;
}
flags[GU_TEXTURE_2D] = false;
System.arraycopy(identityMatrix, 0, matrix[GU_PROJECTION], 0, matrix4Size);
System.arraycopy(identityMatrix, 0, matrix[GU_VIEW], 0, matrix4Size);
System.arraycopy(identityMatrix, 0, matrix[GU_MODEL], 0, matrix4Size);
System.arraycopy(identityMatrix, 0, matrix[GU_TEXTURE], 0, matrix4Size);
colorMaskRed = true;
colorMaskGreen = true;
colorMaskBlue = true;
colorMaskAlpha = true;
depthMask = true;
textureFunc = -1;
textureFuncAlpha = true;
textureFuncColorDouble = false;
frontFace = true;
stencilFunc = -1;
stencilFuncRef = -1;
stencilFuncMask = -1;
stencilOpFail = -1;
stencilOpZFail = -1;
stencilOpZPass = -1;
depthFunc = -1;
for (int i = 0; i < bindTexture.length; i++) {
bindTexture[i] = -1;
}
currentTextureState = textureStates.get(0);
for (int i = 0; i < bindBuffer.length; i++) {
bindBuffer[i] = -1;
}
activeTextureUnit = 0;
frontFace = false;
useProgram = 0;
textureMapMode = -1;
textureProjMapMode = -1;
viewportX = -1;
viewportY = -1;
viewportWidth = -1;
viewportHeight = -1;
matrixMode = -1;
fogHintSet = false;
lineSmoothHintSet = false;
for (int i = 0; i < texEnvi.length; i++) {
texEnvi[i] = -1;
}
for (int i = 0; i < texEnvf.length; i++) {
texEnvf[i] = -1;
}
// Default OpenGL texEnv values
texEnvf[IRenderingEngine.RE_TEXENV_RGB_SCALE] = 1.f;
texEnvi[IRenderingEngine.RE_TEXENV_ENV_MODE] = IRenderingEngine.RE_TEXENV_MODULATE;
pixelStoreRowLength = -1;
pixelStoreAlignment = -1;
scissorX = -1;
scissorY = -1;
scissorWidth = -1;
scissorHeight = -1;
blendEquation = -1;
shadeModel = -1;
alphaFunc = -1;
alphaFuncRef = -1;
depthRangeZpos = 0.f;
depthRangeZscale = 0.f;
depthRangeNear = -1;
depthRangeFar = -1;
vertexColor[0] = -1.f;
for (int i = 0; i < lightAmbientColor.length; i++) {
lightAmbientColor[i][0] = -1.f;
lightDiffuseColor[i][0] = -1.f;
lightSpecularColor[i][0] = -1.f;
}
lightModelAmbientColor[0] = -1.f;
lightMode = -1;
materialAmbientColor[0] = -10000.f;
materialDiffuseColor[0] = -1.f;
materialSpecularColor[0] = -1.f;
materialEmissiveColor[0] = -1.f;
colorMaterialAmbient.setUndefined();
colorMaterialDiffuse.setUndefined();
colorMaterialSpecular.setUndefined();
bindVertexArray = 0;
bindFramebufferRead = -1;
bindFramebufferDraw = -1;
if (VideoEngine.getInstance().isUseTextureAnisotropicFilter() != useTextureAnisotropicFilter) {
// The texture anisotropic filter has been changed,
// invalidate all the texture magnification filters
for (TextureState textureState : textureStates.values()) {
textureState.textureMipmapMagFilter = -1;
}
useTextureAnisotropicFilter = VideoEngine.getInstance().isUseTextureAnisotropicFilter();
}
super.startDisplay();
}
@Override
public void disableFlag(int flag) {
if (flags[flag]) {
super.disableFlag(flag);
flags[flag] = false;
}
}
@Override
public void enableFlag(int flag) {
if (!flags[flag]) {
super.enableFlag(flag);
flags[flag] = true;
}
}
@Override
public void setUniform(int id, int value) {
// An unused uniform as an id == -1
if (id >= 0 && id <= maxUniformId) {
if (uniformInt[useProgram][id] != value) {
super.setUniform(id, value);
uniformInt[useProgram][id] = value;
}
}
}
@Override
public void setUniform(int id, float value) {
if (id >= 0 && id <= maxUniformId) {
if (uniformFloat[useProgram][id] != value) {
super.setUniform(id, value);
uniformFloat[useProgram][id] = value;
}
}
}
@Override
public void setUniform(int id, int value1, int value2) {
if (id >= 0 && id <= maxUniformId) {
int[] oldValues = uniformIntArray[useProgram][id];
if (oldValues == null || oldValues.length != 2) {
super.setUniform(id, value1, value2);
uniformIntArray[useProgram][id] = new int[] { value1, value2 };
} else {
if (oldValues[0] != value1 || oldValues[1] != value2) {
super.setUniform(id, value1, value2);
oldValues[0] = value1;
oldValues[1] = value2;
}
}
}
}
@Override
public void setUniform2(int id, int[] values) {
if (id >= 0 && id <= maxUniformId) {
int[] oldValues = uniformIntArray[useProgram][id];
if (oldValues == null || oldValues.length != 2) {
super.setUniform2(id, values);
oldValues = new int[2];
oldValues[0] = values[0];
oldValues[1] = values[1];
uniformIntArray[useProgram][id] = oldValues;
} else if (oldValues[0] != values[0] || oldValues[1] != values[1]) {
super.setUniform2(id, values);
oldValues[0] = values[0];
oldValues[1] = values[1];
}
}
}
@Override
public void setUniform3(int id, int[] values) {
if (id >= 0 && id <= maxUniformId) {
int[] oldValues = uniformIntArray[useProgram][id];
if (oldValues == null || oldValues.length != 3) {
super.setUniform3(id, values);
oldValues = new int[3];
oldValues[0] = values[0];
oldValues[1] = values[1];
oldValues[2] = values[2];
uniformIntArray[useProgram][id] = oldValues;
} else if (oldValues[0] != values[0] || oldValues[1] != values[1] || oldValues[2] != values[2]) {
super.setUniform3(id, values);
oldValues[0] = values[0];
oldValues[1] = values[1];
oldValues[2] = values[2];
}
}
}
@Override
public void setUniform4(int id, int[] values) {
if (id >= 0 && id <= maxUniformId) {
int[] oldValues = uniformIntArray[useProgram][id];
if (oldValues == null || oldValues.length != 4) {
super.setUniform4(id, values);
oldValues = new int[4];
oldValues[0] = values[0];
oldValues[1] = values[1];
oldValues[2] = values[2];
oldValues[3] = values[3];
uniformIntArray[useProgram][id] = oldValues;
} else if (oldValues[0] != values[0] || oldValues[1] != values[1] || oldValues[2] != values[2] || oldValues[3] != values[3]) {
super.setUniform4(id, values);
oldValues[0] = values[0];
oldValues[1] = values[1];
oldValues[2] = values[2];
oldValues[3] = values[3];
}
}
}
@Override
public void setUniformMatrix4(int id, int count, float[] values) {
if (id >= 0 && id <= maxUniformId && count > 0) {
float[] oldValues = uniformFloatArray[useProgram][id];
int length = count * matrix4Size;
if (oldValues == null || oldValues.length < length) {
super.setUniformMatrix4(id, count, values);
oldValues = new float[length];
System.arraycopy(values, 0, oldValues, 0, length);
uniformFloatArray[useProgram][id] = oldValues;
} else {
boolean differ = false;
for (int i = 0; i < length; i++) {
if (oldValues[i] != values[i]) {
differ = true;
break;
}
}
if (differ) {
super.setUniformMatrix4(id, count, values);
System.arraycopy(values, 0, oldValues, 0, length);
}
}
}
}
protected int matrixFirstUpdated(int id, float[] values) {
if (values == null) {
values = identityMatrix;
}
float[] oldValues = matrix[id];
for (int i = 0; i < values.length; i++) {
if (values[i] != oldValues[i]) {
// Update the remaining values
System.arraycopy(values, i, oldValues, i, values.length - i);
return i;
}
}
return values.length;
}
protected int matrixLastUpdated(int id, float[] values, int length) {
float[] oldValues = matrix[id];
if (values == null) {
values = identityMatrix;
}
for (int i = length - 1; i >= 0; i--) {
if (oldValues[i] != values[i]) {
// Update the remaining values
System.arraycopy(values, 0, oldValues, 0, i + 1);
return i;
}
}
return 0;
}
protected boolean isIdentityMatrix(float[] values) {
if (values == null) {
return true;
}
if (values.length != identityMatrix.length) {
return false;
}
for (int i = 0; i < identityMatrix.length; i++) {
if (values[i] != identityMatrix[i]) {
return false;
}
}
return true;
}
@Override
public void disableClientState(int type) {
StateBoolean state = clientState[type];
if (!state.isFalse()) {
super.disableClientState(type);
state.setValue(false);
}
}
@Override
public void enableClientState(int type) {
// enableClientState(RE_VERTEX) cannot be cached: it is required each time
// by OpenGL and seems to trigger the correct Vertex generation.
StateBoolean state = clientState[type];
if (type == RE_VERTEX || !state.isTrue()) {
super.enableClientState(type);
state.setValue(true);
}
}
@Override
public void disableVertexAttribArray(int id) {
if (id >= 0 && id <= maxUniformId) {
StateBoolean state = vertexAttribArray[id];
if (!state.isFalse()) {
super.disableVertexAttribArray(id);
state.setValue(false);
}
}
}
@Override
public void enableVertexAttribArray(int id) {
if (id >= 0 && id <= maxUniformId) {
StateBoolean state = vertexAttribArray[id];
if (!state.isTrue()) {
super.enableVertexAttribArray(id);
state.setValue(true);
}
}
}
@Override
public void setColorMask(boolean redWriteEnabled, boolean greenWriteEnabled, boolean blueWriteEnabled, boolean alphaWriteEnabled) {
if (redWriteEnabled != colorMaskRed || greenWriteEnabled != colorMaskGreen || blueWriteEnabled != colorMaskBlue || alphaWriteEnabled != colorMaskAlpha) {
super.setColorMask(redWriteEnabled, greenWriteEnabled, blueWriteEnabled, alphaWriteEnabled);
colorMaskRed = redWriteEnabled;
colorMaskGreen = greenWriteEnabled;
colorMaskBlue = blueWriteEnabled;
colorMaskAlpha = alphaWriteEnabled;
// Force a reload of the real color mask
colorMask[0] = -1;
colorMask[1] = -1;
colorMask[2] = -1;
colorMask[3] = -1;
}
}
@Override
public void setColorMask(int redMask, int greenMask, int blueMask, int alphaMask) {
if (redMask != colorMask[0] || greenMask != colorMask[1] || blueMask != colorMask[2] || alphaMask != colorMask[3]) {
super.setColorMask(redMask, greenMask, blueMask, alphaMask);
// colorMaskRed = redMask != 0xFF;
// colorMaskGreen = greenMask != 0xFF;
// colorMaskBlue = blueMask != 0xFF;
// colorMaskAlpha = alphaMask != 0xFF;
colorMask[0] = redMask;
colorMask[1] = greenMask;
colorMask[2] = blueMask;
colorMask[3] = alphaMask;
}
}
@Override
public void setDepthMask(boolean depthWriteEnabled) {
if (depthWriteEnabled != depthMask) {
super.setDepthMask(depthWriteEnabled);
depthMask = depthWriteEnabled;
}
}
@Override
public void setFrontFace(boolean cw) {
if (cw != frontFace) {
super.setFrontFace(cw);
frontFace = cw;
}
}
@Override
public void setTextureFunc(int func, boolean alphaUsed, boolean colorDoubled) {
if (func != textureFunc || alphaUsed != textureFuncAlpha || colorDoubled != textureFuncColorDouble) {
super.setTextureFunc(func, alphaUsed, colorDoubled);
textureFunc = func;
textureFuncAlpha = alphaUsed;
textureFuncColorDouble = colorDoubled;
}
}
@Override
public void setTextureMipmapMinFilter(int filter) {
if (filter != currentTextureState.textureMipmapMinFilter) {
super.setTextureMipmapMinFilter(filter);
currentTextureState.textureMipmapMinFilter = filter;
}
}
@Override
public void setTextureMipmapMagFilter(int filter) {
if (filter != currentTextureState.textureMipmapMagFilter) {
super.setTextureMipmapMagFilter(filter);
currentTextureState.textureMipmapMagFilter = filter;
}
}
@Override
public void setTextureMipmapMinLevel(int level) {
if (level != currentTextureState.textureMipmapMinLevel) {
super.setTextureMipmapMinLevel(level);
currentTextureState.textureMipmapMinLevel = level;
}
}
@Override
public void setTextureMipmapMaxLevel(int level) {
if (level != currentTextureState.textureMipmapMaxLevel) {
super.setTextureMipmapMaxLevel(level);
currentTextureState.textureMipmapMaxLevel = level;
}
}
@Override
public void setTextureWrapMode(int s, int t) {
if (s != currentTextureState.textureWrapModeS || t != currentTextureState.textureWrapModeT) {
super.setTextureWrapMode(s, t);
currentTextureState.textureWrapModeS = s;
currentTextureState.textureWrapModeT = t;
}
}
@Override
public void bindTexture(int texture) {
if (texture != bindTexture[activeTextureUnit]) {
super.bindTexture(texture);
bindTexture[activeTextureUnit] = texture;
// Binding a new texture change the OpenGL texture wrap mode and min/mag filters
currentTextureState = textureStates.get(texture);
if (currentTextureState == null) {
currentTextureState = new TextureState();
textureStates.put(texture, currentTextureState);
}
}
}
@Override
public void setDepthFunc(int func) {
if (func != depthFunc) {
super.setDepthFunc(func);
depthFunc = func;
}
}
@Override
public void setStencilFunc(int func, int ref, int mask) {
if (func != stencilFunc || ref != stencilFuncRef || mask != stencilFuncMask) {
super.setStencilFunc(func, ref, mask);
stencilFunc = func;
stencilFuncRef = ref;
stencilFuncMask = mask;
}
}
@Override
public void setStencilOp(int fail, int zfail, int zpass) {
if (fail != stencilOpFail || zfail != stencilOpZFail || zpass != stencilOpZPass) {
super.setStencilOp(fail, zfail, zpass);
stencilOpFail = fail;
stencilOpZFail = zfail;
stencilOpZPass = zpass;
}
}
@Override
public void deleteTexture(int texture) {
textureStates.remove(texture);
// When deleting the current texture, the current binding is reset to 0
for (int i = 0; i < bindTexture.length; i++) {
if (texture == bindTexture[i]) {
bindTexture[i] = 0;
if (i == activeTextureUnit) {
currentTextureState = textureStates.get(bindTexture[activeTextureUnit]);
}
}
}
super.deleteTexture(texture);
}
@Override
public void bindBuffer(int target, int buffer) {
if (bindBuffer[target] != buffer) {
super.bindBuffer(target, buffer);
bindBuffer[target] = buffer;
}
}
@Override
public void deleteBuffer(int buffer) {
// When deleting the current buffer, the current binding is reset to 0
for (int target = 0; target < bindBuffer.length; target++) {
if (buffer == bindBuffer[target]) {
bindBuffer[target] = 0;
}
}
super.deleteBuffer(buffer);
}
@Override
public void setViewport(int x, int y, int width, int height) {
// Negative x and y values are valid values
if (width >= 0 && height >= 0) {
if (x != viewportX || y != viewportY || width != viewportWidth || height != viewportHeight) {
super.setViewport(x, y, width, height);
viewportX = x;
viewportY = y;
viewportWidth = width;
viewportHeight = height;
}
}
}
@Override
public void useProgram(int program) {
if (useProgram != program) {
super.useProgram(program);
useProgram = program;
}
}
@Override
public void setTextureMapMode(int mode, int proj) {
if (mode != textureMapMode || proj != textureProjMapMode) {
super.setTextureMapMode(mode, proj);
textureMapMode = mode;
textureProjMapMode = proj;
}
}
private void setBufferData(int target, int size, IntBuffer buffer, int usage) {
int[] oldData = bufferDataInt.get(bindBuffer[target]);
int[] newData = new int[size / 4];
int position = buffer.position();
buffer.get(newData);
buffer.position(position);
boolean differ = true;
boolean setBufferData = true;
if (oldData != null && newData.length == oldData.length) {
differ = false;
setBufferData = false;
int limit = buffer.limit();
for (int i = 0; i < newData.length; i++) {
if (newData[i] != oldData[i]) {
differ = true;
int end = i + 1;
for (int j = i + 1; j < newData.length; j++) {
if (newData[j] == oldData[j]) {
end = j;
break;
}
}
buffer.position(i);
super.setBufferSubData(target, i * 4, (end - i) * 4, buffer);
buffer.limit(limit);
i = end;
}
}
}
if (setBufferData) {
super.setBufferData(target, size, buffer, usage);
}
if (differ) {
bufferDataInt.put(bindBuffer[target], newData);
}
}
@Override
public void setBufferData(int target, int size, Buffer buffer, int usage) {
if (target == RE_UNIFORM_BUFFER && size <= 1024 && (size & 3) == 0 && buffer instanceof IntBuffer) {
setBufferData(target, size, (IntBuffer) buffer, usage);
} else if (target == RE_UNIFORM_BUFFER && size <= 1024 && (size & 3) == 0 && buffer instanceof ByteBuffer) {
setBufferData(target, size, ((ByteBuffer) buffer).asIntBuffer(), usage);
} else {
super.setBufferData(target, size, buffer, usage);
}
}
@Override
public void setMatrixMode(int type) {
if (type != matrixMode) {
super.setMatrixMode(type);
matrixMode = type;
}
}
@Override
public void setMatrix(float[] values) {
if (matrixFirstUpdated(matrixMode, values) < matrix4Size) {
if (isIdentityMatrix(values)) {
// Identity Matrix is identified by the special value "null"
super.setMatrix(null);
} else {
super.setMatrix(values);
}
}
}
@Override
public void multMatrix(float[] values) {
if (!isIdentityMatrix(values)) {
super.multMatrix(values);
}
}
@Override
public void setFogHint() {
if (!fogHintSet) {
super.setFogHint();
fogHintSet = true;
}
}
@Override
public void setLineSmoothHint() {
if (!lineSmoothHintSet) {
super.setLineSmoothHint();
lineSmoothHintSet = true;
}
}
@Override
public void setTexEnv(int name, float param) {
if (texEnvf[name] != param) {
super.setTexEnv(name, param);
texEnvf[name] = param;
}
}
@Override
public void setTexEnv(int name, int param) {
if (texEnvi[name] != param) {
super.setTexEnv(name, param);
texEnvi[name] = param;
}
}
@Override
public void setPixelStore(int rowLength, int alignment) {
if (pixelStoreRowLength != rowLength || pixelStoreAlignment != alignment) {
super.setPixelStore(rowLength, alignment);
pixelStoreRowLength = rowLength;
pixelStoreAlignment = alignment;
}
}
@Override
public void setScissor(int x, int y, int width, int height) {
if (x >= 0 && y >= 0 && width >= 0 && height >= 0) {
if (x != scissorX || y != scissorY || width != scissorWidth || height != scissorHeight) {
super.setScissor(x, y, width, height);
scissorX = x;
scissorY = y;
scissorWidth = width;
scissorHeight = height;
}
}
}
@Override
public void setBlendEquation(int mode) {
if (blendEquation != mode) {
super.setBlendEquation(mode);
blendEquation = mode;
}
}
@Override
public void setShadeModel(int model) {
if (shadeModel != model) {
super.setShadeModel(model);
shadeModel = model;
}
}
@Override
public void setAlphaFunc(int func, int ref, int mask) {
if (alphaFunc != func || alphaFuncRef != ref || alphaFuncMask != mask) {
super.setAlphaFunc(func, ref, mask);
alphaFunc = func;
alphaFuncRef = ref;
alphaFuncMask = mask;
}
}
@Override
public void setDepthRange(float zpos, float zscale, int near, int far) {
if (depthRangeZpos != zpos || depthRangeZscale != zscale || depthRangeNear != near || depthRangeFar != far) {
super.setDepthRange(zpos, zscale, near, far);
depthRangeZpos = zpos;
depthRangeZscale = zscale;
depthRangeNear = near;
depthRangeFar = far;
}
}
@Override
public void setVertexColor(float[] color) {
if (vertexColor[0] != color[0] || vertexColor[1] != color[1] || vertexColor[2] != color[2] || vertexColor[3] != color[3]) {
super.setVertexColor(color);
vertexColor[0] = color[0];
vertexColor[1] = color[1];
vertexColor[2] = color[2];
vertexColor[3] = color[3];
}
}
@Override
public void setLightAmbientColor(int light, float[] color) {
float[] stateColor = lightAmbientColor[light];
if (stateColor[0] != color[0] || stateColor[1] != color[1] || stateColor[2] != color[2] || stateColor[3] != color[3]) {
super.setLightAmbientColor(light, color);
stateColor[0] = color[0];
stateColor[1] = color[1];
stateColor[2] = color[2];
stateColor[3] = color[3];
}
}
@Override
public void setLightDiffuseColor(int light, float[] color) {
float[] stateColor = lightDiffuseColor[light];
if (stateColor[0] != color[0] || stateColor[1] != color[1] || stateColor[2] != color[2] || stateColor[3] != color[3]) {
super.setLightDiffuseColor(light, color);
stateColor[0] = color[0];
stateColor[1] = color[1];
stateColor[2] = color[2];
stateColor[3] = color[3];
}
}
@Override
public void setLightSpecularColor(int light, float[] color) {
float[] stateColor = lightSpecularColor[light];
if (stateColor[0] != color[0] || stateColor[1] != color[1] || stateColor[2] != color[2] || stateColor[3] != color[3]) {
super.setLightSpecularColor(light, color);
stateColor[0] = color[0];
stateColor[1] = color[1];
stateColor[2] = color[2];
stateColor[3] = color[3];
}
}
@Override
public void setMaterialAmbientColor(float[] color) {
if (materialAmbientColor[0] != color[0] || materialAmbientColor[1] != color[1] || materialAmbientColor[2] != color[2] || materialAmbientColor[3] != color[3]) {
super.setMaterialAmbientColor(color);
materialAmbientColor[0] = color[0];
materialAmbientColor[1] = color[1];
materialAmbientColor[2] = color[2];
materialAmbientColor[3] = color[3];
}
}
@Override
public void setMaterialDiffuseColor(float[] color) {
if (materialDiffuseColor[0] != color[0] || materialDiffuseColor[1] != color[1] || materialDiffuseColor[2] != color[2] || materialDiffuseColor[3] != color[3]) {
super.setMaterialDiffuseColor(color);
materialDiffuseColor[0] = color[0];
materialDiffuseColor[1] = color[1];
materialDiffuseColor[2] = color[2];
materialDiffuseColor[3] = color[3];
}
}
@Override
public void setMaterialEmissiveColor(float[] color) {
if (materialEmissiveColor[0] != color[0] || materialEmissiveColor[1] != color[1] || materialEmissiveColor[2] != color[2] || materialEmissiveColor[3] != color[3]) {
super.setMaterialEmissiveColor(color);
materialEmissiveColor[0] = color[0];
materialEmissiveColor[1] = color[1];
materialEmissiveColor[2] = color[2];
materialEmissiveColor[3] = color[3];
}
}
@Override
public void setMaterialSpecularColor(float[] color) {
if (materialSpecularColor[0] != color[0] || materialSpecularColor[1] != color[1] || materialSpecularColor[2] != color[2] || materialSpecularColor[3] != color[3]) {
super.setMaterialSpecularColor(color);
materialSpecularColor[0] = color[0];
materialSpecularColor[1] = color[1];
materialSpecularColor[2] = color[2];
materialSpecularColor[3] = color[3];
}
}
@Override
public void setColorMaterial(boolean ambient, boolean diffuse, boolean specular) {
if (!colorMaterialAmbient.isValue(ambient) || !colorMaterialDiffuse.isValue(diffuse) || !colorMaterialSpecular.isValue(specular)) {
super.setColorMaterial(ambient, diffuse, specular);
colorMaterialAmbient.setValue(ambient);
colorMaterialDiffuse.setValue(diffuse);
colorMaterialSpecular.setValue(specular);
}
}
private void invalidateMaterialColors() {
// Drawing with "color material" enabled overwrites the material colors
if (flags[IRenderingEngine.RE_COLOR_MATERIAL]) {
if (colorMaterialAmbient.isTrue()) {
materialAmbientColor[0] = -1.f;
}
if (colorMaterialDiffuse.isTrue()) {
materialDiffuseColor[0] = -1.f;
}
if (colorMaterialSpecular.isTrue()) {
materialSpecularColor[0] = -1.f;
}
}
}
@Override
public void drawArrays(int type, int first, int count) {
invalidateMaterialColors();
super.drawArrays(type, first, count);
}
@Override
public void setLightMode(int mode) {
if (lightMode != mode) {
super.setLightMode(mode);
lightMode = mode;
}
}
@Override
public void setLightModelAmbientColor(float[] color) {
if (lightModelAmbientColor[0] != color[0] || lightModelAmbientColor[1] != color[1] || lightModelAmbientColor[2] != color[2] || lightModelAmbientColor[3] != color[3]) {
super.setLightModelAmbientColor(color);
lightModelAmbientColor[0] = color[0];
lightModelAmbientColor[1] = color[1];
lightModelAmbientColor[2] = color[2];
lightModelAmbientColor[3] = color[3];
}
}
private void onVertexArrayChanged() {
for (int i = 0; i < clientState.length; i++) {
clientState[i].setUndefined();
}
for (int i = 0; i < vertexAttribArray.length; i++) {
vertexAttribArray[i].setUndefined();
}
bindBuffer[IRenderingEngine.RE_ELEMENT_ARRAY_BUFFER] = -1;
}
@Override
public void bindVertexArray(int id) {
if (id != bindVertexArray) {
onVertexArrayChanged();
super.bindVertexArray(id);
bindVertexArray = id;
}
}
@Override
public void deleteVertexArray(int id) {
// When deleting the current vertex array, the current binding is reset to 0
if (id == bindVertexArray) {
onVertexArrayChanged();
bindVertexArray = 0;
}
super.deleteVertexArray(id);
}
@Override
public void setActiveTexture(int index) {
if (index != activeTextureUnit) {
super.setActiveTexture(index);
activeTextureUnit = index;
currentTextureState = textureStates.get(bindTexture[activeTextureUnit]);
}
}
@Override
public void bindActiveTexture(int index, int texture) {
if (texture != bindTexture[index]) {
super.bindActiveTexture(index, texture);
bindTexture[index] = texture;
if (index == activeTextureUnit) {
// Binding a new texture change the OpenGL texture wrap mode and min/mag filters
currentTextureState = textureStates.get(texture);
if (currentTextureState == null) {
currentTextureState = new TextureState();
textureStates.put(texture, currentTextureState);
}
}
}
}
@Override
public void setTextureAnisotropy(float value) {
if (value != currentTextureState.textureAnisotropy) {
super.setTextureAnisotropy(value);
currentTextureState.textureAnisotropy = value;
}
}
@Override
public void setBlendSFix(int sfix, float[] color) {
if (this.sfix != sfix) {
super.setBlendSFix(sfix, color);
this.sfix = sfix;
}
}
@Override
public void setBlendDFix(int dfix, float[] color) {
if (this.dfix != dfix) {
super.setBlendDFix(dfix, color);
this.dfix = dfix;
}
}
@Override
public void setVertexAttribPointer(int id, int size, int type, boolean normalized, int stride, long offset) {
// id==-1 is a non-existing vertex attrib
if (id >= 0) {
super.setVertexAttribPointer(id, size, type, normalized, stride, offset);
}
}
@Override
public void setVertexAttribPointer(int id, int size, int type, boolean normalized, int stride, int bufferSize, Buffer buffer) {
// id==-1 is a non-existing vertex attrib
if (id >= 0) {
super.setVertexAttribPointer(id, size, type, normalized, stride, bufferSize, buffer);
}
}
@Override
public void bindFramebuffer(int target, int framebuffer) {
switch (target) {
case RE_FRAMEBUFFER:
if (framebuffer != bindFramebufferRead || framebuffer != bindFramebufferDraw) {
super.bindFramebuffer(target, framebuffer);
bindFramebufferRead = framebuffer;
bindFramebufferDraw = framebuffer;
}
break;
case RE_READ_FRAMEBUFFER:
if (framebuffer != bindFramebufferRead) {
super.bindFramebuffer(target, framebuffer);
bindFramebufferRead = framebuffer;
}
break;
case RE_DRAW_FRAMEBUFFER:
if (framebuffer != bindFramebufferDraw) {
super.bindFramebuffer(target, framebuffer);
bindFramebufferDraw = framebuffer;
}
break;
default:
super.bindFramebuffer(target, framebuffer);
break;
}
}
}