parent
42d76cfd29
commit
adc5084f5d
@ -0,0 +1,509 @@ |
||||
/* |
||||
* Copyright (c) 2009-2016 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
package com.jme3.material; |
||||
|
||||
import com.jme3.asset.AssetManager; |
||||
import com.jme3.light.LightList; |
||||
import com.jme3.math.Matrix4f; |
||||
import com.jme3.renderer.RenderManager; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.shape.Box; |
||||
import com.jme3.shader.Shader; |
||||
import com.jme3.shader.Uniform; |
||||
import com.jme3.shader.VarType; |
||||
import java.util.Arrays; |
||||
import java.util.HashSet; |
||||
import org.junit.Assert; |
||||
import org.junit.Test; |
||||
|
||||
import static com.jme3.scene.MPOTestUtils.*; |
||||
import com.jme3.shader.DefineList; |
||||
import com.jme3.system.NullRenderer; |
||||
import com.jme3.system.TestUtil; |
||||
import com.jme3.texture.Image.Format; |
||||
import com.jme3.texture.Texture; |
||||
import com.jme3.texture.Texture2D; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
public class TechniqueDefMatParamOverrideTest { |
||||
|
||||
private static final HashSet<String> IGNORED_UNIFORMS = new HashSet<String>( |
||||
Arrays.asList(new String[]{"m_ParallaxHeight", "m_Shininess"})); |
||||
|
||||
@Test |
||||
public void testBoolMpoOnly() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMpo(mpoBool("UseMaterialColors", true)); |
||||
outDefines(def("MATERIAL_COLORS", VarType.Boolean, true)); |
||||
outUniforms(uniform("UseMaterialColors", VarType.Boolean, true)); |
||||
} |
||||
|
||||
@Test |
||||
public void testBoolMpOnly() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMp(mpoBool("UseMaterialColors", true)); |
||||
outDefines(def("MATERIAL_COLORS", VarType.Boolean, true)); |
||||
outUniforms(uniform("UseMaterialColors", VarType.Boolean, true)); |
||||
} |
||||
|
||||
@Test |
||||
public void testBoolOverrideFalse() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMp(mpoBool("UseMaterialColors", true)); |
||||
inputMpo(mpoBool("UseMaterialColors", false)); |
||||
outDefines(); |
||||
outUniforms(uniform("UseMaterialColors", VarType.Boolean, false)); |
||||
} |
||||
|
||||
@Test |
||||
public void testBoolOverrideTrue() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMp(mpoBool("UseMaterialColors", false)); |
||||
inputMpo(mpoBool("UseMaterialColors", true)); |
||||
outDefines(def("MATERIAL_COLORS", VarType.Boolean, true)); |
||||
outUniforms(uniform("UseMaterialColors", VarType.Boolean, true)); |
||||
} |
||||
|
||||
@Test |
||||
public void testFloatMpoOnly() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMpo(mpoFloat("AlphaDiscardThreshold", 3.12f)); |
||||
outDefines(def("DISCARD_ALPHA", VarType.Float, 3.12f)); |
||||
outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 3.12f)); |
||||
} |
||||
|
||||
@Test |
||||
public void testFloatMpOnly() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMp(mpoFloat("AlphaDiscardThreshold", 3.12f)); |
||||
outDefines(def("DISCARD_ALPHA", VarType.Float, 3.12f)); |
||||
outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 3.12f)); |
||||
} |
||||
|
||||
@Test |
||||
public void testFloatOverride() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMp(mpoFloat("AlphaDiscardThreshold", 3.12f)); |
||||
inputMpo(mpoFloat("AlphaDiscardThreshold", 2.79f)); |
||||
outDefines(def("DISCARD_ALPHA", VarType.Float, 2.79f)); |
||||
outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 2.79f)); |
||||
} |
||||
|
||||
@Test |
||||
public void testIntMpoOnly() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMpo(mpoInt("NumberOfBones", 1234)); |
||||
outDefines(def("NUM_BONES", VarType.Int, 1234)); |
||||
outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); |
||||
} |
||||
|
||||
@Test |
||||
public void testIntMpOnly() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMp(mpoInt("NumberOfBones", 1234)); |
||||
outDefines(def("NUM_BONES", VarType.Int, 1234)); |
||||
outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); |
||||
} |
||||
|
||||
@Test |
||||
public void testIntOverride() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMp(mpoInt("NumberOfBones", 1234)); |
||||
inputMpo(mpoInt("NumberOfBones", 4321)); |
||||
outDefines(def("NUM_BONES", VarType.Int, 4321)); |
||||
outUniforms(uniform("NumberOfBones", VarType.Int, 4321)); |
||||
} |
||||
|
||||
@Test |
||||
public void testMatrixArray() { |
||||
Matrix4f[] matrices = new Matrix4f[]{ |
||||
new Matrix4f() |
||||
}; |
||||
|
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMpo(mpoMatrix4Array("BoneMatrices", matrices)); |
||||
outDefines(); |
||||
outUniforms(uniform("BoneMatrices", VarType.Matrix4Array, matrices)); |
||||
} |
||||
|
||||
@Test |
||||
public void testNonExistentParameter() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMpo(mpoInt("NonExistent", 4321)); |
||||
outDefines(); |
||||
outUniforms(); |
||||
} |
||||
|
||||
@Test |
||||
public void testWrongType() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMpo(mpoInt("UseMaterialColors", 4321)); |
||||
outDefines(); |
||||
outUniforms(); |
||||
} |
||||
|
||||
@Test |
||||
public void testParamOnly() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
inputMpo(mpoFloat("ShadowMapSize", 3.12f)); |
||||
outDefines(); |
||||
outUniforms(uniform("ShadowMapSize", VarType.Float, 3.12f)); |
||||
} |
||||
|
||||
@Test |
||||
public void testRemove() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
|
||||
reset(); |
||||
inputMp(mpoInt("NumberOfBones", 1234)); |
||||
outDefines(def("NUM_BONES", VarType.Int, 1234)); |
||||
outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); |
||||
|
||||
reset(); |
||||
inputMpo(mpoInt("NumberOfBones", 4321)); |
||||
outDefines(def("NUM_BONES", VarType.Int, 4321)); |
||||
outUniforms(uniform("NumberOfBones", VarType.Int, 4321)); |
||||
|
||||
reset(); |
||||
geometry.clearMatParamOverrides(); |
||||
outDefines(def("NUM_BONES", VarType.Int, 1234)); |
||||
outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); |
||||
|
||||
reset(); |
||||
geometry.getMaterial().clearParam("NumberOfBones"); |
||||
outDefines(); |
||||
outUniforms(); |
||||
|
||||
reset(); |
||||
inputMpo(mpoInt("NumberOfBones", 4321)); |
||||
outDefines(def("NUM_BONES", VarType.Int, 4321)); |
||||
outUniforms(uniform("NumberOfBones", VarType.Int, 4321)); |
||||
|
||||
reset(); |
||||
inputMp(mpoInt("NumberOfBones", 1234)); |
||||
outDefines(def("NUM_BONES", VarType.Int, 4321)); |
||||
outUniforms(uniform("NumberOfBones", VarType.Int, 4321)); |
||||
} |
||||
|
||||
public void testRemoveOverride() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
|
||||
reset(); |
||||
inputMp(mpoInt("NumberOfBones", 1234)); |
||||
outDefines(def("NUM_BONES", VarType.Int, 1234)); |
||||
outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); |
||||
|
||||
reset(); |
||||
inputMpo(mpoInt("NumberOfBones", 4321)); |
||||
outDefines(def("NUM_BONES", VarType.Int, 4321)); |
||||
outUniforms(uniform("NumberOfBones", VarType.Int, 4321)); |
||||
|
||||
reset(); |
||||
geometry.clearMatParamOverrides(); |
||||
outDefines(def("NUM_BONES", VarType.Int, 1234)); |
||||
outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); |
||||
} |
||||
|
||||
@Test |
||||
public void testRemoveMpoOnly() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
|
||||
reset(); |
||||
inputMpo(mpoInt("NumberOfBones", 4321)); |
||||
outDefines(def("NUM_BONES", VarType.Int, 4321)); |
||||
outUniforms(uniform("NumberOfBones", VarType.Int, 4321)); |
||||
|
||||
reset(); |
||||
geometry.clearMatParamOverrides(); |
||||
outDefines(); |
||||
outUniforms(); |
||||
} |
||||
|
||||
@Test |
||||
public void testTextureMpoOnly() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
Texture2D tex = new Texture2D(128, 128, Format.RGBA8); |
||||
|
||||
inputMpo(mpoTexture2D("DiffuseMap", tex)); |
||||
outDefines(def("DIFFUSEMAP", VarType.Texture2D, tex)); |
||||
outUniforms(uniform("DiffuseMap", VarType.Int, 0)); |
||||
outTextures(tex); |
||||
} |
||||
|
||||
@Test |
||||
public void testTextureOverride() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
Texture2D tex1 = new Texture2D(128, 128, Format.RGBA8); |
||||
Texture2D tex2 = new Texture2D(128, 128, Format.RGBA8); |
||||
|
||||
inputMp(mpoTexture2D("DiffuseMap", tex1)); |
||||
inputMpo(mpoTexture2D("DiffuseMap", tex2)); |
||||
|
||||
outDefines(def("DIFFUSEMAP", VarType.Texture2D, tex2)); |
||||
outUniforms(uniform("DiffuseMap", VarType.Int, 0)); |
||||
outTextures(tex2); |
||||
} |
||||
|
||||
@Test |
||||
public void testRemoveTexture() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
Texture2D tex = new Texture2D(128, 128, Format.RGBA8); |
||||
|
||||
reset(); |
||||
inputMpo(mpoTexture2D("DiffuseMap", tex)); |
||||
outDefines(def("DIFFUSEMAP", VarType.Texture2D, tex)); |
||||
outUniforms(uniform("DiffuseMap", VarType.Int, 0)); |
||||
outTextures(tex); |
||||
|
||||
reset(); |
||||
geometry.clearMatParamOverrides(); |
||||
outDefines(); |
||||
outUniforms(); |
||||
outTextures(); |
||||
} |
||||
|
||||
@Test |
||||
public void testRemoveTextureOverride() { |
||||
material("Common/MatDefs/Light/Lighting.j3md"); |
||||
Texture2D tex1 = new Texture2D(128, 128, Format.RGBA8); |
||||
Texture2D tex2 = new Texture2D(128, 128, Format.RGBA8); |
||||
|
||||
reset(); |
||||
inputMp(mpoTexture2D("DiffuseMap", tex1)); |
||||
outDefines(def("DIFFUSEMAP", VarType.Texture2D, tex1)); |
||||
outUniforms(uniform("DiffuseMap", VarType.Int, 0)); |
||||
outTextures(tex1); |
||||
|
||||
reset(); |
||||
inputMpo(mpoTexture2D("DiffuseMap", tex2)); |
||||
outDefines(def("DIFFUSEMAP", VarType.Texture2D, tex2)); |
||||
outUniforms(uniform("DiffuseMap", VarType.Int, 0)); |
||||
outTextures(tex2); |
||||
|
||||
reset(); |
||||
geometry.clearMatParamOverrides(); |
||||
outDefines(def("DIFFUSEMAP", VarType.Texture2D, tex1)); |
||||
outUniforms(uniform("DiffuseMap", VarType.Int, 0)); |
||||
outTextures(tex1); |
||||
} |
||||
|
||||
private static final class Define { |
||||
|
||||
public String name; |
||||
public VarType type; |
||||
public Object value; |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
int hash = 3; |
||||
hash = 89 * hash + this.name.hashCode(); |
||||
hash = 89 * hash + this.type.hashCode(); |
||||
hash = 89 * hash + this.value.hashCode(); |
||||
return hash; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
final Define other = (Define) obj; |
||||
return this.name.equals(other.name) && this.type.equals(other.type) && this.value.equals(other.value); |
||||
} |
||||
} |
||||
|
||||
private final Geometry geometry = new Geometry("geometry", new Box(1, 1, 1)); |
||||
private final LightList lightList = new LightList(geometry); |
||||
|
||||
private final NullRenderer renderer = new NullRenderer() { |
||||
@Override |
||||
public void setShader(Shader shader) { |
||||
TechniqueDefMatParamOverrideTest.this.usedShader = shader; |
||||
evaluated = true; |
||||
} |
||||
|
||||
@Override |
||||
public void setTexture(int unit, Texture texture) { |
||||
TechniqueDefMatParamOverrideTest.this.usedTextures[unit] = texture; |
||||
} |
||||
}; |
||||
private final RenderManager renderManager = new RenderManager(renderer); |
||||
|
||||
private boolean evaluated = false; |
||||
private Shader usedShader = null; |
||||
private final Texture[] usedTextures = new Texture[32]; |
||||
|
||||
private void inputMp(MatParam... params) { |
||||
if (evaluated) { |
||||
throw new IllegalStateException(); |
||||
} |
||||
Material mat = geometry.getMaterial(); |
||||
for (MatParam param : params) { |
||||
mat.setParam(param.getName(), param.getVarType(), param.getValue()); |
||||
} |
||||
} |
||||
|
||||
private void inputMpo(MatParamOverride... overrides) { |
||||
if (evaluated) { |
||||
throw new IllegalStateException(); |
||||
} |
||||
for (MatParamOverride override : overrides) { |
||||
geometry.addMatParamOverride(override); |
||||
} |
||||
geometry.updateGeometricState(); |
||||
} |
||||
|
||||
private void reset() { |
||||
evaluated = false; |
||||
usedShader = null; |
||||
Arrays.fill(usedTextures, null); |
||||
} |
||||
|
||||
private Define def(String name, VarType type, Object value) { |
||||
Define d = new Define(); |
||||
d.name = name; |
||||
d.type = type; |
||||
d.value = value; |
||||
return d; |
||||
} |
||||
|
||||
private Uniform uniform(String name, VarType type, Object value) { |
||||
Uniform u = new Uniform(); |
||||
u.setName("m_" + name); |
||||
u.setValue(type, value); |
||||
return u; |
||||
} |
||||
|
||||
private void material(String path) { |
||||
AssetManager assetManager = TestUtil.createAssetManager(); |
||||
geometry.setMaterial(new Material(assetManager, path)); |
||||
} |
||||
|
||||
private void evaluateTechniqueDef() { |
||||
Assert.assertFalse(evaluated); |
||||
Material mat = geometry.getMaterial(); |
||||
mat.render(geometry, lightList, renderManager); |
||||
Assert.assertTrue(evaluated); |
||||
} |
||||
|
||||
private void outTextures(Texture... textures) { |
||||
for (int i = 0; i < usedTextures.length; i++) { |
||||
if (i < textures.length) { |
||||
Assert.assertSame(textures[i], usedTextures[i]); |
||||
} else { |
||||
Assert.assertNull(usedTextures[i]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void outDefines(Define... expectedDefinesArray) { |
||||
Map<String, Define> nameToDefineMap = new HashMap<String, Define>(); |
||||
for (Define define : expectedDefinesArray) { |
||||
nameToDefineMap.put(define.name, define); |
||||
} |
||||
|
||||
if (!evaluated) { |
||||
evaluateTechniqueDef(); |
||||
} |
||||
|
||||
Material mat = geometry.getMaterial(); |
||||
Technique tech = mat.getActiveTechnique(); |
||||
TechniqueDef def = tech.getDef(); |
||||
DefineList actualDefines = tech.getDynamicDefines(); |
||||
|
||||
String[] defineNames = def.getDefineNames(); |
||||
VarType[] defineTypes = def.getDefineTypes(); |
||||
|
||||
Assert.assertEquals(defineNames.length, defineTypes.length); |
||||
|
||||
for (int index = 0; index < defineNames.length; index++) { |
||||
String name = defineNames[index]; |
||||
VarType type = defineTypes[index]; |
||||
Define expectedDefine = nameToDefineMap.remove(name); |
||||
Object expectedValue = null; |
||||
|
||||
if (expectedDefine != null) { |
||||
Assert.assertEquals(expectedDefine.type, type); |
||||
expectedValue = expectedDefine.value; |
||||
} |
||||
|
||||
switch (type) { |
||||
case Boolean: |
||||
if (expectedValue != null) { |
||||
Assert.assertEquals((boolean) (Boolean) expectedValue, actualDefines.getBoolean(index)); |
||||
} else { |
||||
Assert.assertEquals(false, actualDefines.getBoolean(index)); |
||||
} |
||||
break; |
||||
case Int: |
||||
if (expectedValue != null) { |
||||
Assert.assertEquals((int) (Integer) expectedValue, actualDefines.getInt(index)); |
||||
} else { |
||||
Assert.assertEquals(0, actualDefines.getInt(index)); |
||||
} |
||||
break; |
||||
case Float: |
||||
if (expectedValue != null) { |
||||
Assert.assertEquals((float) (Float) expectedValue, actualDefines.getFloat(index), 0f); |
||||
} else { |
||||
Assert.assertEquals(0f, actualDefines.getFloat(index), 0f); |
||||
} |
||||
break; |
||||
default: |
||||
if (expectedValue != null) { |
||||
Assert.assertEquals(1, actualDefines.getInt(index)); |
||||
} else { |
||||
Assert.assertEquals(0, actualDefines.getInt(index)); |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
Assert.assertTrue(nameToDefineMap.isEmpty()); |
||||
} |
||||
|
||||
private void outUniforms(Uniform... uniforms) { |
||||
HashSet<Uniform> actualUniforms = new HashSet<Uniform>(); |
||||
|
||||
for (Uniform uniform : usedShader.getUniformMap().values()) { |
||||
if (uniform.getName().startsWith("m_") |
||||
&& !IGNORED_UNIFORMS.contains(uniform.getName())) { |
||||
actualUniforms.add(uniform); |
||||
} |
||||
} |
||||
|
||||
HashSet<Uniform> expectedUniforms = new HashSet<Uniform>(Arrays.asList(uniforms)); |
||||
|
||||
if (!expectedUniforms.equals(actualUniforms)) { |
||||
System.out.println(expectedUniforms + " != " + actualUniforms); |
||||
Assert.fail("Uniform lists must match"); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue