|
|
@ -93,7 +93,6 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
private ListMap<String, MatParam> paramValues = new ListMap<String, MatParam>(); |
|
|
|
private ListMap<String, MatParam> paramValues = new ListMap<String, MatParam>(); |
|
|
|
private Technique technique; |
|
|
|
private Technique technique; |
|
|
|
private HashMap<String, Technique> techniques = new HashMap<String, Technique>(); |
|
|
|
private HashMap<String, Technique> techniques = new HashMap<String, Technique>(); |
|
|
|
private int nextTexUnit = 0; |
|
|
|
|
|
|
|
private RenderState additionalState = null; |
|
|
|
private RenderState additionalState = null; |
|
|
|
private RenderState mergedRenderState = new RenderState(); |
|
|
|
private RenderState mergedRenderState = new RenderState(); |
|
|
|
private boolean transparent = false; |
|
|
|
private boolean transparent = false; |
|
|
@ -264,8 +263,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
// E.g. if user chose custom technique for one material but
|
|
|
|
// E.g. if user chose custom technique for one material but
|
|
|
|
// uses default technique for other material, the materials
|
|
|
|
// uses default technique for other material, the materials
|
|
|
|
// are not equal.
|
|
|
|
// are not equal.
|
|
|
|
String thisDefName = this.technique != null ? this.technique.getDef().getName() : "Default"; |
|
|
|
String thisDefName = this.technique != null |
|
|
|
String otherDefName = other.technique != null ? other.technique.getDef().getName() : "Default"; |
|
|
|
? this.technique.getDef().getName() |
|
|
|
|
|
|
|
: TechniqueDef.DEFAULT_TECHNIQUE_NAME; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String otherDefName = other.technique != null |
|
|
|
|
|
|
|
? other.technique.getDef().getName() |
|
|
|
|
|
|
|
: TechniqueDef.DEFAULT_TECHNIQUE_NAME; |
|
|
|
|
|
|
|
|
|
|
|
if (!thisDefName.equals(otherDefName)) { |
|
|
|
if (!thisDefName.equals(otherDefName)) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
@ -510,16 +515,6 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
|
|
|
|
|
|
|
|
paramValues.remove(name); |
|
|
|
paramValues.remove(name); |
|
|
|
if (matParam instanceof MatParamTexture) { |
|
|
|
if (matParam instanceof MatParamTexture) { |
|
|
|
int texUnit = ((MatParamTexture) matParam).getUnit(); |
|
|
|
|
|
|
|
nextTexUnit--; |
|
|
|
|
|
|
|
for (MatParam param : paramValues.values()) { |
|
|
|
|
|
|
|
if (param instanceof MatParamTexture) { |
|
|
|
|
|
|
|
MatParamTexture texParam = (MatParamTexture) param; |
|
|
|
|
|
|
|
if (texParam.getUnit() > texUnit) { |
|
|
|
|
|
|
|
texParam.setUnit(texParam.getUnit() - 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sortingId = -1; |
|
|
|
sortingId = -1; |
|
|
|
} |
|
|
|
} |
|
|
|
if (technique != null) { |
|
|
|
if (technique != null) { |
|
|
@ -562,13 +557,13 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
+ "Linear using texture.getImage.setColorSpace().", |
|
|
|
+ "Linear using texture.getImage.setColorSpace().", |
|
|
|
new Object[]{value.getName(), value.getImage().getColorSpace().name(), name}); |
|
|
|
new Object[]{value.getName(), value.getImage().getColorSpace().name(), name}); |
|
|
|
} |
|
|
|
} |
|
|
|
paramValues.put(name, new MatParamTexture(type, name, value, nextTexUnit++, null)); |
|
|
|
paramValues.put(name, new MatParamTexture(type, name, value, null)); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
val.setTextureValue(value); |
|
|
|
val.setTextureValue(value); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (technique != null) { |
|
|
|
if (technique != null) { |
|
|
|
technique.notifyParamChanged(name, type, nextTexUnit - 1); |
|
|
|
technique.notifyParamChanged(name, type, value); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// need to recompute sort ID
|
|
|
|
// need to recompute sort ID
|
|
|
@ -704,23 +699,18 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
/** |
|
|
|
/** |
|
|
|
* Select the technique to use for rendering this material. |
|
|
|
* Select the technique to use for rendering this material. |
|
|
|
* <p> |
|
|
|
* <p> |
|
|
|
* If <code>name</code> is "Default", then one of the |
|
|
|
|
|
|
|
* {@link MaterialDef#getDefaultTechniques() default techniques} |
|
|
|
|
|
|
|
* on the material will be selected. Otherwise, the named technique |
|
|
|
|
|
|
|
* will be found in the material definition. |
|
|
|
|
|
|
|
* <p> |
|
|
|
|
|
|
|
* Any candidate technique for selection (either default or named) |
|
|
|
* Any candidate technique for selection (either default or named) |
|
|
|
* must be verified to be compatible with the system, for that, the |
|
|
|
* must be verified to be compatible with the system, for that, the |
|
|
|
* <code>renderManager</code> is queried for capabilities. |
|
|
|
* <code>renderManager</code> is queried for capabilities. |
|
|
|
* |
|
|
|
* |
|
|
|
* @param name The name of the technique to select, pass "Default" to |
|
|
|
* @param name The name of the technique to select, pass |
|
|
|
* select one of the default techniques. |
|
|
|
* {@link TechniqueDef#DEFAULT_TECHNIQUE_NAME} to select one of the default |
|
|
|
|
|
|
|
* techniques. |
|
|
|
* @param renderManager The {@link RenderManager render manager} |
|
|
|
* @param renderManager The {@link RenderManager render manager} |
|
|
|
* to query for capabilities. |
|
|
|
* to query for capabilities. |
|
|
|
* |
|
|
|
* |
|
|
|
* @throws IllegalArgumentException If "Default" is passed and no default |
|
|
|
* @throws IllegalArgumentException If no technique exists with the given |
|
|
|
* techniques are available on the material definition, or if a name |
|
|
|
* name. |
|
|
|
* is passed but there's no technique by that name. |
|
|
|
|
|
|
|
* @throws UnsupportedOperationException If no candidate technique supports |
|
|
|
* @throws UnsupportedOperationException If no candidate technique supports |
|
|
|
* the system capabilities. |
|
|
|
* the system capabilities. |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -731,46 +721,30 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
// supports all the caps.
|
|
|
|
// supports all the caps.
|
|
|
|
if (tech == null) { |
|
|
|
if (tech == null) { |
|
|
|
EnumSet<Caps> rendererCaps = renderManager.getRenderer().getCaps(); |
|
|
|
EnumSet<Caps> rendererCaps = renderManager.getRenderer().getCaps(); |
|
|
|
if (name.equals("Default")) { |
|
|
|
List<TechniqueDef> techDefs = def.getTechniqueDefs(name); |
|
|
|
List<TechniqueDef> techDefs = def.getDefaultTechniques(); |
|
|
|
|
|
|
|
if (techDefs == null || techDefs.isEmpty()) { |
|
|
|
|
|
|
|
throw new IllegalArgumentException("No default techniques are available on material '" + def.getName() + "'"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TechniqueDef lastTech = null; |
|
|
|
|
|
|
|
for (TechniqueDef techDef : techDefs) { |
|
|
|
|
|
|
|
if (rendererCaps.containsAll(techDef.getRequiredCaps())) { |
|
|
|
|
|
|
|
// use the first one that supports all the caps
|
|
|
|
|
|
|
|
tech = new Technique(this, techDef); |
|
|
|
|
|
|
|
techniques.put(name, tech); |
|
|
|
|
|
|
|
if(tech.getDef().getLightMode() == renderManager.getPreferredLightMode() || |
|
|
|
|
|
|
|
tech.getDef().getLightMode() == LightMode.Disable){ |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
lastTech = techDef; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (tech == null) { |
|
|
|
|
|
|
|
throw new UnsupportedOperationException("No default technique on material '" + def.getName() + "'\n" |
|
|
|
|
|
|
|
+ " is supported by the video hardware. The caps " |
|
|
|
|
|
|
|
+ lastTech.getRequiredCaps() + " are required."); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
if (techDefs == null || techDefs.isEmpty()) { |
|
|
|
// create "special" technique instance
|
|
|
|
throw new IllegalArgumentException( |
|
|
|
TechniqueDef techDef = def.getTechniqueDef(name); |
|
|
|
String.format("The requested technique %s is not available on material %s", name, def.getName())); |
|
|
|
if (techDef == null) { |
|
|
|
} |
|
|
|
throw new IllegalArgumentException("For material " + def.getName() + ", technique not found: " + name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!rendererCaps.containsAll(techDef.getRequiredCaps())) { |
|
|
|
TechniqueDef lastTech = null; |
|
|
|
throw new UnsupportedOperationException("The explicitly chosen technique '" + name + "' on material '" + def.getName() + "'\n" |
|
|
|
for (TechniqueDef techDef : techDefs) { |
|
|
|
+ "requires caps " + techDef.getRequiredCaps() + " which are not " |
|
|
|
if (rendererCaps.containsAll(techDef.getRequiredCaps())) { |
|
|
|
+ "supported by the video renderer"); |
|
|
|
// use the first one that supports all the caps
|
|
|
|
|
|
|
|
tech = new Technique(this, techDef); |
|
|
|
|
|
|
|
techniques.put(name, tech); |
|
|
|
|
|
|
|
if (tech.getDef().getLightMode() == renderManager.getPreferredLightMode() |
|
|
|
|
|
|
|
|| tech.getDef().getLightMode() == LightMode.Disable) { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
lastTech = techDef; |
|
|
|
tech = new Technique(this, techDef); |
|
|
|
} |
|
|
|
techniques.put(name, tech); |
|
|
|
if (tech == null) { |
|
|
|
|
|
|
|
throw new UnsupportedOperationException("No default technique on material '" + def.getName() + "'\n" |
|
|
|
|
|
|
|
+ " is supported by the video hardware. The caps " |
|
|
|
|
|
|
|
+ lastTech.getRequiredCaps() + " are required."); |
|
|
|
} |
|
|
|
} |
|
|
|
} else if (technique == tech) { |
|
|
|
} else if (technique == tech) { |
|
|
|
// attempting to switch to an already
|
|
|
|
// attempting to switch to an already
|
|
|
@ -785,32 +759,43 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
sortingId = -1; |
|
|
|
sortingId = -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private int updateShaderMaterialParameters(Renderer renderer, Shader shader, List<MatParamOverride> overrides) { |
|
|
|
private int applyOverrides(Renderer renderer, Shader shader, List<MatParamOverride> overrides, int unit) { |
|
|
|
int unit = 0; |
|
|
|
for (MatParamOverride override : overrides) { |
|
|
|
|
|
|
|
VarType type = override.getVarType(); |
|
|
|
|
|
|
|
|
|
|
|
if (overrides != null) { |
|
|
|
MatParam paramDef = def.getMaterialParam(override.getName()); |
|
|
|
for (MatParamOverride override : overrides) { |
|
|
|
|
|
|
|
VarType type = override.getVarType(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MatParam paramDef = def.getMaterialParam(override.getName()); |
|
|
|
if (paramDef == null || paramDef.getVarType() != type || !override.isEnabled()) { |
|
|
|
if (paramDef == null || paramDef.getVarType() != type || !override.isEnabled()) { |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Uniform uniform = shader.getUniform(override.getPrefixedName()); |
|
|
|
Uniform uniform = shader.getUniform(override.getPrefixedName()); |
|
|
|
if (override.getValue() != null) { |
|
|
|
|
|
|
|
if (type.isTextureType()) { |
|
|
|
if (override.getValue() != null) { |
|
|
|
renderer.setTexture(unit, (Texture) override.getValue()); |
|
|
|
if (type.isTextureType()) { |
|
|
|
uniform.setValue(VarType.Int, unit); |
|
|
|
renderer.setTexture(unit, (Texture) override.getValue()); |
|
|
|
unit++; |
|
|
|
uniform.setValue(VarType.Int, unit); |
|
|
|
} else { |
|
|
|
unit++; |
|
|
|
uniform.setValue(type, override.getValue()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
uniform.clearValue(); |
|
|
|
uniform.setValue(type, override.getValue()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
uniform.clearValue(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return unit; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private int updateShaderMaterialParameters(Renderer renderer, Shader shader, |
|
|
|
|
|
|
|
List<MatParamOverride> worldOverrides, List<MatParamOverride> forcedOverrides) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int unit = 0; |
|
|
|
|
|
|
|
if (worldOverrides != null) { |
|
|
|
|
|
|
|
unit = applyOverrides(renderer, shader, worldOverrides, unit); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (forcedOverrides != null) { |
|
|
|
|
|
|
|
unit = applyOverrides(renderer, shader, forcedOverrides, unit); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < paramValues.size(); i++) { |
|
|
|
for (int i = 0; i < paramValues.size(); i++) { |
|
|
|
MatParam param = paramValues.getValue(i); |
|
|
|
MatParam param = paramValues.getValue(i); |
|
|
@ -857,7 +842,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public void preload(RenderManager renderManager) { |
|
|
|
public void preload(RenderManager renderManager) { |
|
|
|
if (technique == null) { |
|
|
|
if (technique == null) { |
|
|
|
selectTechnique("Default", renderManager); |
|
|
|
selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); |
|
|
|
} |
|
|
|
} |
|
|
|
TechniqueDef techniqueDef = technique.getDef(); |
|
|
|
TechniqueDef techniqueDef = technique.getDef(); |
|
|
|
Renderer renderer = renderManager.getRenderer(); |
|
|
|
Renderer renderer = renderManager.getRenderer(); |
|
|
@ -867,8 +852,8 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Shader shader = technique.makeCurrent(renderManager, null, null, rendererCaps); |
|
|
|
Shader shader = technique.makeCurrent(renderManager, null, null, null, rendererCaps); |
|
|
|
updateShaderMaterialParameters(renderer, shader, null); |
|
|
|
updateShaderMaterialParameters(renderer, shader, null, null); |
|
|
|
renderManager.getRenderer().setShader(shader); |
|
|
|
renderManager.getRenderer().setShader(shader); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -957,7 +942,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public void render(Geometry geometry, LightList lights, RenderManager renderManager) { |
|
|
|
public void render(Geometry geometry, LightList lights, RenderManager renderManager) { |
|
|
|
if (technique == null) { |
|
|
|
if (technique == null) { |
|
|
|
selectTechnique("Default", renderManager); |
|
|
|
selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
TechniqueDef techniqueDef = technique.getDef(); |
|
|
|
TechniqueDef techniqueDef = technique.getDef(); |
|
|
@ -975,7 +960,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
List<MatParamOverride> overrides = geometry.getWorldMatParamOverrides(); |
|
|
|
List<MatParamOverride> overrides = geometry.getWorldMatParamOverrides(); |
|
|
|
|
|
|
|
|
|
|
|
// Select shader to use
|
|
|
|
// Select shader to use
|
|
|
|
Shader shader = technique.makeCurrent(renderManager, overrides, lights, rendererCaps); |
|
|
|
Shader shader = technique.makeCurrent(renderManager, overrides, renderManager.getForcedMatParams(), lights, rendererCaps); |
|
|
|
|
|
|
|
|
|
|
|
// Begin tracking which uniforms were changed by material.
|
|
|
|
// Begin tracking which uniforms were changed by material.
|
|
|
|
clearUniformsSetByCurrent(shader); |
|
|
|
clearUniformsSetByCurrent(shader); |
|
|
@ -984,8 +969,9 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
renderManager.updateUniformBindings(shader); |
|
|
|
renderManager.updateUniformBindings(shader); |
|
|
|
|
|
|
|
|
|
|
|
// Set material parameters
|
|
|
|
// Set material parameters
|
|
|
|
|
|
|
|
|
|
|
|
//TODO RRemove the unit when texture units are handled in the Uniform
|
|
|
|
//TODO RRemove the unit when texture units are handled in the Uniform
|
|
|
|
int unit = updateShaderMaterialParameters(renderer, shader, geometry.getWorldMatParamOverrides()); |
|
|
|
int unit = updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams()); |
|
|
|
|
|
|
|
|
|
|
|
// Clear any uniforms not changed by material.
|
|
|
|
// Clear any uniforms not changed by material.
|
|
|
|
resetUniformsNotSetByCurrent(shader); |
|
|
|
resetUniformsNotSetByCurrent(shader); |
|
|
@ -1081,11 +1067,6 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { |
|
|
|
MatParam param = entry.getValue(); |
|
|
|
MatParam param = entry.getValue(); |
|
|
|
if (param instanceof MatParamTexture) { |
|
|
|
if (param instanceof MatParamTexture) { |
|
|
|
MatParamTexture texVal = (MatParamTexture) param; |
|
|
|
MatParamTexture texVal = (MatParamTexture) param; |
|
|
|
|
|
|
|
|
|
|
|
if (nextTexUnit < texVal.getUnit() + 1) { |
|
|
|
|
|
|
|
nextTexUnit = texVal.getUnit() + 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// the texture failed to load for this param
|
|
|
|
// the texture failed to load for this param
|
|
|
|
// do not add to param values
|
|
|
|
// do not add to param values
|
|
|
|
if (texVal.getTextureValue() == null || texVal.getTextureValue().getImage() == null) { |
|
|
|
if (texVal.getTextureValue() == null || texVal.getTextureValue().getImage() == null) { |
|
|
|