getParamsMap() {
return paramValues;
}
@@ -504,16 +503,6 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
paramValues.remove(name);
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;
}
if (technique != null) {
@@ -556,13 +545,13 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
+ "Linear using texture.getImage.setColorSpace().",
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 {
val.setTextureValue(value);
}
if (technique != null) {
- technique.notifyParamChanged(name, type, nextTexUnit - 1);
+ technique.notifyParamChanged(name, type, value);
}
// need to recompute sort ID
@@ -695,277 +684,21 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
setParam(name, VarType.Vector4, value);
}
- private ColorRGBA getAmbientColor(LightList lightList, boolean removeLights) {
- ambientLightColor.set(0, 0, 0, 1);
- for (int j = 0; j < lightList.size(); j++) {
- Light l = lightList.get(j);
- if (l instanceof AmbientLight) {
- ambientLightColor.addLocal(l.getColor());
- if(removeLights){
- lightList.remove(l);
- }
- }
- }
- ambientLightColor.a = 1.0f;
- return ambientLightColor;
- }
-
- private static void renderMeshFromGeometry(Renderer renderer, Geometry geom) {
- Mesh mesh = geom.getMesh();
- int lodLevel = geom.getLodLevel();
- if (geom instanceof InstancedGeometry) {
- InstancedGeometry instGeom = (InstancedGeometry) geom;
- int numInstances = instGeom.getActualNumInstances();
- if (numInstances == 0) {
- return;
- }
- if (renderer.getCaps().contains(Caps.MeshInstancing)) {
- renderer.renderMesh(mesh, lodLevel, numInstances, instGeom.getAllInstanceData());
- } else {
- throw new RendererException("Mesh instancing is not supported by the video hardware");
- }
- } else {
- renderer.renderMesh(mesh, lodLevel, 1, null);
- }
- }
-
- /**
- * Uploads the lights in the light list as two uniform arrays.
*
- *
- * uniform vec4 g_LightColor[numLights];
//
- * g_LightColor.rgb is the diffuse/specular color of the light.
//
- * g_Lightcolor.a is the type of light, 0 = Directional, 1 = Point,
//
- * 2 = Spot.
- * uniform vec4 g_LightPosition[numLights];
//
- * g_LightPosition.xyz is the position of the light (for point lights)
- * // or the direction of the light (for directional lights).
//
- * g_LightPosition.w is the inverse radius (1/r) of the light (for
- * attenuation)
- */
- protected int updateLightListUniforms(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex) {
- if (numLights == 0) { // this shader does not do lighting, ignore.
- return 0;
- }
-
- Uniform lightData = shader.getUniform("g_LightData");
- lightData.setVector4Length(numLights * 3);//8 lights * max 3
- Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
-
-
- if (startIndex != 0) {
- // apply additive blending for 2nd and future passes
- rm.getRenderer().applyRenderState(additiveLight);
- ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
- }else{
- ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList,true));
- }
-
- int lightDataIndex = 0;
- TempVars vars = TempVars.get();
- Vector4f tmpVec = vars.vect4f1;
- int curIndex;
- int endIndex = numLights + startIndex;
- for (curIndex = startIndex; curIndex < endIndex && curIndex < lightList.size(); curIndex++) {
-
-
- Light l = lightList.get(curIndex);
- if(l.getType() == Light.Type.Ambient){
- endIndex++;
- continue;
- }
- ColorRGBA color = l.getColor();
- //Color
- lightData.setVector4InArray(color.getRed(),
- color.getGreen(),
- color.getBlue(),
- l.getType().getId(),
- lightDataIndex);
- lightDataIndex++;
-
- switch (l.getType()) {
- case Directional:
- DirectionalLight dl = (DirectionalLight) l;
- Vector3f dir = dl.getDirection();
- //Data directly sent in view space to avoid a matrix mult for each pixel
- tmpVec.set(dir.getX(), dir.getY(), dir.getZ(), 0.0f);
- rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
-// tmpVec.divideLocal(tmpVec.w);
-// tmpVec.normalizeLocal();
- lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), -1, lightDataIndex);
- lightDataIndex++;
- //PADDING
- lightData.setVector4InArray(0,0,0,0, lightDataIndex);
- lightDataIndex++;
- break;
- case Point:
- PointLight pl = (PointLight) l;
- Vector3f pos = pl.getPosition();
- float invRadius = pl.getInvRadius();
- tmpVec.set(pos.getX(), pos.getY(), pos.getZ(), 1.0f);
- rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
- //tmpVec.divideLocal(tmpVec.w);
- lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRadius, lightDataIndex);
- lightDataIndex++;
- //PADDING
- lightData.setVector4InArray(0,0,0,0, lightDataIndex);
- lightDataIndex++;
- break;
- case Spot:
- SpotLight sl = (SpotLight) l;
- Vector3f pos2 = sl.getPosition();
- Vector3f dir2 = sl.getDirection();
- float invRange = sl.getInvSpotRange();
- float spotAngleCos = sl.getPackedAngleCos();
- tmpVec.set(pos2.getX(), pos2.getY(), pos2.getZ(), 1.0f);
- rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
- // tmpVec.divideLocal(tmpVec.w);
- lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRange, lightDataIndex);
- lightDataIndex++;
-
- //We transform the spot direction in view space here to save 5 varying later in the lighting shader
- //one vec4 less and a vec4 that becomes a vec3
- //the downside is that spotAngleCos decoding happens now in the frag shader.
- tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0.0f);
- rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
- tmpVec.normalizeLocal();
- lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos, lightDataIndex);
- lightDataIndex++;
- break;
- default:
- throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
- }
- }
- vars.release();
- //Padding of unsued buffer space
- while(lightDataIndex < numLights * 3) {
- lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex);
- lightDataIndex++;
- }
- return curIndex;
- }
-
- protected void renderMultipassLighting(Shader shader, Geometry g, LightList lightList, RenderManager rm) {
-
- Renderer r = rm.getRenderer();
- Uniform lightDir = shader.getUniform("g_LightDirection");
- Uniform lightColor = shader.getUniform("g_LightColor");
- Uniform lightPos = shader.getUniform("g_LightPosition");
- Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
- boolean isFirstLight = true;
- boolean isSecondLight = false;
-
- for (int i = 0; i < lightList.size(); i++) {
- Light l = lightList.get(i);
- if (l instanceof AmbientLight) {
- continue;
- }
-
- if (isFirstLight) {
- // set ambient color for first light only
- ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, false));
- isFirstLight = false;
- isSecondLight = true;
- } else if (isSecondLight) {
- ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
- // apply additive blending for 2nd and future lights
- r.applyRenderState(additiveLight);
- isSecondLight = false;
- }
-
- TempVars vars = TempVars.get();
- Quaternion tmpLightDirection = vars.quat1;
- Quaternion tmpLightPosition = vars.quat2;
- ColorRGBA tmpLightColor = vars.color;
- Vector4f tmpVec = vars.vect4f1;
-
- ColorRGBA color = l.getColor();
- tmpLightColor.set(color);
- tmpLightColor.a = l.getType().getId();
- lightColor.setValue(VarType.Vector4, tmpLightColor);
-
- switch (l.getType()) {
- case Directional:
- DirectionalLight dl = (DirectionalLight) l;
- Vector3f dir = dl.getDirection();
- //FIXME : there is an inconstency here due to backward
- //compatibility of the lighting shader.
- //The directional light direction is passed in the
- //LightPosition uniform. The lighting shader needs to be
- //reworked though in order to fix this.
- tmpLightPosition.set(dir.getX(), dir.getY(), dir.getZ(), -1);
- lightPos.setValue(VarType.Vector4, tmpLightPosition);
- tmpLightDirection.set(0, 0, 0, 0);
- lightDir.setValue(VarType.Vector4, tmpLightDirection);
- break;
- case Point:
- PointLight pl = (PointLight) l;
- Vector3f pos = pl.getPosition();
- float invRadius = pl.getInvRadius();
-
- tmpLightPosition.set(pos.getX(), pos.getY(), pos.getZ(), invRadius);
- lightPos.setValue(VarType.Vector4, tmpLightPosition);
- tmpLightDirection.set(0, 0, 0, 0);
- lightDir.setValue(VarType.Vector4, tmpLightDirection);
- break;
- case Spot:
- SpotLight sl = (SpotLight) l;
- Vector3f pos2 = sl.getPosition();
- Vector3f dir2 = sl.getDirection();
- float invRange = sl.getInvSpotRange();
- float spotAngleCos = sl.getPackedAngleCos();
-
- tmpLightPosition.set(pos2.getX(), pos2.getY(), pos2.getZ(), invRange);
- lightPos.setValue(VarType.Vector4, tmpLightPosition);
-
- //We transform the spot direction in view space here to save 5 varying later in the lighting shader
- //one vec4 less and a vec4 that becomes a vec3
- //the downside is that spotAngleCos decoding happens now in the frag shader.
- tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0);
- rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
- tmpLightDirection.set(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos);
-
- lightDir.setValue(VarType.Vector4, tmpLightDirection);
-
- break;
- default:
- throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
- }
- vars.release();
- r.setShader(shader);
- renderMeshFromGeometry(r, g);
- }
-
- if (isFirstLight) {
- // Either there are no lights at all, or only ambient lights.
- // Render a dummy "normal light" so we can see the ambient color.
- ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, false));
- lightColor.setValue(VarType.Vector4, ColorRGBA.BlackNoAlpha);
- lightPos.setValue(VarType.Vector4, nullDirLight);
- r.setShader(shader);
- renderMeshFromGeometry(r, g);
- }
- }
-
/**
* Select the technique to use for rendering this material.
*
- * If name
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.
- *
* Any candidate technique for selection (either default or named)
* must be verified to be compatible with the system, for that, the
* renderManager
is queried for capabilities.
*
- * @param name The name of the technique to select, pass "Default" to
- * select one of the default techniques.
+ * @param name The name of the technique to select, pass
+ * {@link TechniqueDef#DEFAULT_TECHNIQUE_NAME} to select one of the default
+ * techniques.
* @param renderManager The {@link RenderManager render manager}
* to query for capabilities.
*
- * @throws IllegalArgumentException If "Default" is passed and no default
- * techniques are available on the material definition, or if a name
- * is passed but there's no technique by that name.
+ * @throws IllegalArgumentException If no technique exists with the given
+ * name.
* @throws UnsupportedOperationException If no candidate technique supports
* the system capabilities.
*/
@@ -974,49 +707,34 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
Technique tech = techniques.get(name);
// When choosing technique, we choose one that
// supports all the caps.
- EnumSet rendererCaps = renderManager.getRenderer().getCaps();
if (tech == null) {
+ EnumSet rendererCaps = renderManager.getRenderer().getCaps();
+ List techDefs = def.getTechniqueDefs(name);
- if (name.equals("Default")) {
- List techDefs = def.getDefaultTechniques();
- if (techDefs == null || techDefs.isEmpty()) {
- throw new IllegalArgumentException("No default techniques are available on material '" + def.getName() + "'");
- }
+ if (techDefs == null || techDefs.isEmpty()) {
+ throw new IllegalArgumentException(
+ String.format("The requested technique %s is not available on material %s", name, 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;
- }
+ 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 {
- // create "special" technique instance
- TechniqueDef techDef = def.getTechniqueDef(name);
- if (techDef == null) {
- throw new IllegalArgumentException("For material " + def.getName() + ", technique not found: " + name);
- }
-
- if (!rendererCaps.containsAll(techDef.getRequiredCaps())) {
- throw new UnsupportedOperationException("The explicitly chosen technique '" + name + "' on material '" + def.getName() + "'\n"
- + "requires caps " + techDef.getRequiredCaps() + " which are not "
- + "supported by the video renderer");
}
-
- tech = new Technique(this, techDef);
- techniques.put(name, tech);
+ lastTech = techDef;
+ }
+ if (tech == null) {
+ throw new UnsupportedOperationException(
+ String.format("No technique '%s' on material "
+ + "'%s' is supported by the video hardware. "
+ + "The capabilities %s are required.",
+ name, def.getName(), lastTech.getRequiredCaps()));
}
} else if (technique == tech) {
// attempting to switch to an already
@@ -1025,20 +743,82 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
}
technique = tech;
- tech.makeCurrent(def.getAssetManager(), true, rendererCaps, renderManager);
+ tech.notifyTechniqueSwitched();
// shader was changed
sortingId = -1;
}
- private void autoSelectTechnique(RenderManager rm) {
- if (technique == null) {
- selectTechnique("Default", rm);
- } else {
- technique.makeCurrent(def.getAssetManager(), false, rm.getRenderer().getCaps(), rm);
+ private int applyOverrides(Renderer renderer, Shader shader, List overrides, int unit) {
+ for (MatParamOverride override : overrides) {
+ VarType type = override.getVarType();
+
+ MatParam paramDef = def.getMaterialParam(override.getName());
+
+ if (paramDef == null || paramDef.getVarType() != type || !override.isEnabled()) {
+ continue;
+ }
+
+ Uniform uniform = shader.getUniform(override.getPrefixedName());
+
+ if (override.getValue() != null) {
+ if (type.isTextureType()) {
+ renderer.setTexture(unit, (Texture) override.getValue());
+ uniform.setValue(VarType.Int, unit);
+ unit++;
+ } else {
+ uniform.setValue(type, override.getValue());
+ }
+ } else {
+ uniform.clearValue();
+ }
}
+ return unit;
}
+ private void updateShaderMaterialParameters(Renderer renderer, Shader shader,
+ List worldOverrides, List 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++) {
+ MatParam param = paramValues.getValue(i);
+ VarType type = param.getVarType();
+ Uniform uniform = shader.getUniform(param.getPrefixedName());
+
+ if (uniform.isSetByCurrentMaterial()) {
+ continue;
+ }
+
+ if (type.isTextureType()) {
+ renderer.setTexture(unit, (Texture) param.getValue());
+ uniform.setValue(VarType.Int, unit);
+ unit++;
+ } else {
+ uniform.setValue(type, param.getValue());
+ }
+ }
+
+ }
+
+ private void updateRenderState(RenderManager renderManager, Renderer renderer, TechniqueDef techniqueDef) {
+ if (renderManager.getForcedRenderState() != null) {
+ renderer.applyRenderState(renderManager.getForcedRenderState());
+ } else {
+ if (techniqueDef.getRenderState() != null) {
+ renderer.applyRenderState(techniqueDef.getRenderState().copyMergedTo(additionalState, mergedRenderState));
+ } else {
+ renderer.applyRenderState(RenderState.DEFAULT.copyMergedTo(additionalState, mergedRenderState));
+ }
+ }
+ }
+
/**
* Preloads this material for the given render manager.
*
@@ -1046,20 +826,23 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
* used for rendering, there won't be any delay since the material has
* been already been setup for rendering.
*
- * @param rm The render manager to preload for
+ * @param renderManager The render manager to preload for
*/
- public void preload(RenderManager rm) {
- autoSelectTechnique(rm);
-
- Renderer r = rm.getRenderer();
- TechniqueDef techDef = technique.getDef();
+ public void preload(RenderManager renderManager) {
+ if (technique == null) {
+ selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager);
+ }
+ TechniqueDef techniqueDef = technique.getDef();
+ Renderer renderer = renderManager.getRenderer();
+ EnumSet rendererCaps = renderer.getCaps();
- Collection params = paramValues.values();
- for (MatParam param : params) {
- param.apply(r, technique);
+ if (techniqueDef.isNoRender()) {
+ return;
}
- r.setShader(technique.getShader());
+ Shader shader = technique.makeCurrent(renderManager, null, null, null, rendererCaps);
+ updateShaderMaterialParameters(renderer, shader, null, null);
+ renderManager.getRenderer().setShader(shader);
}
private void clearUniformsSetByCurrent(Shader shader) {
@@ -1141,80 +924,46 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
*
*
*
- * @param geom The geometry to render
+ * @param geometry The geometry to render
* @param lights Presorted and filtered light list to use for rendering
- * @param rm The render manager requesting the rendering
+ * @param renderManager The render manager requesting the rendering
*/
- public void render(Geometry geom, LightList lights, RenderManager rm) {
- autoSelectTechnique(rm);
- TechniqueDef techDef = technique.getDef();
-
- if (techDef.isNoRender()) return;
-
- Renderer r = rm.getRenderer();
-
- if (rm.getForcedRenderState() != null) {
- r.applyRenderState(rm.getForcedRenderState());
- } else {
- if (techDef.getRenderState() != null) {
- r.applyRenderState(techDef.getRenderState().copyMergedTo(additionalState, mergedRenderState));
- } else {
- r.applyRenderState(RenderState.DEFAULT.copyMergedTo(additionalState, mergedRenderState));
- }
- }
-
-
- // update camera and world matrices
- // NOTE: setWorldTransform should have been called already
-
- // reset unchanged uniform flag
- clearUniformsSetByCurrent(technique.getShader());
- rm.updateUniformBindings(technique.getWorldBindUniforms());
-
-
- // setup textures and uniforms
- for (int i = 0; i < paramValues.size(); i++) {
- MatParam param = paramValues.getValue(i);
- param.apply(r, technique);
+ public void render(Geometry geometry, LightList lights, RenderManager renderManager) {
+ if (technique == null) {
+ selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager);
}
-
- Shader shader = technique.getShader();
-
- // send lighting information, if needed
- switch (techDef.getLightMode()) {
- case Disable:
- break;
- case SinglePass:
- int nbRenderedLights = 0;
- resetUniformsNotSetByCurrent(shader);
- if (lights.size() == 0) {
- nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, 0);
- r.setShader(shader);
- renderMeshFromGeometry(r, geom);
- } else {
- while (nbRenderedLights < lights.size()) {
- nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, nbRenderedLights);
- r.setShader(shader);
- renderMeshFromGeometry(r, geom);
- }
- }
- return;
- case FixedPipeline:
- throw new IllegalArgumentException("OpenGL1 is not supported");
- case MultiPass:
- // NOTE: Special case!
- resetUniformsNotSetByCurrent(shader);
- renderMultipassLighting(shader, geom, lights, rm);
- // very important, notice the return statement!
- return;
+
+ TechniqueDef techniqueDef = technique.getDef();
+ Renderer renderer = renderManager.getRenderer();
+ EnumSet rendererCaps = renderer.getCaps();
+
+ if (techniqueDef.isNoRender()) {
+ return;
}
- // upload and bind shader
- // any unset uniforms will be set to 0
+ // Apply render state
+ updateRenderState(renderManager, renderer, techniqueDef);
+
+ // Get world overrides
+ List overrides = geometry.getWorldMatParamOverrides();
+
+ // Select shader to use
+ Shader shader = technique.makeCurrent(renderManager, overrides, renderManager.getForcedMatParams(), lights, rendererCaps);
+
+ // Begin tracking which uniforms were changed by material.
+ clearUniformsSetByCurrent(shader);
+
+ // Set uniform bindings
+ renderManager.updateUniformBindings(shader);
+
+ // Set material parameters
+ updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams());
+
+ // Clear any uniforms not changed by material.
resetUniformsNotSetByCurrent(shader);
- r.setShader(shader);
-
- renderMeshFromGeometry(r, geom);
+
+ // Delegate rendering to the technique
+ technique.render(renderManager, shader, geometry, lights);
}
/**
@@ -1239,6 +988,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
oc.write(name, "name", null);
oc.writeStringSavableMap(paramValues, "parameters", null);
}
+
+ @Override
+ public String toString() {
+ return "Material[name=" + name +
+ ", def=" + def.getName() +
+ ", tech=" + technique.getDef().getName() +
+ "]";
+ }
public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this);
@@ -1296,11 +1053,6 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
MatParam param = entry.getValue();
if (param instanceof MatParamTexture) {
MatParamTexture texVal = (MatParamTexture) param;
-
- if (nextTexUnit < texVal.getUnit() + 1) {
- nextTexUnit = texVal.getUnit() + 1;
- }
-
// the texture failed to load for this param
// do not add to param values
if (texVal.getTextureValue() == null || texVal.getTextureValue().getImage() == null) {
@@ -1335,14 +1087,11 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
// Try to guess values of "apply" render state based on defaults
// if value != default then set apply to true
additionalState.applyPolyOffset = additionalState.offsetEnabled;
- additionalState.applyAlphaFallOff = additionalState.alphaTest;
- additionalState.applyAlphaTest = additionalState.alphaTest;
additionalState.applyBlendMode = additionalState.blendMode != BlendMode.Off;
additionalState.applyColorWrite = !additionalState.colorWrite;
additionalState.applyCullMode = additionalState.cullMode != FaceCullMode.Back;
additionalState.applyDepthTest = !additionalState.depthTest;
additionalState.applyDepthWrite = !additionalState.depthWrite;
- additionalState.applyPointSprite = additionalState.pointSprite;
additionalState.applyStencilTest = additionalState.stencilTest;
additionalState.applyWireFrame = additionalState.wireframe;
}
diff --git a/jme3-core/src/main/java/com/jme3/material/MaterialDef.java b/jme3-core/src/main/java/com/jme3/material/MaterialDef.java
index 47d672f3b..fa205460e 100644
--- a/jme3-core/src/main/java/com/jme3/material/MaterialDef.java
+++ b/jme3-core/src/main/java/com/jme3/material/MaterialDef.java
@@ -32,6 +32,7 @@
package com.jme3.material;
import com.jme3.asset.AssetManager;
+import com.jme3.renderer.Caps;
import com.jme3.shader.VarType;
import com.jme3.texture.image.ColorSpace;
import java.util.*;
@@ -51,8 +52,7 @@ public class MaterialDef {
private String assetName;
private AssetManager assetManager;
- private List defaultTechs;
- private Map techniques;
+ private Map> techniques;
private Map matParams;
/**
@@ -70,9 +70,8 @@ public class MaterialDef {
public MaterialDef(AssetManager assetManager, String name){
this.assetManager = assetManager;
this.name = name;
- techniques = new HashMap();
+ techniques = new HashMap>();
matParams = new HashMap();
- defaultTechs = new ArrayList();
logger.log(Level.FINE, "Loaded material definition: {0}", name);
}
@@ -135,7 +134,7 @@ public class MaterialDef {
* @see ColorSpace
*/
public void addMaterialParamTexture(VarType type, String name, ColorSpace colorSpace) {
- matParams.put(name, new MatParamTexture(type, name, null , 0, colorSpace));
+ matParams.put(name, new MatParamTexture(type, name, null, colorSpace));
}
/**
@@ -164,40 +163,26 @@ public class MaterialDef {
/**
* Adds a new technique definition to this material definition.
- *
- * If the technique name is "Default", it will be added
- * to the list of {@link MaterialDef#getDefaultTechniques() default techniques}.
- *
+ *
* @param technique The technique definition to add.
*/
public void addTechniqueDef(TechniqueDef technique) {
- if (technique.getName().equals("Default")) {
- defaultTechs.add(technique);
- } else {
- techniques.put(technique.getName(), technique);
+ List list = techniques.get(technique.getName());
+ if (list == null) {
+ list = new ArrayList<>();
+ techniques.put(technique.getName(), list);
}
+ list.add(technique);
}
/**
- * Returns a list of all default techniques.
- *
- * @return a list of all default techniques.
- */
- public List getDefaultTechniques(){
- return defaultTechs;
- }
-
- /**
- * Returns a technique definition with the given name.
- * This does not include default techniques which can be
- * retrieved via {@link MaterialDef#getDefaultTechniques() }.
- *
- * @param name The name of the technique definition to find
- *
- * @return The technique definition, or null if cannot be found.
+ * Returns technique definitions with the given name.
+ *
+ * @param name The name of the technique definitions to find
+ *
+ * @return The technique definitions, or null if cannot be found.
*/
- public TechniqueDef getTechniqueDef(String name) {
+ public List getTechniqueDefs(String name) {
return techniques.get(name);
}
-
}
diff --git a/jme3-core/src/main/java/com/jme3/material/RenderState.java b/jme3-core/src/main/java/com/jme3/material/RenderState.java
index 94cae3f50..1fb33a079 100644
--- a/jme3-core/src/main/java/com/jme3/material/RenderState.java
+++ b/jme3-core/src/main/java/com/jme3/material/RenderState.java
@@ -75,12 +75,11 @@ public class RenderState implements Cloneable, Savable {
/**
* TestFunction
specifies the testing function for stencil test
- * function and alpha test function.
+ * function.
*
- * The functions work similarly as described except that for stencil
- * test function, the reference value given in the stencil command is
- * the input value while the reference is the value already in the stencil
- * buffer.
+ *
+ * The reference value given in the stencil command is the input value while
+ * the reference is the value already in the stencil buffer.
*/
public enum TestFunction {
@@ -118,7 +117,94 @@ public class RenderState implements Cloneable, Savable {
/**
* The test always passes
*/
- Always,}
+ Always
+ }
+
+ /**
+ * BlendEquation
specifies the blending equation to combine
+ * pixels.
+ */
+ public enum BlendEquation {
+ /**
+ * Sets the blend equation so that the source and destination data are
+ * added. (Default) Clamps to [0,1] Useful for things like antialiasing
+ * and transparency.
+ */
+ Add,
+ /**
+ * Sets the blend equation so that the source and destination data are
+ * subtracted (Src - Dest). Clamps to [0,1] Falls back to Add if
+ * supportsSubtract is false.
+ */
+ Subtract,
+ /**
+ * Same as Subtract, but the order is reversed (Dst - Src). Clamps to
+ * [0,1] Falls back to Add if supportsSubtract is false.
+ */
+ ReverseSubtract,
+ /**
+ * Sets the blend equation so that each component of the result color is
+ * the minimum of the corresponding components of the source and
+ * destination colors. This and Max are useful for applications that
+ * analyze image data (image thresholding against a constant color, for
+ * example). Falls back to Add if supportsMinMax is false.
+ */
+ Min,
+ /**
+ * Sets the blend equation so that each component of the result color is
+ * the maximum of the corresponding components of the source and
+ * destination colors. This and Min are useful for applications that
+ * analyze image data (image thresholding against a constant color, for
+ * example). Falls back to Add if supportsMinMax is false.
+ */
+ Max
+ }
+
+ /**
+ * BlendEquationAlpha
specifies the blending equation to
+ * combine pixels for the alpha component.
+ */
+ public enum BlendEquationAlpha {
+ /**
+ * Sets the blend equation to be the same as the one defined by
+ * {@link #blendEquation}.
+ *
+ */
+ InheritColor,
+ /**
+ * Sets the blend equation so that the source and destination data are
+ * added. (Default) Clamps to [0,1] Useful for things like antialiasing
+ * and transparency.
+ */
+ Add,
+ /**
+ * Sets the blend equation so that the source and destination data are
+ * subtracted (Src - Dest). Clamps to [0,1] Falls back to Add if
+ * supportsSubtract is false.
+ */
+ Subtract,
+ /**
+ * Same as Subtract, but the order is reversed (Dst - Src). Clamps to
+ * [0,1] Falls back to Add if supportsSubtract is false.
+ */
+ ReverseSubtract,
+ /**
+ * Sets the blend equation so that the result alpha is the minimum of
+ * the source alpha and destination alpha. This and Max are useful for
+ * applications that analyze image data (image thresholding against a
+ * constant color, for example). Falls back to Add if supportsMinMax is
+ * false.
+ */
+ Min,
+ /**
+ * sSets the blend equation so that the result alpha is the maximum of
+ * the source alpha and destination alpha. This and Min are useful for
+ * applications that analyze image data (image thresholding against a
+ * constant color, for example). Falls back to Add if supportsMinMax is
+ * false.
+ */
+ Max
+ }
/**
* BlendMode
specifies the blending operation to use.
@@ -276,19 +362,16 @@ public class RenderState implements Cloneable, Savable {
}
static {
- ADDITIONAL.applyPointSprite = false;
ADDITIONAL.applyWireFrame = false;
ADDITIONAL.applyCullMode = false;
ADDITIONAL.applyDepthWrite = false;
ADDITIONAL.applyDepthTest = false;
ADDITIONAL.applyColorWrite = false;
+ ADDITIONAL.applyBlendEquation = false;
+ ADDITIONAL.applyBlendEquationAlpha = false;
ADDITIONAL.applyBlendMode = false;
- ADDITIONAL.applyAlphaTest = false;
- ADDITIONAL.applyAlphaFallOff = false;
ADDITIONAL.applyPolyOffset = false;
}
- boolean pointSprite = false;
- boolean applyPointSprite = true;
boolean wireframe = false;
boolean applyWireFrame = true;
FaceCullMode cullMode = FaceCullMode.Back;
@@ -299,12 +382,12 @@ public class RenderState implements Cloneable, Savable {
boolean applyDepthTest = true;
boolean colorWrite = true;
boolean applyColorWrite = true;
+ BlendEquation blendEquation = BlendEquation.Add;
+ boolean applyBlendEquation = true;
+ BlendEquationAlpha blendEquationAlpha = BlendEquationAlpha.InheritColor;
+ boolean applyBlendEquationAlpha = true;
BlendMode blendMode = BlendMode.Off;
boolean applyBlendMode = true;
- boolean alphaTest = false;
- boolean applyAlphaTest = true;
- float alphaFallOff = 0;
- boolean applyAlphaFallOff = true;
float offsetFactor = 0;
float offsetUnits = 0;
boolean offsetEnabled = false;
@@ -315,10 +398,7 @@ public class RenderState implements Cloneable, Savable {
boolean applyLineWidth = false;
TestFunction depthFunc = TestFunction.LessOrEqual;
//by default depth func will be applied anyway if depth test is applied
- boolean applyDepthFunc = false;
- //by default alpha func will be applied anyway if alpha test is applied
- TestFunction alphaFunc = TestFunction.Greater;
- boolean applyAlphaFunc = false;
+ boolean applyDepthFunc = false;
StencilOperation frontStencilStencilFailOperation = StencilOperation.Keep;
StencilOperation frontStencilDepthFailOperation = StencilOperation.Keep;
StencilOperation frontStencilDepthPassOperation = StencilOperation.Keep;
@@ -331,15 +411,13 @@ public class RenderState implements Cloneable, Savable {
public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);
- oc.write(pointSprite, "pointSprite", false);
+ oc.write(true, "pointSprite", false);
oc.write(wireframe, "wireframe", false);
oc.write(cullMode, "cullMode", FaceCullMode.Back);
oc.write(depthWrite, "depthWrite", true);
oc.write(depthTest, "depthTest", true);
oc.write(colorWrite, "colorWrite", true);
oc.write(blendMode, "blendMode", BlendMode.Off);
- oc.write(alphaTest, "alphaTest", false);
- oc.write(alphaFallOff, "alphaFallOff", 0);
oc.write(offsetEnabled, "offsetEnabled", false);
oc.write(offsetFactor, "offsetFactor", 0);
oc.write(offsetUnits, "offsetUnits", 0);
@@ -352,38 +430,34 @@ public class RenderState implements Cloneable, Savable {
oc.write(backStencilDepthPassOperation, "backStencilDepthPassOperation", StencilOperation.Keep);
oc.write(frontStencilFunction, "frontStencilFunction", TestFunction.Always);
oc.write(backStencilFunction, "backStencilFunction", TestFunction.Always);
+ oc.write(blendEquation, "blendEquation", BlendEquation.Add);
+ oc.write(blendEquationAlpha, "blendEquationAlpha", BlendEquationAlpha.InheritColor);
oc.write(depthFunc, "depthFunc", TestFunction.LessOrEqual);
- oc.write(alphaFunc, "alphaFunc", TestFunction.Greater);
oc.write(lineWidth, "lineWidth", 1);
// Only "additional render state" has them set to false by default
- oc.write(applyPointSprite, "applyPointSprite", true);
oc.write(applyWireFrame, "applyWireFrame", true);
oc.write(applyCullMode, "applyCullMode", true);
oc.write(applyDepthWrite, "applyDepthWrite", true);
oc.write(applyDepthTest, "applyDepthTest", true);
oc.write(applyColorWrite, "applyColorWrite", true);
+ oc.write(applyBlendEquation, "applyBlendEquation", true);
+ oc.write(applyBlendEquationAlpha, "applyBlendEquationAlpha", true);
oc.write(applyBlendMode, "applyBlendMode", true);
- oc.write(applyAlphaTest, "applyAlphaTest", true);
- oc.write(applyAlphaFallOff, "applyAlphaFallOff", true);
oc.write(applyPolyOffset, "applyPolyOffset", true);
oc.write(applyDepthFunc, "applyDepthFunc", true);
- oc.write(applyAlphaFunc, "applyAlphaFunc", false);
oc.write(applyLineWidth, "applyLineWidth", true);
}
public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this);
- pointSprite = ic.readBoolean("pointSprite", false);
wireframe = ic.readBoolean("wireframe", false);
cullMode = ic.readEnum("cullMode", FaceCullMode.class, FaceCullMode.Back);
depthWrite = ic.readBoolean("depthWrite", true);
depthTest = ic.readBoolean("depthTest", true);
colorWrite = ic.readBoolean("colorWrite", true);
blendMode = ic.readEnum("blendMode", BlendMode.class, BlendMode.Off);
- alphaTest = ic.readBoolean("alphaTest", false);
- alphaFallOff = ic.readFloat("alphaFallOff", 0);
offsetEnabled = ic.readBoolean("offsetEnabled", false);
offsetFactor = ic.readFloat("offsetFactor", 0);
offsetUnits = ic.readFloat("offsetUnits", 0);
@@ -396,23 +470,22 @@ public class RenderState implements Cloneable, Savable {
backStencilDepthPassOperation = ic.readEnum("backStencilDepthPassOperation", StencilOperation.class, StencilOperation.Keep);
frontStencilFunction = ic.readEnum("frontStencilFunction", TestFunction.class, TestFunction.Always);
backStencilFunction = ic.readEnum("backStencilFunction", TestFunction.class, TestFunction.Always);
+ blendEquation = ic.readEnum("blendEquation", BlendEquation.class, BlendEquation.Add);
+ blendEquationAlpha = ic.readEnum("blendEquationAlpha", BlendEquationAlpha.class, BlendEquationAlpha.InheritColor);
depthFunc = ic.readEnum("depthFunc", TestFunction.class, TestFunction.LessOrEqual);
- alphaFunc = ic.readEnum("alphaFunc", TestFunction.class, TestFunction.Greater);
lineWidth = ic.readFloat("lineWidth", 1);
- applyPointSprite = ic.readBoolean("applyPointSprite", true);
applyWireFrame = ic.readBoolean("applyWireFrame", true);
applyCullMode = ic.readBoolean("applyCullMode", true);
applyDepthWrite = ic.readBoolean("applyDepthWrite", true);
applyDepthTest = ic.readBoolean("applyDepthTest", true);
applyColorWrite = ic.readBoolean("applyColorWrite", true);
+ applyBlendEquation = ic.readBoolean("applyBlendEquation", true);
+ applyBlendEquationAlpha = ic.readBoolean("applyBlendEquationAlpha", true);
applyBlendMode = ic.readBoolean("applyBlendMode", true);
- applyAlphaTest = ic.readBoolean("applyAlphaTest", true);
- applyAlphaFallOff = ic.readBoolean("applyAlphaFallOff", true);
applyPolyOffset = ic.readBoolean("applyPolyOffset", true);
applyDepthFunc = ic.readBoolean("applyDepthFunc", true);
- applyAlphaFunc = ic.readBoolean("applyAlphaFunc", false);
applyLineWidth = ic.readBoolean("applyLineWidth", true);
@@ -433,8 +506,8 @@ public class RenderState implements Cloneable, Savable {
}
/**
- * returns true if the given renderState is equall to this one
- * @param o the renderState to compate to
+ * returns true if the given renderState is equal to this one
+ * @param o the renderState to compare to
* @return true if the renderStates are equal
*/
@Override
@@ -446,9 +519,6 @@ public class RenderState implements Cloneable, Savable {
return false;
}
RenderState rs = (RenderState) o;
- if (pointSprite != rs.pointSprite) {
- return false;
- }
if (wireframe != rs.wireframe) {
return false;
@@ -475,23 +545,19 @@ public class RenderState implements Cloneable, Savable {
return false;
}
- if (blendMode != rs.blendMode) {
+ if (blendEquation != rs.blendEquation) {
return false;
}
- if (alphaTest != rs.alphaTest) {
+ if (blendEquationAlpha != rs.blendEquationAlpha) {
return false;
}
- if (alphaTest) {
- if (alphaFunc != rs.alphaFunc) {
- return false;
- }
- }
- if (alphaFallOff != rs.alphaFallOff) {
+ if (blendMode != rs.blendMode) {
return false;
}
+
if (offsetEnabled != rs.offsetEnabled) {
return false;
}
@@ -544,70 +610,30 @@ public class RenderState implements Cloneable, Savable {
}
/**
- * Enables point sprite mode.
- *
- *
When point sprite is enabled, any meshes
- * with the type of {@link Mode#Points} will be rendered as 2D quads
- * with texturing enabled. Fragment shaders can write to the
- * gl_PointCoord
variable to manipulate the texture coordinate
- * for each pixel. The size of the 2D quad can be controlled by writing
- * to the gl_PointSize
variable in the vertex shader.
- *
- * @param pointSprite Enables Point Sprite mode.
+ * @deprecated Does nothing. Point sprite is already enabled by default for
+ * all supported platforms. jME3 does not support rendering conventional
+ * point clouds.
*/
+ @Deprecated
public void setPointSprite(boolean pointSprite) {
- applyPointSprite = true;
- this.pointSprite = pointSprite;
- cachedHashCode = -1;
}
/**
- * Sets the alpha fall off value for alpha testing.
- *
- *
If the pixel's alpha value is greater than the
- * alphaFallOff
then the pixel will be rendered, otherwise
- * the pixel will be discarded.
- *
- * Note : Alpha test is deprecated since opengl 3.0 and does not exists in
- * openglES 2.0.
- * The prefered way is to use the alphaDiscardThreshold on the material
- * Or have a shader that discards the pixel when its alpha value meets the
- * discarding condition.
- *
- * @param alphaFallOff The alpha of all rendered pixels must be higher
- * than this value to be rendered. This value should be between 0 and 1.
- *
- * @see RenderState#setAlphaTest(boolean)
+ * @deprecated Does nothing. To use alpha test, set the
+ * AlphaDiscardThreshold
material parameter.
+ * @param alphaFallOff does nothing
*/
+ @Deprecated
public void setAlphaFallOff(float alphaFallOff) {
- applyAlphaFallOff = true;
- this.alphaFallOff = alphaFallOff;
- cachedHashCode = -1;
}
/**
- * Enable alpha testing.
- *
- *
When alpha testing is enabled, all input pixels' alpha are compared
- * to the {@link RenderState#setAlphaFallOff(float) constant alpha falloff}.
- * If the input alpha is greater than the falloff, the pixel will be rendered,
- * otherwise it will be discarded.
- *
- * @param alphaTest Set to true to enable alpha testing.
- *
- * Note : Alpha test is deprecated since opengl 3.0 and does not exists in
- * openglES 2.0.
- * The prefered way is to use the alphaDiscardThreshold on the material
- * Or have a shader that discards the pixel when its alpha value meets the
- * discarding condition.
- *
- *
- * @see RenderState#setAlphaFallOff(float)
+ * @deprecated Does nothing. To use alpha test, set the
+ * AlphaDiscardThreshold
material parameter.
+ * @param alphaTest does nothing
*/
+ @Deprecated
public void setAlphaTest(boolean alphaTest) {
- applyAlphaTest = true;
- this.alphaTest = alphaTest;
- cachedHashCode = -1;
}
/**
@@ -663,6 +689,61 @@ public class RenderState implements Cloneable, Savable {
cachedHashCode = -1;
}
+ /**
+ * Set the blending equation.
+ *
+ * When blending is enabled, (blendMode
is not
+ * {@link BlendMode#Off}) the input pixel will be blended with the pixel
+ * already in the color buffer. The blending equation is determined by the
+ * {@link BlendEquation}. For example, the mode {@link BlendMode#Additive}
+ * and {@link BlendEquation#Add} will add the input pixel's color to the
+ * color already in the color buffer:
+ *
+ * Result = Source Color + Destination Color
+ *
+ * However, the mode {@link BlendMode#Additive}
+ * and {@link BlendEquation#Subtract} will subtract the input pixel's color to the
+ * color already in the color buffer:
+ *
+ * Result = Source Color - Destination Color
+ *
+ * @param blendEquation The blend equation to use.
+ */
+ public void setBlendEquation(BlendEquation blendEquation) {
+ applyBlendEquation = true;
+ this.blendEquation = blendEquation;
+ cachedHashCode = -1;
+ }
+
+ /**
+ * Set the blending equation for the alpha component.
+ *
+ * When blending is enabled, (blendMode
is not
+ * {@link BlendMode#Off}) the input pixel will be blended with the pixel
+ * already in the color buffer. The blending equation is determined by the
+ * {@link BlendEquation} and can be overrode for the alpha component using
+ * the {@link BlendEquationAlpha} . For example, the mode
+ * {@link BlendMode#Additive} and {@link BlendEquationAlpha#Add} will add
+ * the input pixel's alpha to the alpha component already in the color
+ * buffer:
+ *
+ * Result = Source Alpha + Destination Alpha
+ *
+ * However, the mode {@link BlendMode#Additive} and
+ * {@link BlendEquationAlpha#Subtract} will subtract the input pixel's alpha
+ * to the alpha component already in the color buffer:
+ *
+ * Result = Source Alpha - Destination Alpha
+ *
+ * @param blendEquationAlpha The blend equation to use for the alpha
+ * component.
+ */
+ public void setBlendEquationAlpha(BlendEquationAlpha blendEquationAlpha) {
+ applyBlendEquationAlpha = true;
+ this.blendEquationAlpha = blendEquationAlpha;
+ cachedHashCode = -1;
+ }
+
/**
* Enable depth testing.
*
@@ -796,24 +877,10 @@ public class RenderState implements Cloneable, Savable {
}
/**
- * Sets the alpha comparision function to the given TestFunction
- * default is Greater (GL_GREATER)
- *
- * Note : Alpha test is deprecated since opengl 3.0 and does not exists in
- * openglES 2.0.
- * The prefered way is to use the alphaDiscardThreshold on the material
- * Or have a shader taht discards the pixel when its alpha value meets the
- * discarding condition.
- *
- * @see TestFunction
- * @see RenderState#setAlphaTest(boolean)
- * @see RenderState#setAlphaFallOff(float)
- * @param alphaFunc the alpha comparision function
+ * @deprecated
*/
- public void setAlphaFunc(TestFunction alphaFunc) {
- applyAlphaFunc = true;
- this.alphaFunc = alphaFunc;
- cachedHashCode = -1;
+ @Deprecated
+ public void setAlphaFunc(TestFunction alphaFunc) {
}
/**
@@ -822,6 +889,9 @@ public class RenderState implements Cloneable, Savable {
* @param lineWidth the line width.
*/
public void setLineWidth(float lineWidth) {
+ if (lineWidth < 1f) {
+ throw new IllegalArgumentException("lineWidth must be greater than or equal to 1.0");
+ }
this.lineWidth = lineWidth;
this.applyLineWidth = true;
cachedHashCode = -1;
@@ -988,6 +1058,24 @@ public class RenderState implements Cloneable, Savable {
return backStencilFunction;
}
+ /**
+ * Retrieve the blend equation.
+ *
+ * @return the blend equation.
+ */
+ public BlendEquation getBlendEquation() {
+ return blendEquation;
+ }
+
+ /**
+ * Retrieve the blend equation used for the alpha component.
+ *
+ * @return the blend equation for the alpha component.
+ */
+ public BlendEquationAlpha getBlendEquationAlpha() {
+ return blendEquationAlpha;
+ }
+
/**
* Retrieve the blend mode.
*
@@ -998,25 +1086,22 @@ public class RenderState implements Cloneable, Savable {
}
/**
- * Check if point sprite mode is enabled
- *
- * @return True if point sprite mode is enabled.
- *
- * @see RenderState#setPointSprite(boolean)
+ * @return true
+ * @deprecated Always returns true since point sprite is always enabled.
+ * @see #setPointSprite(boolean)
*/
+ @Deprecated
public boolean isPointSprite() {
- return pointSprite;
+ return true;
}
/**
- * Check if alpha test is enabled.
- *
- * @return True if alpha test is enabled.
- *
- * @see RenderState#setAlphaTest(boolean)
+ * @deprecated To use alpha test, set the AlphaDiscardThreshold
+ * material parameter.
+ * @return false
*/
public boolean isAlphaTest() {
- return alphaTest;
+ return false;
}
/**
@@ -1108,14 +1193,12 @@ public class RenderState implements Cloneable, Savable {
}
/**
- * Retrieve the alpha falloff value.
- *
- * @return the alpha falloff value.
- *
- * @see RenderState#setAlphaFallOff(float)
+ * @return 0
+ * @deprecated
*/
+ @Deprecated
public float getAlphaFallOff() {
- return alphaFallOff;
+ return 0f;
}
/**
@@ -1130,14 +1213,12 @@ public class RenderState implements Cloneable, Savable {
}
/**
- * Retrieve the alpha comparison function
- *
- * @return the alpha comparison function
- *
- * @see RenderState#setAlphaFunc(com.jme3.material.RenderState.TestFunction)
+ * @return {@link TestFunction#Greater}.
+ * @deprecated
*/
+ @Deprecated
public TestFunction getAlphaFunc() {
- return alphaFunc;
+ return TestFunction.Greater;
}
/**
@@ -1150,16 +1231,17 @@ public class RenderState implements Cloneable, Savable {
}
- public boolean isApplyAlphaFallOff() {
- return applyAlphaFallOff;
+
+ public boolean isApplyBlendMode() {
+ return applyBlendMode;
}
- public boolean isApplyAlphaTest() {
- return applyAlphaTest;
+ public boolean isApplyBlendEquation() {
+ return applyBlendEquation;
}
- public boolean isApplyBlendMode() {
- return applyBlendMode;
+ public boolean isApplyBlendEquationAlpha() {
+ return applyBlendEquationAlpha;
}
public boolean isApplyColorWrite() {
@@ -1178,9 +1260,6 @@ public class RenderState implements Cloneable, Savable {
return applyDepthWrite;
}
- public boolean isApplyPointSprite() {
- return applyPointSprite;
- }
public boolean isApplyPolyOffset() {
return applyPolyOffset;
@@ -1194,9 +1273,6 @@ public class RenderState implements Cloneable, Savable {
return applyDepthFunc;
}
- public boolean isApplyAlphaFunc() {
- return applyAlphaFunc;
- }
public boolean isApplyLineWidth() {
return applyLineWidth;
@@ -1208,7 +1284,6 @@ public class RenderState implements Cloneable, Savable {
public int contentHashCode() {
if (cachedHashCode == -1){
int hash = 7;
- hash = 79 * hash + (this.pointSprite ? 1 : 0);
hash = 79 * hash + (this.wireframe ? 1 : 0);
hash = 79 * hash + (this.cullMode != null ? this.cullMode.hashCode() : 0);
hash = 79 * hash + (this.depthWrite ? 1 : 0);
@@ -1216,9 +1291,8 @@ public class RenderState implements Cloneable, Savable {
hash = 79 * hash + (this.depthFunc != null ? this.depthFunc.hashCode() : 0);
hash = 79 * hash + (this.colorWrite ? 1 : 0);
hash = 79 * hash + (this.blendMode != null ? this.blendMode.hashCode() : 0);
- hash = 79 * hash + (this.alphaTest ? 1 : 0);
- hash = 79 * hash + (this.alphaFunc != null ? this.alphaFunc.hashCode() : 0);
- hash = 79 * hash + Float.floatToIntBits(this.alphaFallOff);
+ hash = 79 * hash + (this.blendEquation != null ? this.blendEquation.hashCode() : 0);
+ hash = 79 * hash + (this.blendEquationAlpha != null ? this.blendEquationAlpha.hashCode() : 0);
hash = 79 * hash + Float.floatToIntBits(this.offsetFactor);
hash = 79 * hash + Float.floatToIntBits(this.offsetUnits);
hash = 79 * hash + (this.offsetEnabled ? 1 : 0);
@@ -1263,11 +1337,6 @@ public class RenderState implements Cloneable, Savable {
return this;
}
- if (additionalState.applyPointSprite) {
- state.pointSprite = additionalState.pointSprite;
- } else {
- state.pointSprite = pointSprite;
- }
if (additionalState.applyWireFrame) {
state.wireframe = additionalState.wireframe;
} else {
@@ -1299,27 +1368,22 @@ public class RenderState implements Cloneable, Savable {
} else {
state.colorWrite = colorWrite;
}
- if (additionalState.applyBlendMode) {
- state.blendMode = additionalState.blendMode;
+ if (additionalState.applyBlendEquation) {
+ state.blendEquation = additionalState.blendEquation;
} else {
- state.blendMode = blendMode;
+ state.blendEquation = blendEquation;
}
- if (additionalState.applyAlphaTest) {
- state.alphaTest = additionalState.alphaTest;
+ if (additionalState.applyBlendEquationAlpha) {
+ state.blendEquationAlpha = additionalState.blendEquationAlpha;
} else {
- state.alphaTest = alphaTest;
- }
- if (additionalState.applyAlphaFunc) {
- state.alphaFunc = additionalState.alphaFunc;
+ state.blendEquationAlpha = blendEquationAlpha;
+ }
+ if (additionalState.applyBlendMode) {
+ state.blendMode = additionalState.blendMode;
} else {
- state.alphaFunc = alphaFunc;
+ state.blendMode = blendMode;
}
- if (additionalState.applyAlphaFallOff) {
- state.alphaFallOff = additionalState.alphaFallOff;
- } else {
- state.alphaFallOff = alphaFallOff;
- }
if (additionalState.applyPolyOffset) {
state.offsetEnabled = additionalState.offsetEnabled;
state.offsetFactor = additionalState.offsetFactor;
@@ -1364,16 +1428,14 @@ public class RenderState implements Cloneable, Savable {
state.cachedHashCode = -1;
return state;
}
- public void set(RenderState state) {
- pointSprite = state.pointSprite;
+
+ public void set(RenderState state) {
wireframe = state.wireframe;
cullMode = state.cullMode;
depthWrite = state.depthWrite;
depthTest = state.depthTest;
colorWrite = state.colorWrite;
blendMode = state.blendMode;
- alphaTest = state.alphaTest;
- alphaFallOff = state.alphaFallOff;
offsetEnabled = state.offsetEnabled;
offsetFactor = state.offsetFactor;
offsetUnits = state.offsetUnits;
@@ -1386,30 +1448,27 @@ public class RenderState implements Cloneable, Savable {
backStencilDepthPassOperation = state.backStencilDepthPassOperation;
frontStencilFunction = state.frontStencilFunction;
backStencilFunction = state.backStencilFunction;
+ blendEquationAlpha = state.blendEquationAlpha;
+ blendEquation = state.blendEquation;
depthFunc = state.depthFunc;
- alphaFunc = state.alphaFunc;
lineWidth = state.lineWidth;
- applyPointSprite = true;
applyWireFrame = true;
applyCullMode = true;
applyDepthWrite = true;
applyDepthTest = true;
applyColorWrite = true;
- applyBlendMode = true;
- applyAlphaTest = true;
- applyAlphaFallOff = true;
+ applyBlendEquation = true;
+ applyBlendEquationAlpha = true;
+ applyBlendMode = true;
applyPolyOffset = true;
- applyDepthFunc = true;
- applyAlphaFunc = false;
+ applyDepthFunc = true;
applyLineWidth = true;
}
@Override
public String toString() {
return "RenderState[\n"
- + "pointSprite=" + pointSprite
- + "\napplyPointSprite=" + applyPointSprite
+ "\nwireframe=" + wireframe
+ "\napplyWireFrame=" + applyWireFrame
+ "\ncullMode=" + cullMode
@@ -1421,13 +1480,11 @@ public class RenderState implements Cloneable, Savable {
+ "\napplyDepthTest=" + applyDepthTest
+ "\ncolorWrite=" + colorWrite
+ "\napplyColorWrite=" + applyColorWrite
+ + "\nblendEquation=" + blendEquation
+ + "\napplyBlendEquation=" + applyBlendEquation
+ + "\napplyBlendEquationAlpha=" + applyBlendEquationAlpha
+ "\nblendMode=" + blendMode
+ "\napplyBlendMode=" + applyBlendMode
- + "\nalphaTest=" + alphaTest
- + "\nalphaFunc=" + alphaFunc
- + "\napplyAlphaTest=" + applyAlphaTest
- + "\nalphaFallOff=" + alphaFallOff
- + "\napplyAlphaFallOff=" + applyAlphaFallOff
+ "\noffsetEnabled=" + offsetEnabled
+ "\napplyPolyOffset=" + applyPolyOffset
+ "\noffsetFactor=" + offsetFactor
diff --git a/jme3-core/src/main/java/com/jme3/material/Technique.java b/jme3-core/src/main/java/com/jme3/material/Technique.java
index 8321991bf..8ca95b178 100644
--- a/jme3-core/src/main/java/com/jme3/material/Technique.java
+++ b/jme3-core/src/main/java/com/jme3/material/Technique.java
@@ -31,27 +31,30 @@
*/
package com.jme3.material;
+import com.jme3.material.logic.TechniqueDefLogic;
import com.jme3.asset.AssetManager;
+import com.jme3.light.LightList;
+import com.jme3.material.TechniqueDef.LightMode;
import com.jme3.renderer.Caps;
import com.jme3.renderer.RenderManager;
-import com.jme3.shader.*;
+import com.jme3.scene.Geometry;
+import com.jme3.shader.DefineList;
+import com.jme3.shader.Shader;
+import com.jme3.shader.VarType;
+import com.jme3.util.ListMap;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
-import java.util.logging.Logger;
/**
* Represents a technique instance.
*/
-public class Technique /* implements Savable */ {
+public final class Technique {
- private static final Logger logger = Logger.getLogger(Technique.class.getName());
- private TechniqueDef def;
- private Material owner;
- private ArrayList worldBindUniforms;
- private DefineList defines;
- private Shader shader;
- private boolean needReload = true;
+ private final TechniqueDef def;
+ private final Material owner;
+ private final DefineList paramDefines;
+ private final DefineList dynamicDefines;
/**
* Creates a new technique instance that implements the given
@@ -63,14 +66,8 @@ public class Technique /* implements Savable */ {
public Technique(Material owner, TechniqueDef def) {
this.owner = owner;
this.def = def;
- this.worldBindUniforms = new ArrayList();
- this.defines = new DefineList();
- }
-
- /**
- * Serialization only. Do not use.
- */
- public Technique() {
+ this.paramDefines = def.createDefineList();
+ this.dynamicDefines = def.createDefineList();
}
/**
@@ -85,157 +82,125 @@ public class Technique /* implements Savable */ {
}
/**
- * Returns the shader currently used by this technique instance.
- *
- * Shaders are typically loaded dynamically when the technique is first
- * used, therefore, this variable will most likely be null most of the time.
- *
- * @return the shader currently used by this technique instance.
+ * Called by the material to tell the technique a parameter was modified.
+ * Specify null
for value if the param is to be cleared.
*/
- public Shader getShader() {
- return shader;
- }
+ final void notifyParamChanged(String paramName, VarType type, Object value) {
+ Integer defineId = def.getShaderParamDefineId(paramName);
+
+ if (defineId == null) {
+ return;
+ }
+ paramDefines.set(defineId, type, value);
+ }
+
/**
- * Returns a list of uniforms that implements the world parameters
- * that were requested by the material definition.
- *
- * @return a list of uniforms implementing the world parameters.
+ * Called by the material to tell the technique that it has been made
+ * current.
+ * The technique updates dynamic defines based on the
+ * currently set material parameters.
*/
- public List getWorldBindUniforms() {
- return worldBindUniforms;
+ final void notifyTechniqueSwitched() {
+ ListMap paramMap = owner.getParamsMap();
+ paramDefines.clear();
+ for (int i = 0; i < paramMap.size(); i++) {
+ MatParam param = paramMap.getValue(i);
+ notifyParamChanged(param.getName(), param.getVarType(), param.getValue());
+ }
}
- /**
- * Called by the material to tell the technique a parameter was modified.
- * Specify null
for value if the param is to be cleared.
- */
- void notifyParamChanged(String paramName, VarType type, Object value) {
- // Check if there's a define binding associated with this
- // parameter.
- String defineName = def.getShaderParamDefine(paramName);
- if (defineName != null) {
- // There is a define. Change it on the define list.
- // The "needReload" variable will determine
- // if the shader will be reloaded when the material
- // is rendered.
-
- if (value == null) {
- // Clear the define.
- needReload = defines.remove(defineName) || needReload;
- } else {
- // Set the define.
- needReload = defines.set(defineName, type, value) || needReload;
+ private void applyOverrides(DefineList defineList, List overrides) {
+ for (MatParamOverride override : overrides) {
+ if (!override.isEnabled()) {
+ continue;
+ }
+ Integer defineId = def.getShaderParamDefineId(override.name);
+ if (defineId != null) {
+ if (def.getDefineIdType(defineId) == override.type) {
+ defineList.set(defineId, override.type, override.value);
+ }
}
}
}
- void updateUniformParam(String paramName, VarType type, Object value) {
- if (paramName == null) {
- throw new IllegalArgumentException();
+ /**
+ * Called by the material to determine which shader to use for rendering.
+ *
+ * The {@link TechniqueDefLogic} is used to determine the shader to use
+ * based on the {@link LightMode}.
+ *
+ * @param renderManager The render manager for which the shader is to be selected.
+ * @param rendererCaps The renderer capabilities which the shader should support.
+ * @return A compatible shader.
+ */
+ Shader makeCurrent(RenderManager renderManager, List worldOverrides,
+ List forcedOverrides,
+ LightList lights, EnumSet rendererCaps) {
+ TechniqueDefLogic logic = def.getLogic();
+ AssetManager assetManager = owner.getMaterialDef().getAssetManager();
+
+ dynamicDefines.clear();
+ dynamicDefines.setAll(paramDefines);
+
+ if (worldOverrides != null) {
+ applyOverrides(dynamicDefines, worldOverrides);
}
-
- Uniform u = shader.getUniform(paramName);
- switch (type) {
- case TextureBuffer:
- case Texture2D: // fall intentional
- case Texture3D:
- case TextureArray:
- case TextureCubeMap:
- case Int:
- u.setValue(VarType.Int, value);
- break;
- default:
- u.setValue(type, value);
- break;
+ if (forcedOverrides != null) {
+ applyOverrides(dynamicDefines, forcedOverrides);
}
- }
+ return logic.makeCurrent(assetManager, renderManager, rendererCaps, lights, dynamicDefines);
+ }
+
/**
- * Returns true if the technique must be reloaded.
- *
- * If a technique needs to reload, then the {@link Material} should
- * call {@link #makeCurrent(com.jme3.asset.AssetManager) } on this
- * technique.
+ * Render the technique according to its {@link TechniqueDefLogic}.
*
- * @return true if the technique must be reloaded.
+ * @param renderManager The render manager to perform the rendering against.
+ * @param shader The shader that was selected in
+ * {@link #makeCurrent(com.jme3.renderer.RenderManager, java.util.EnumSet)}.
+ * @param geometry The geometry to render
+ * @param lights Lights which influence the geometry.
*/
- public boolean isNeedReload() {
- return needReload;
+ void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights) {
+ TechniqueDefLogic logic = def.getLogic();
+ logic.render(renderManager, shader, geometry, lights);
}
-
+
/**
- * Prepares the technique for use by loading the shader and setting
- * the proper defines based on material parameters.
+ * Get the {@link DefineList} for dynamic defines.
+ *
+ * Dynamic defines are used to implement material parameter -> define
+ * bindings as well as {@link TechniqueDefLogic} specific functionality.
*
- * @param assetManager The asset manager to use for loading shaders.
+ * @return all dynamic defines.
*/
- public void makeCurrent(AssetManager assetManager, boolean techniqueSwitched, EnumSet rendererCaps, RenderManager rm) {
- if (techniqueSwitched) {
- if (defines.update(owner.getParamsMap(), def)) {
- needReload = true;
- }
- if (getDef().getLightMode() == TechniqueDef.LightMode.SinglePass) {
- defines.set("SINGLE_PASS_LIGHTING", VarType.Boolean, true);
- defines.set("NB_LIGHTS", VarType.Int, rm.getSinglePassLightBatchSize() * 3);
- } else {
- defines.set("SINGLE_PASS_LIGHTING", VarType.Boolean, null);
- }
- }
-
- if (needReload) {
- loadShader(assetManager,rendererCaps);
- }
- }
-
- private void loadShader(AssetManager manager,EnumSet rendererCaps) {
-
- ShaderKey key = new ShaderKey(getAllDefines(),def.getShaderProgramLanguages(),def.getShaderProgramNames());
-
- if (getDef().isUsingShaderNodes()) {
- manager.getShaderGenerator(rendererCaps).initialize(this);
- key.setUsesShaderNodes(true);
- }
- shader = manager.loadShader(key);
-
- // register the world bound uniforms
- worldBindUniforms.clear();
- if (def.getWorldBindings() != null) {
- for (UniformBinding binding : def.getWorldBindings()) {
- Uniform uniform = shader.getUniform("g_" + binding.name());
- uniform.setBinding(binding);
- worldBindUniforms.add(uniform);
- }
- }
- needReload = false;
+ public DefineList getDynamicDefines() {
+ return dynamicDefines;
}
/**
- * Computes the define list
- * @return the complete define list
+ * @return nothing.
+ *
+ * @deprecated Preset defines are precompiled into
+ * {@link TechniqueDef#getShaderPrologue()}, whereas dynamic defines are
+ * available via {@link #getParamDefines()}.
*/
+ @Deprecated
public DefineList getAllDefines() {
- DefineList allDefines = new DefineList();
- allDefines.addFrom(def.getShaderPresetDefines());
- allDefines.addFrom(defines);
- return allDefines;
- }
-
- /*
- public void write(JmeExporter ex) throws IOException {
- OutputCapsule oc = ex.getCapsule(this);
- oc.write(def, "def", null);
- oc.writeSavableArrayList(worldBindUniforms, "worldBindUniforms", null);
- oc.write(defines, "defines", null);
- oc.write(shader, "shader", null);
+ throw new UnsupportedOperationException();
}
-
- public void read(JmeImporter im) throws IOException {
- InputCapsule ic = im.getCapsule(this);
- def = (TechniqueDef) ic.readSavable("def", null);
- worldBindUniforms = ic.readSavableArrayList("worldBindUniforms", null);
- defines = (DefineList) ic.readSavable("defines", null);
- shader = (Shader) ic.readSavable("shader", null);
+
+ /**
+ * Compute the sort ID. Similar to {@link Object#hashCode()} but used
+ * for sorting geometries for rendering.
+ *
+ * @return the sort ID for this technique instance.
+ */
+ public int getSortId() {
+ int hash = 17;
+ hash = hash * 23 + def.getSortId();
+ hash = hash * 23 + paramDefines.hashCode();
+ return hash;
}
- */
}
diff --git a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
index d7523956c..8edc8e19f 100644
--- a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
+++ b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
@@ -31,9 +31,12 @@
*/
package com.jme3.material;
+import com.jme3.material.logic.TechniqueDefLogic;
+import com.jme3.asset.AssetManager;
import com.jme3.export.*;
import com.jme3.renderer.Caps;
import com.jme3.shader.*;
+import com.jme3.shader.Shader.ShaderType;
import java.io.IOException;
import java.util.*;
@@ -50,6 +53,14 @@ public class TechniqueDef implements Savable {
*/
public static final int SAVABLE_VERSION = 1;
+ /**
+ * The default technique name.
+ *
+ * The technique with this name is selected if no specific technique is
+ * requested by the user. Currently set to "Default".
+ */
+ public static final String DEFAULT_TECHNIQUE_NAME = "Default";
+
/**
* Describes light rendering mode.
*/
@@ -91,13 +102,19 @@ public class TechniqueDef implements Savable {
PostPass,
}
- private EnumSet requiredCaps = EnumSet.noneOf(Caps.class);
+ private final EnumSet requiredCaps = EnumSet.noneOf(Caps.class);
private String name;
-
+ private int sortId;
+
private EnumMap shaderLanguages;
private EnumMap shaderNames;
- private DefineList presetDefines;
+ private String shaderPrologue;
+ private ArrayList defineNames;
+ private ArrayList defineTypes;
+ private HashMap paramToDefineId;
+ private final HashMap definesToShaderMap;
+
private boolean usesNodes = false;
private List shaderNodes;
private ShaderGenerationInfo shaderGenerationInfo;
@@ -106,10 +123,10 @@ public class TechniqueDef implements Savable {
private RenderState renderState;
private RenderState forcedRenderState;
- private LightMode lightMode = LightMode.Disable;
+ private LightMode lightMode = LightMode.Disable;
private ShadowMode shadowMode = ShadowMode.Disable;
+ private TechniqueDefLogic logic;
- private HashMap defineParams;
private ArrayList worldBinds;
/**
@@ -117,25 +134,38 @@ public class TechniqueDef implements Savable {
*
* Used internally by the J3M/J3MD loader.
*
- * @param name The name of the technique, should be set to null
- * for default techniques.
+ * @param name The name of the technique
*/
- public TechniqueDef(String name){
+ public TechniqueDef(String name, int sortId){
this();
- this.name = name == null ? "Default" : name;
+ this.sortId = sortId;
+ this.name = name;
}
/**
* Serialization only. Do not use.
*/
- public TechniqueDef(){
- shaderLanguages=new EnumMap(Shader.ShaderType.class);
- shaderNames=new EnumMap(Shader.ShaderType.class);
+ public TechniqueDef() {
+ shaderLanguages = new EnumMap(Shader.ShaderType.class);
+ shaderNames = new EnumMap(Shader.ShaderType.class);
+ defineNames = new ArrayList();
+ defineTypes = new ArrayList();
+ paramToDefineId = new HashMap();
+ definesToShaderMap = new HashMap();
+ }
+
+ /**
+ * @return A unique sort ID.
+ * No other technique definition can have the same ID.
+ */
+ public int getSortId() {
+ return sortId;
}
/**
* Returns the name of this technique as specified in the J3MD file.
- * Default techniques have the name "Default".
+ * Default
+ * techniques have the name {@link #DEFAULT_TECHNIQUE_NAME}.
*
* @return the name of this technique
*/
@@ -162,7 +192,15 @@ public class TechniqueDef implements Savable {
public void setLightMode(LightMode lightMode) {
this.lightMode = lightMode;
}
+
+ public void setLogic(TechniqueDefLogic logic) {
+ this.logic = logic;
+ }
+ public TechniqueDefLogic getLogic() {
+ return logic;
+ }
+
/**
* Returns the shadow mode.
* @return the shadow mode.
@@ -224,14 +262,6 @@ public class TechniqueDef implements Savable {
return noRender;
}
- /**
- * @deprecated jME3 always requires shaders now
- */
- @Deprecated
- public boolean isUsingShaders(){
- return true;
- }
-
/**
* Returns true if this technique uses Shader Nodes, false otherwise.
*
@@ -273,34 +303,24 @@ public class TechniqueDef implements Savable {
requiredCaps.add(fragCap);
}
-
/**
- * Sets the shaders that this technique definition will use.
- *
- * @param shaderNames EnumMap containing all shader names for this stage
- * @param shaderLanguages EnumMap containing all shader languages for this stage
+ * Set a string which is prepended to every shader used by this technique.
+ *
+ * Typically this is used for preset defines.
+ *
+ * @param shaderPrologue The prologue to append before the technique's shaders.
*/
- public void setShaderFile(EnumMap shaderNames, EnumMap shaderLanguages) {
- requiredCaps.clear();
-
- for (Shader.ShaderType shaderType : shaderNames.keySet()) {
- String language = shaderLanguages.get(shaderType);
- String shaderFile = shaderNames.get(shaderType);
-
- this.shaderLanguages.put(shaderType, language);
- this.shaderNames.put(shaderType, shaderFile);
-
- Caps vertCap = Caps.valueOf(language);
- requiredCaps.add(vertCap);
-
- if (shaderType.equals(Shader.ShaderType.Geometry)) {
- requiredCaps.add(Caps.GeometryShader);
- } else if (shaderType.equals(Shader.ShaderType.TessellationControl)) {
- requiredCaps.add(Caps.TesselationShader);
- }
- }
+ public void setShaderPrologue(String shaderPrologue) {
+ this.shaderPrologue = shaderPrologue;
}
-
+
+ /**
+ * @return the shader prologue which is prepended to every shader.
+ */
+ public String getShaderPrologue() {
+ return shaderPrologue;
+ }
+
/**
* Returns the define name which the given material parameter influences.
*
@@ -310,60 +330,186 @@ public class TechniqueDef implements Savable {
* @see #addShaderParamDefine(java.lang.String, java.lang.String)
*/
public String getShaderParamDefine(String paramName){
- if (defineParams == null) {
+ Integer defineId = paramToDefineId.get(paramName);
+ if (defineId != null) {
+ return defineNames.get(defineId);
+ } else {
return null;
}
- return defineParams.get(paramName);
+ }
+
+ /**
+ * Get the define ID for a given material parameter.
+ *
+ * @param paramName The parameter name to look up
+ * @return The define ID, or null if not found.
+ */
+ public Integer getShaderParamDefineId(String paramName) {
+ return paramToDefineId.get(paramName);
}
+ /**
+ * Get the type of a particular define.
+ *
+ * @param defineId The define ID to lookup.
+ * @return The type of the define, or null if not found.
+ */
+ public VarType getDefineIdType(int defineId) {
+ return defineId < defineTypes.size() ? defineTypes.get(defineId) : null;
+ }
+
/**
* Adds a define linked to a material parameter.
*
* Any time the material parameter on the parent material is altered,
* the appropriate define on the technique will be modified as well.
- * See the method
- * {@link DefineList#set(java.lang.String, com.jme3.shader.VarType, java.lang.Object) }
- * on the exact details of how the material parameter changes the define.
+ * When set, the material parameter will be mapped to an integer define,
+ * typically 1
if it is set, unless it is an integer or a float,
+ * in which case it will converted into an integer.
*
* @param paramName The name of the material parameter to link to.
+ * @param paramType The type of the material parameter to link to.
* @param defineName The name of the define parameter, e.g. USE_LIGHTING
*/
- public void addShaderParamDefine(String paramName, String defineName){
- if (defineParams == null) {
- defineParams = new HashMap();
+ public void addShaderParamDefine(String paramName, VarType paramType, String defineName){
+ int defineId = defineNames.size();
+
+ if (defineId >= DefineList.MAX_DEFINES) {
+ throw new IllegalStateException("Cannot have more than " +
+ DefineList.MAX_DEFINES + " defines on a technique.");
+ }
+
+ paramToDefineId.put(paramName, defineId);
+ defineNames.add(defineName);
+ defineTypes.add(paramType);
+ }
+
+ /**
+ * Add an unmapped define which can only be set by define ID.
+ *
+ * Unmapped defines are used by technique renderers to
+ * configure the shader internally before rendering.
+ *
+ * @param defineName The define name to create
+ * @return The define ID of the created define
+ */
+ public int addShaderUnmappedDefine(String defineName, VarType defineType) {
+ int defineId = defineNames.size();
+
+ if (defineId >= DefineList.MAX_DEFINES) {
+ throw new IllegalStateException("Cannot have more than " +
+ DefineList.MAX_DEFINES + " defines on a technique.");
}
- defineParams.put(paramName, defineName);
+
+ defineNames.add(defineName);
+ defineTypes.add(defineType);
+ return defineId;
}
/**
- * Returns the {@link DefineList} for the preset defines.
+ * Get the names of all defines declared on this technique definition.
*
- * @return the {@link DefineList} for the preset defines.
+ * The defines are returned in order of declaration.
*
- * @see #addShaderPresetDefine(java.lang.String, com.jme3.shader.VarType, java.lang.Object)
+ * @return the names of all defines declared.
*/
- public DefineList getShaderPresetDefines() {
- return presetDefines;
+ public String[] getDefineNames() {
+ return defineNames.toArray(new String[0]);
}
/**
- * Adds a preset define.
- *
- * Preset defines do not depend upon any parameters to be activated,
- * they are always passed to the shader as long as this technique is used.
+ * Get the types of all defines declared on this technique definition.
*
- * @param defineName The name of the define parameter, e.g. USE_LIGHTING
- * @param type The type of the define. See
- * {@link DefineList#set(java.lang.String, com.jme3.shader.VarType, java.lang.Object) }
- * to see why it matters.
+ * The types are returned in order of declaration.
*
- * @param value The value of the define
+ * @return the types of all defines declared.
*/
- public void addShaderPresetDefine(String defineName, VarType type, Object value){
- if (presetDefines == null) {
- presetDefines = new DefineList();
+ public VarType[] getDefineTypes() {
+ return defineTypes.toArray(new VarType[0]);
+ }
+
+ /**
+ * Create a define list with the size matching the number
+ * of defines on this technique.
+ *
+ * @return a define list with the size matching the number
+ * of defines on this technique.
+ */
+ public DefineList createDefineList() {
+ return new DefineList(defineNames.size());
+ }
+
+ private Shader loadShader(AssetManager assetManager, EnumSet rendererCaps, DefineList defines) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(shaderPrologue);
+ defines.generateSource(sb, defineNames, defineTypes);
+ String definesSourceCode = sb.toString();
+
+ Shader shader;
+ if (isUsingShaderNodes()) {
+ ShaderGenerator shaderGenerator = assetManager.getShaderGenerator(rendererCaps);
+ if (shaderGenerator == null) {
+ throw new UnsupportedOperationException("ShaderGenerator was not initialized, "
+ + "make sure assetManager.getGenerator(caps) has been called");
+ }
+ shaderGenerator.initialize(this);
+ shader = shaderGenerator.generateShader(definesSourceCode);
+ } else {
+ shader = new Shader();
+ for (ShaderType type : ShaderType.values()) {
+ String language = shaderLanguages.get(type);
+ String shaderSourceAssetName = shaderNames.get(type);
+ if (language == null || shaderSourceAssetName == null) {
+ continue;
+ }
+ String shaderSourceCode = (String) assetManager.loadAsset(shaderSourceAssetName);
+ shader.addSource(type, shaderSourceAssetName, shaderSourceCode, definesSourceCode, language);
+ }
+ }
+
+ if (getWorldBindings() != null) {
+ for (UniformBinding binding : getWorldBindings()) {
+ shader.addUniformBinding(binding);
+ }
+ }
+
+ return shader;
+ }
+
+ public Shader getShader(AssetManager assetManager, EnumSet rendererCaps, DefineList defines) {
+ Shader shader = definesToShaderMap.get(defines);
+ if (shader == null) {
+ shader = loadShader(assetManager, rendererCaps, defines);
+ definesToShaderMap.put(defines.deepClone(), shader);
+ }
+ return shader;
+ }
+
+ /**
+ * Sets the shaders that this technique definition will use.
+ *
+ * @param shaderNames EnumMap containing all shader names for this stage
+ * @param shaderLanguages EnumMap containing all shader languages for this stage
+ */
+ public void setShaderFile(EnumMap shaderNames, EnumMap shaderLanguages) {
+ requiredCaps.clear();
+
+ for (Shader.ShaderType shaderType : shaderNames.keySet()) {
+ String language = shaderLanguages.get(shaderType);
+ String shaderFile = shaderNames.get(shaderType);
+
+ this.shaderLanguages.put(shaderType, language);
+ this.shaderNames.put(shaderType, shaderFile);
+
+ Caps vertCap = Caps.valueOf(language);
+ requiredCaps.add(vertCap);
+
+ if (shaderType.equals(Shader.ShaderType.Geometry)) {
+ requiredCaps.add(Caps.GeometryShader);
+ } else if (shaderType.equals(Shader.ShaderType.TessellationControl)) {
+ requiredCaps.add(Caps.TesselationShader);
+ }
}
- presetDefines.set(defineName, type, value);
}
/**
@@ -467,7 +613,7 @@ public class TechniqueDef implements Savable {
oc.write(shaderLanguages.get(Shader.ShaderType.TessellationControl), "tsctrlLanguage", null);
oc.write(shaderLanguages.get(Shader.ShaderType.TessellationEvaluation), "tsevalLanguage", null);
- oc.write(presetDefines, "presetDefines", null);
+ oc.write(shaderPrologue, "shaderPrologue", null);
oc.write(lightMode, "lightMode", LightMode.Disable);
oc.write(shadowMode, "shadowMode", ShadowMode.Disable);
oc.write(renderState, "renderState", null);
@@ -490,7 +636,7 @@ public class TechniqueDef implements Savable {
shaderNames.put(Shader.ShaderType.Geometry,ic.readString("geomName", null));
shaderNames.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrlName", null));
shaderNames.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tsevalName", null));
- presetDefines = (DefineList) ic.readSavable("presetDefines", null);
+ shaderPrologue = ic.readString("shaderPrologue", null);
lightMode = ic.readEnum("lightMode", LightMode.class, LightMode.Disable);
shadowMode = ic.readEnum("shadowMode", ShadowMode.class, ShadowMode.Disable);
renderState = (RenderState) ic.readSavable("renderState", null);
@@ -547,9 +693,14 @@ public class TechniqueDef implements Savable {
this.shaderGenerationInfo = shaderGenerationInfo;
}
- //todo: make toString return something usefull
@Override
public String toString() {
- return "TechniqueDef{" + "requiredCaps=" + requiredCaps + ", name=" + name /*+ ", vertName=" + vertName + ", fragName=" + fragName + ", vertLanguage=" + vertLanguage + ", fragLanguage=" + fragLanguage */+ ", presetDefines=" + presetDefines + ", usesNodes=" + usesNodes + ", shaderNodes=" + shaderNodes + ", shaderGenerationInfo=" + shaderGenerationInfo + ", renderState=" + renderState + ", forcedRenderState=" + forcedRenderState + ", lightMode=" + lightMode + ", shadowMode=" + shadowMode + ", defineParams=" + defineParams + ", worldBinds=" + worldBinds + ", noRender=" + noRender + '}';
+ return "TechniqueDef[name=" + name
+ + ", requiredCaps=" + requiredCaps
+ + ", noRender=" + noRender
+ + ", lightMode=" + lightMode
+ + ", usesNodes=" + usesNodes
+ + ", renderState=" + renderState
+ + ", forcedRenderState=" + forcedRenderState + "]";
}
}
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java
new file mode 100644
index 000000000..ffe72cc00
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009-2015 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.logic;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.Light;
+import com.jme3.light.LightList;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.ColorRGBA;
+import com.jme3.renderer.Caps;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.instancing.InstancedGeometry;
+import com.jme3.shader.DefineList;
+import com.jme3.shader.Shader;
+import java.util.EnumSet;
+
+public class DefaultTechniqueDefLogic implements TechniqueDefLogic {
+
+ protected final TechniqueDef techniqueDef;
+
+ public DefaultTechniqueDefLogic(TechniqueDef techniqueDef) {
+ this.techniqueDef = techniqueDef;
+ }
+
+ @Override
+ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
+ EnumSet rendererCaps, LightList lights, DefineList defines) {
+ return techniqueDef.getShader(assetManager, rendererCaps, defines);
+ }
+
+ public static void renderMeshFromGeometry(Renderer renderer, Geometry geom) {
+ Mesh mesh = geom.getMesh();
+ int lodLevel = geom.getLodLevel();
+ if (geom instanceof InstancedGeometry) {
+ InstancedGeometry instGeom = (InstancedGeometry) geom;
+ renderer.renderMesh(mesh, lodLevel, instGeom.getActualNumInstances(),
+ instGeom.getAllInstanceData());
+ } else {
+ renderer.renderMesh(mesh, lodLevel, 1, null);
+ }
+ }
+
+ protected static ColorRGBA getAmbientColor(LightList lightList, boolean removeLights, ColorRGBA ambientLightColor) {
+ ambientLightColor.set(0, 0, 0, 1);
+ for (int j = 0; j < lightList.size(); j++) {
+ Light l = lightList.get(j);
+ if (l instanceof AmbientLight) {
+ ambientLightColor.addLocal(l.getColor());
+ if (removeLights) {
+ lightList.remove(l);
+ }
+ }
+ }
+ ambientLightColor.a = 1.0f;
+ return ambientLightColor;
+ }
+
+ @Override
+ public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights) {
+ Renderer renderer = renderManager.getRenderer();
+ renderer.setShader(shader);
+ renderMeshFromGeometry(renderer, geometry);
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java
new file mode 100644
index 000000000..7b5e2f4a5
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2009-2015 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.logic;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.light.LightList;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.RenderState;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.math.Vector4f;
+import com.jme3.renderer.Caps;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.scene.Geometry;
+import com.jme3.shader.DefineList;
+import com.jme3.shader.Shader;
+import com.jme3.shader.Uniform;
+import com.jme3.shader.VarType;
+import com.jme3.util.TempVars;
+import java.util.EnumSet;
+
+public final class MultiPassLightingLogic extends DefaultTechniqueDefLogic {
+
+ private static final RenderState ADDITIVE_LIGHT = new RenderState();
+ private static final Quaternion NULL_DIR_LIGHT = new Quaternion(0, -1, 0, -1);
+
+ private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1);
+
+ static {
+ ADDITIVE_LIGHT.setBlendMode(RenderState.BlendMode.AlphaAdditive);
+ ADDITIVE_LIGHT.setDepthWrite(false);
+ }
+
+ public MultiPassLightingLogic(TechniqueDef techniqueDef) {
+ super(techniqueDef);
+ }
+
+ @Override
+ public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights) {
+ Renderer r = renderManager.getRenderer();
+ Uniform lightDir = shader.getUniform("g_LightDirection");
+ Uniform lightColor = shader.getUniform("g_LightColor");
+ Uniform lightPos = shader.getUniform("g_LightPosition");
+ Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
+ boolean isFirstLight = true;
+ boolean isSecondLight = false;
+
+ getAmbientColor(lights, false, ambientLightColor);
+
+ for (int i = 0; i < lights.size(); i++) {
+ Light l = lights.get(i);
+ if (l instanceof AmbientLight) {
+ continue;
+ }
+
+ if (isFirstLight) {
+ // set ambient color for first light only
+ ambientColor.setValue(VarType.Vector4, ambientLightColor);
+ isFirstLight = false;
+ isSecondLight = true;
+ } else if (isSecondLight) {
+ ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
+ // apply additive blending for 2nd and future lights
+ r.applyRenderState(ADDITIVE_LIGHT);
+ isSecondLight = false;
+ }
+
+ TempVars vars = TempVars.get();
+ Quaternion tmpLightDirection = vars.quat1;
+ Quaternion tmpLightPosition = vars.quat2;
+ ColorRGBA tmpLightColor = vars.color;
+ Vector4f tmpVec = vars.vect4f1;
+
+ ColorRGBA color = l.getColor();
+ tmpLightColor.set(color);
+ tmpLightColor.a = l.getType().getId();
+ lightColor.setValue(VarType.Vector4, tmpLightColor);
+
+ switch (l.getType()) {
+ case Directional:
+ DirectionalLight dl = (DirectionalLight) l;
+ Vector3f dir = dl.getDirection();
+ //FIXME : there is an inconstency here due to backward
+ //compatibility of the lighting shader.
+ //The directional light direction is passed in the
+ //LightPosition uniform. The lighting shader needs to be
+ //reworked though in order to fix this.
+ tmpLightPosition.set(dir.getX(), dir.getY(), dir.getZ(), -1);
+ lightPos.setValue(VarType.Vector4, tmpLightPosition);
+ tmpLightDirection.set(0, 0, 0, 0);
+ lightDir.setValue(VarType.Vector4, tmpLightDirection);
+ break;
+ case Point:
+ PointLight pl = (PointLight) l;
+ Vector3f pos = pl.getPosition();
+ float invRadius = pl.getInvRadius();
+
+ tmpLightPosition.set(pos.getX(), pos.getY(), pos.getZ(), invRadius);
+ lightPos.setValue(VarType.Vector4, tmpLightPosition);
+ tmpLightDirection.set(0, 0, 0, 0);
+ lightDir.setValue(VarType.Vector4, tmpLightDirection);
+ break;
+ case Spot:
+ SpotLight sl = (SpotLight) l;
+ Vector3f pos2 = sl.getPosition();
+ Vector3f dir2 = sl.getDirection();
+ float invRange = sl.getInvSpotRange();
+ float spotAngleCos = sl.getPackedAngleCos();
+
+ tmpLightPosition.set(pos2.getX(), pos2.getY(), pos2.getZ(), invRange);
+ lightPos.setValue(VarType.Vector4, tmpLightPosition);
+
+ //We transform the spot direction in view space here to save 5 varying later in the lighting shader
+ //one vec4 less and a vec4 that becomes a vec3
+ //the downside is that spotAngleCos decoding happens now in the frag shader.
+ tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0);
+ renderManager.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
+ tmpLightDirection.set(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos);
+
+ lightDir.setValue(VarType.Vector4, tmpLightDirection);
+
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
+ }
+ vars.release();
+ r.setShader(shader);
+ renderMeshFromGeometry(r, geometry);
+ }
+
+ if (isFirstLight) {
+ // Either there are no lights at all, or only ambient lights.
+ // Render a dummy "normal light" so we can see the ambient color.
+ ambientColor.setValue(VarType.Vector4, getAmbientColor(lights, false, ambientLightColor));
+ lightColor.setValue(VarType.Vector4, ColorRGBA.BlackNoAlpha);
+ lightPos.setValue(VarType.Vector4, NULL_DIR_LIGHT);
+ r.setShader(shader);
+ renderMeshFromGeometry(r, geometry);
+ }
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java
new file mode 100644
index 000000000..2b31c7869
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2009-2015 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.logic;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.light.LightList;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.RenderState;
+import com.jme3.material.RenderState.BlendMode;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.math.Vector4f;
+import com.jme3.renderer.Caps;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.scene.Geometry;
+import com.jme3.shader.DefineList;
+import com.jme3.shader.Shader;
+import com.jme3.shader.Uniform;
+import com.jme3.shader.VarType;
+import com.jme3.util.TempVars;
+import java.util.EnumSet;
+
+public final class SinglePassLightingLogic extends DefaultTechniqueDefLogic {
+
+ private static final String DEFINE_SINGLE_PASS_LIGHTING = "SINGLE_PASS_LIGHTING";
+ private static final String DEFINE_NB_LIGHTS = "NB_LIGHTS";
+ private static final RenderState ADDITIVE_LIGHT = new RenderState();
+
+ private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1);
+
+ static {
+ ADDITIVE_LIGHT.setBlendMode(BlendMode.AlphaAdditive);
+ ADDITIVE_LIGHT.setDepthWrite(false);
+ }
+
+ private final int singlePassLightingDefineId;
+ private final int nbLightsDefineId;
+
+ public SinglePassLightingLogic(TechniqueDef techniqueDef) {
+ super(techniqueDef);
+ singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_SINGLE_PASS_LIGHTING, VarType.Boolean);
+ nbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int);
+ }
+
+ @Override
+ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
+ EnumSet rendererCaps, LightList lights, DefineList defines) {
+ defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3);
+ defines.set(singlePassLightingDefineId, true);
+ return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines);
+ }
+
+ /**
+ * Uploads the lights in the light list as two uniform arrays.
*
+ *
+ * uniform vec4 g_LightColor[numLights];
//
+ * g_LightColor.rgb is the diffuse/specular color of the light.
//
+ * g_Lightcolor.a is the type of light, 0 = Directional, 1 = Point,
//
+ * 2 = Spot.
+ * uniform vec4 g_LightPosition[numLights];
//
+ * g_LightPosition.xyz is the position of the light (for point lights)
+ * // or the direction of the light (for directional lights).
//
+ * g_LightPosition.w is the inverse radius (1/r) of the light (for
+ * attenuation)
+ */
+ protected int updateLightListUniforms(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex) {
+ if (numLights == 0) { // this shader does not do lighting, ignore.
+ return 0;
+ }
+
+ Uniform lightData = shader.getUniform("g_LightData");
+ lightData.setVector4Length(numLights * 3);//8 lights * max 3
+ Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
+
+
+ if (startIndex != 0) {
+ // apply additive blending for 2nd and future passes
+ rm.getRenderer().applyRenderState(ADDITIVE_LIGHT);
+ ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
+ } else {
+ ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, true, ambientLightColor));
+ }
+
+ int lightDataIndex = 0;
+ TempVars vars = TempVars.get();
+ Vector4f tmpVec = vars.vect4f1;
+ int curIndex;
+ int endIndex = numLights + startIndex;
+ for (curIndex = startIndex; curIndex < endIndex && curIndex < lightList.size(); curIndex++) {
+
+ Light l = lightList.get(curIndex);
+ if (l.getType() == Light.Type.Ambient) {
+ endIndex++;
+ continue;
+ }
+ ColorRGBA color = l.getColor();
+ //Color
+ lightData.setVector4InArray(color.getRed(),
+ color.getGreen(),
+ color.getBlue(),
+ l.getType().getId(),
+ lightDataIndex);
+ lightDataIndex++;
+
+ switch (l.getType()) {
+ case Directional:
+ DirectionalLight dl = (DirectionalLight) l;
+ Vector3f dir = dl.getDirection();
+ //Data directly sent in view space to avoid a matrix mult for each pixel
+ tmpVec.set(dir.getX(), dir.getY(), dir.getZ(), 0.0f);
+ rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
+// tmpVec.divideLocal(tmpVec.w);
+// tmpVec.normalizeLocal();
+ lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), -1, lightDataIndex);
+ lightDataIndex++;
+ //PADDING
+ lightData.setVector4InArray(0, 0, 0, 0, lightDataIndex);
+ lightDataIndex++;
+ break;
+ case Point:
+ PointLight pl = (PointLight) l;
+ Vector3f pos = pl.getPosition();
+ float invRadius = pl.getInvRadius();
+ tmpVec.set(pos.getX(), pos.getY(), pos.getZ(), 1.0f);
+ rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
+ //tmpVec.divideLocal(tmpVec.w);
+ lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRadius, lightDataIndex);
+ lightDataIndex++;
+ //PADDING
+ lightData.setVector4InArray(0, 0, 0, 0, lightDataIndex);
+ lightDataIndex++;
+ break;
+ case Spot:
+ SpotLight sl = (SpotLight) l;
+ Vector3f pos2 = sl.getPosition();
+ Vector3f dir2 = sl.getDirection();
+ float invRange = sl.getInvSpotRange();
+ float spotAngleCos = sl.getPackedAngleCos();
+ tmpVec.set(pos2.getX(), pos2.getY(), pos2.getZ(), 1.0f);
+ rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
+ // tmpVec.divideLocal(tmpVec.w);
+ lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRange, lightDataIndex);
+ lightDataIndex++;
+
+ //We transform the spot direction in view space here to save 5 varying later in the lighting shader
+ //one vec4 less and a vec4 that becomes a vec3
+ //the downside is that spotAngleCos decoding happens now in the frag shader.
+ tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0.0f);
+ rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
+ tmpVec.normalizeLocal();
+ lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos, lightDataIndex);
+ lightDataIndex++;
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
+ }
+ }
+ vars.release();
+ //Padding of unsued buffer space
+ while(lightDataIndex < numLights * 3) {
+ lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex);
+ lightDataIndex++;
+ }
+ return curIndex;
+ }
+
+ @Override
+ public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights) {
+ int nbRenderedLights = 0;
+ Renderer renderer = renderManager.getRenderer();
+ int batchSize = renderManager.getSinglePassLightBatchSize();
+ if (lights.size() == 0) {
+ updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, 0);
+ renderer.setShader(shader);
+ renderMeshFromGeometry(renderer, geometry);
+ } else {
+ while (nbRenderedLights < lights.size()) {
+ nbRenderedLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, nbRenderedLights);
+ renderer.setShader(shader);
+ renderMeshFromGeometry(renderer, geometry);
+ }
+ }
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
new file mode 100644
index 000000000..4193b118b
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2009-2015 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.logic;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.light.LightList;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.Caps;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.scene.Geometry;
+import com.jme3.shader.DefineList;
+import com.jme3.shader.Shader;
+import com.jme3.shader.Uniform;
+import com.jme3.shader.VarType;
+import java.util.ArrayList;
+import java.util.EnumSet;
+
+/**
+ * Rendering logic for static pass.
+ *
+ * @author Kirill Vainer
+ */
+public final class StaticPassLightingLogic extends DefaultTechniqueDefLogic {
+
+ private static final String DEFINE_NUM_DIR_LIGHTS = "NUM_DIR_LIGHTS";
+ private static final String DEFINE_NUM_POINT_LIGHTS = "NUM_POINT_LIGHTS";
+ private static final String DEFINE_NUM_SPOT_LIGHTS = "NUM_SPOT_LIGHTS";
+
+ private final int numDirLightsDefineId;
+ private final int numPointLightsDefineId;
+ private final int numSpotLightsDefineId;
+
+ private final ArrayList tempDirLights = new ArrayList();
+ private final ArrayList tempPointLights = new ArrayList();
+ private final ArrayList tempSpotLights = new ArrayList();
+
+ private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1);
+ private final Vector3f tempPosition = new Vector3f();
+ private final Vector3f tempDirection = new Vector3f();
+
+ public StaticPassLightingLogic(TechniqueDef techniqueDef) {
+ super(techniqueDef);
+
+ numDirLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_DIR_LIGHTS, VarType.Int);
+ numPointLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_POINT_LIGHTS, VarType.Int);
+ numSpotLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_SPOT_LIGHTS, VarType.Int);
+ }
+
+ @Override
+ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
+ EnumSet rendererCaps, LightList lights, DefineList defines) {
+
+ // TODO: if it ever changes that render isn't called
+ // right away with the same geometry after makeCurrent, it would be
+ // a problem.
+ // Do a radix sort.
+ tempDirLights.clear();
+ tempPointLights.clear();
+ tempSpotLights.clear();
+ for (Light light : lights) {
+ switch (light.getType()) {
+ case Directional:
+ tempDirLights.add((DirectionalLight) light);
+ break;
+ case Point:
+ tempPointLights.add((PointLight) light);
+ break;
+ case Spot:
+ tempSpotLights.add((SpotLight) light);
+ break;
+ }
+ }
+
+ defines.set(numDirLightsDefineId, tempDirLights.size());
+ defines.set(numPointLightsDefineId, tempPointLights.size());
+ defines.set(numSpotLightsDefineId, tempSpotLights.size());
+
+ return techniqueDef.getShader(assetManager, rendererCaps, defines);
+ }
+
+ private void transformDirection(Matrix4f viewMatrix, Vector3f direction) {
+ viewMatrix.multNormal(direction, direction);
+ }
+
+ private void transformPosition(Matrix4f viewMatrix, Vector3f location) {
+ viewMatrix.mult(location, location);
+ }
+
+ private void updateLightListUniforms(Matrix4f viewMatrix, Shader shader, LightList lights) {
+ Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
+ ambientColor.setValue(VarType.Vector4, getAmbientColor(lights, true, ambientLightColor));
+
+ Uniform lightData = shader.getUniform("g_LightData");
+
+ int totalSize = tempDirLights.size() * 2
+ + tempPointLights.size() * 2
+ + tempSpotLights.size() * 3;
+ lightData.setVector4Length(totalSize);
+
+ int index = 0;
+ for (DirectionalLight light : tempDirLights) {
+ ColorRGBA color = light.getColor();
+ tempDirection.set(light.getDirection());
+ transformDirection(viewMatrix, tempDirection);
+ lightData.setVector4InArray(color.r, color.g, color.b, 1f, index++);
+ lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, 1f, index++);
+ }
+
+ for (PointLight light : tempPointLights) {
+ ColorRGBA color = light.getColor();
+ tempPosition.set(light.getPosition());
+ float invRadius = light.getInvRadius();
+ transformPosition(viewMatrix, tempPosition);
+ lightData.setVector4InArray(color.r, color.g, color.b, 1f, index++);
+ lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRadius, index++);
+ }
+
+ for (SpotLight light : tempSpotLights) {
+ ColorRGBA color = light.getColor();
+ Vector3f pos = light.getPosition();
+ Vector3f dir = light.getDirection();
+
+ tempPosition.set(light.getPosition());
+ tempDirection.set(light.getDirection());
+ transformPosition(viewMatrix, tempPosition);
+ transformDirection(viewMatrix, tempDirection);
+
+ float invRange = light.getInvSpotRange();
+ float spotAngleCos = light.getPackedAngleCos();
+ lightData.setVector4InArray(color.r, color.g, color.b, 1f, index++);
+ lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRange, index++);
+ lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, spotAngleCos, index++);
+ }
+ }
+
+ @Override
+ public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights) {
+ Renderer renderer = renderManager.getRenderer();
+ Matrix4f viewMatrix = renderManager.getCurrentCamera().getViewMatrix();
+ updateLightListUniforms(viewMatrix, shader, lights);
+ renderer.setShader(shader);
+ renderMeshFromGeometry(renderer, geometry);
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java
new file mode 100644
index 000000000..95ab8ccf3
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009-2015 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.logic;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.light.LightList;
+import com.jme3.material.TechniqueDef.LightMode;
+import com.jme3.renderer.Caps;
+import com.jme3.renderer.RenderManager;
+import com.jme3.scene.Geometry;
+import com.jme3.shader.DefineList;
+import com.jme3.shader.Shader;
+import com.jme3.shader.Uniform;
+import com.jme3.shader.UniformBinding;
+import com.jme3.texture.Texture;
+import java.util.EnumSet;
+
+/**
+ * TechniqueDefLogic
is used to customize how
+ * a material should be rendered.
+ *
+ * Typically used to implement {@link LightMode lighting modes}.
+ * Implementations can register
+ * {@link TechniqueDef#addShaderUnmappedDefine(java.lang.String) unmapped defines}
+ * in their constructor and then later set them based on the geometry
+ * or light environment being rendered.
+ *
+ * @author Kirill Vainer
+ */
+public interface TechniqueDefLogic {
+
+ /**
+ * Determine the shader to use for the given geometry / material combination.
+ *
+ * @param assetManager The asset manager to use for loading shader source code,
+ * shader nodes, and and lookup textures.
+ * @param renderManager The render manager for which rendering is to be performed.
+ * @param rendererCaps Renderer capabilities. The returned shader must
+ * support these capabilities.
+ * @param lights The lights with which the geometry shall be rendered. This
+ * list must not include culled lights.
+ * @param defines The define list used by the technique, any
+ * {@link TechniqueDef#addShaderUnmappedDefine(java.lang.String) unmapped defines}
+ * should be set here to change shader behavior.
+ *
+ * @return The shader to use for rendering.
+ */
+ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
+ EnumSet rendererCaps, LightList lights, DefineList defines);
+
+ /**
+ * Requests that the TechniqueDefLogic
renders the given geometry.
+ *
+ * Fixed material functionality such as {@link RenderState},
+ * {@link MatParam material parameters}, and
+ * {@link UniformBinding uniform bindings}
+ * have already been applied by the material, however,
+ * {@link RenderState}, {@link Uniform uniforms}, {@link Texture textures},
+ * can still be overriden.
+ *
+ * @param renderManager The render manager to perform the rendering against.
+ * * @param shader The shader that was selected by this logic in
+ * {@link #makeCurrent(com.jme3.asset.AssetManager, com.jme3.renderer.RenderManager, java.util.EnumSet, com.jme3.shader.DefineList)}.
+ * @param geometry The geometry to render
+ * @param lights Lights which influence the geometry.
+ */
+ public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights);
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/Camera.java b/jme3-core/src/main/java/com/jme3/renderer/Camera.java
index 0ce5bafd7..2d4a61a45 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/Camera.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/Camera.java
@@ -1005,12 +1005,12 @@ public class Camera implements Savable, Cloneable {
*
* NOTE: This method is used internally for culling, for public usage,
* the plane state of the bounding volume must be saved and restored, e.g:
- * BoundingVolume bv;
- * Camera c;
- * int planeState = bv.getPlaneState();
- * bv.setPlaneState(0);
- * c.contains(bv);
- * bv.setPlaneState(plateState);
+ * BoundingVolume bv;
+ * Camera c;
+ * int planeState = bv.getPlaneState();
+ * bv.setPlaneState(0);
+ * c.contains(bv);
+ * bv.setPlaneState(plateState);
*
*
* @param bound the bound to check for culling
diff --git a/jme3-core/src/main/java/com/jme3/renderer/Limits.java b/jme3-core/src/main/java/com/jme3/renderer/Limits.java
index 81db88f5e..a7e737092 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/Limits.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/Limits.java
@@ -32,51 +32,34 @@
package com.jme3.renderer;
/**
- * Limits
allows querying the limits of certain features in
+ * Limits
allows querying the limits of certain features in
* {@link Renderer}.
*
* For example, maximum texture sizes or number of samples.
- *
+ *
* @author Kirill Vainer
*/
public enum Limits {
/**
- * Maximum number of vertex texture units, or number of textures
- * that can be used in the vertex shader.
+ * Maximum number of vertex texture units, or number of textures that can be
+ * used in the vertex shader.
*/
VertexTextureUnits,
-
/**
- * Maximum number of fragment texture units, or number of textures
- * that can be used in the fragment shader.
+ * Maximum number of fragment texture units, or number of textures that can
+ * be used in the fragment shader.
*/
FragmentTextureUnits,
-
- FragmentUniforms,
-
+ FragmentUniformVectors,
+ VertexUniformVectors,
VertexAttributes,
-
FrameBufferSamples,
-
FrameBufferAttachments,
-
FrameBufferMrtAttachments,
-
RenderBufferSize,
-
TextureSize,
-
CubemapSize,
-
- VertexCount,
-
- TriangleCount,
-
ColorTextureSamples,
-
DepthTextureSamples,
-
- VertexUniformVectors,
-
TextureAnisotropy,
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java
index 5be184c94..49f25240a 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java
@@ -55,16 +55,6 @@ public class RenderContext {
*/
public boolean depthTestEnabled = false;
- /**
- * @see RenderState#setAlphaFallOff(float)
- */
- public float alphaTestFallOff = 0f;
-
- /**
- * @see RenderState#setAlphaTest(boolean)
- */
- public boolean alphaTestEnabled = false;
-
/**
* @see RenderState#setDepthWrite(boolean)
*/
@@ -111,14 +101,19 @@ public class RenderContext {
public RenderState.BlendMode blendMode = RenderState.BlendMode.Off;
/**
- * @see RenderState#setWireframe(boolean)
+ * @see RenderState#setBlendEquation(com.jme3.material.RenderState.BlendEquation)
*/
- public boolean wireframe = false;
+ public RenderState.BlendEquation blendEquation = RenderState.BlendEquation.Add;
+
+ /**
+ * @see RenderState#setBlendEquationAlpha(com.jme3.material.RenderState.BlendEquationAlpha)
+ */
+ public RenderState.BlendEquationAlpha blendEquationAlpha = RenderState.BlendEquationAlpha.InheritColor;
/**
- * @see RenderState#setPointSprite(boolean)
+ * @see RenderState#setWireframe(boolean)
*/
- public boolean pointSprite = false;
+ public boolean wireframe = false;
/**
* @see Renderer#setShader(com.jme3.shader.Shader)
@@ -261,7 +256,6 @@ public class RenderContext {
public void reset(){
cullMode = RenderState.FaceCullMode.Off;
depthTestEnabled = false;
- alphaTestFallOff = 0f;
depthWriteEnabled = false;
colorWriteEnabled = false;
clipRectEnabled = false;
@@ -270,6 +264,8 @@ public class RenderContext {
polyOffsetUnits = 0;
pointSize = 1;
blendMode = RenderState.BlendMode.Off;
+ blendEquation = RenderState.BlendEquation.Add;
+ blendEquationAlpha = RenderState.BlendEquationAlpha.InheritColor;
wireframe = false;
boundShaderProgram = 0;
boundShader = null;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
index 7aac5a689..50cc207f7 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
@@ -34,8 +34,13 @@ package com.jme3.renderer;
import com.jme3.light.DefaultLightFilter;
import com.jme3.light.LightFilter;
import com.jme3.light.LightList;
-import com.jme3.material.*;
-import com.jme3.math.Matrix4f;
+import com.jme3.material.MatParamOverride;
+import com.jme3.material.Material;
+import com.jme3.material.MaterialDef;
+import com.jme3.material.RenderState;
+import com.jme3.material.Technique;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.*;
import com.jme3.post.SceneProcessor;
import com.jme3.profile.AppProfiler;
import com.jme3.profile.AppStep;
@@ -45,13 +50,12 @@ import com.jme3.renderer.queue.RenderQueue;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.*;
-import com.jme3.shader.Uniform;
+import com.jme3.shader.Shader;
import com.jme3.shader.UniformBinding;
import com.jme3.shader.UniformBindingManager;
import com.jme3.system.NullRenderer;
import com.jme3.system.Timer;
import com.jme3.util.SafeArrayList;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -70,25 +74,26 @@ import java.util.logging.Logger;
public class RenderManager {
private static final Logger logger = Logger.getLogger(RenderManager.class.getName());
- private Renderer renderer;
- private UniformBindingManager uniformBindingManager = new UniformBindingManager();
- private ArrayList preViewPorts = new ArrayList();
- private ArrayList viewPorts = new ArrayList();
- private ArrayList postViewPorts = new ArrayList();
+ private final Renderer renderer;
+ private final UniformBindingManager uniformBindingManager = new UniformBindingManager();
+ private final ArrayList preViewPorts = new ArrayList<>();
+ private final ArrayList viewPorts = new ArrayList<>();
+ private final ArrayList postViewPorts = new ArrayList<>();
private Camera prevCam = null;
private Material forcedMaterial = null;
private String forcedTechnique = null;
private RenderState forcedRenderState = null;
+ private final List forcedOverrides = new ArrayList<>();
private int viewX, viewY, viewWidth, viewHeight;
- private Matrix4f orthoMatrix = new Matrix4f();
- private LightList filteredLightList = new LightList(null);
- private String tmpTech;
+ private final Matrix4f orthoMatrix = new Matrix4f();
+ private final LightList filteredLightList = new LightList(null);
private boolean handleTranlucentBucket = true;
private AppProfiler prof;
private LightFilter lightFilter = new DefaultLightFilter();
private TechniqueDef.LightMode preferredLightMode = TechniqueDef.LightMode.MultiPass;
private int singlePassLightBatchSize = 1;
+
/**
* Create a high-level rendering interface over the
* low-level rendering interface.
@@ -423,6 +428,44 @@ public class RenderManager {
this.forcedTechnique = forcedTechnique;
}
+ /**
+ * Adds a forced material parameter to use when rendering geometries.
+ *
+ * The provided parameter takes precedence over parameters set on the
+ * material or any overrides that exist in the scene graph that have the
+ * same name.
+ *
+ * @param override The override to add
+ * @see MatParamOverride
+ * @see #removeForcedMatParam(com.jme3.material.MatParamOverride)
+ */
+ public void addForcedMatParam(MatParamOverride override) {
+ forcedOverrides.add(override);
+ }
+
+ /**
+ * Remove a forced material parameter previously added.
+ *
+ * @param override The override to remove.
+ * @see #addForcedMatParam(com.jme3.material.MatParamOverride)
+ */
+ public void removeForcedMatParam(MatParamOverride override) {
+ forcedOverrides.remove(override);
+ }
+
+ /**
+ * Get the forced material parameters applied to rendered geometries.
+ *
+ * Forced parameters can be added via
+ * {@link #addForcedMatParam(com.jme3.material.MatParamOverride)} or removed
+ * via {@link #removeForcedMatParam(com.jme3.material.MatParamOverride)}.
+ *
+ * @return The forced material parameters.
+ */
+ public List getForcedMatParams() {
+ return forcedOverrides;
+ }
+
/**
* Enable or disable alpha-to-coverage.
*
@@ -480,8 +523,8 @@ public class RenderManager {
* Updates the given list of uniforms with {@link UniformBinding uniform bindings}
* based on the current world state.
*/
- public void updateUniformBindings(List params) {
- uniformBindingManager.updateUniformBindings(params);
+ public void updateUniformBindings(Shader shader) {
+ uniformBindingManager.updateUniformBindings(shader);
}
/**
@@ -508,45 +551,54 @@ public class RenderManager {
* for rendering the material, and the material's own render state is ignored.
* Otherwise, the material's render state is used as intended.
*
- * @param g The geometry to render
- *
+ * @param geom The geometry to render
+ *
* @see Technique
* @see RenderState
* @see Material#selectTechnique(java.lang.String, com.jme3.renderer.RenderManager)
* @see Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager)
*/
- public void renderGeometry(Geometry g) {
- if (g.isIgnoreTransform()) {
+ public void renderGeometry(Geometry geom) {
+ if (geom.isIgnoreTransform()) {
setWorldMatrix(Matrix4f.IDENTITY);
} else {
- setWorldMatrix(g.getWorldMatrix());
+ setWorldMatrix(geom.getWorldMatrix());
}
// Perform light filtering if we have a light filter.
- LightList lightList = g.getWorldLightList();
+ LightList lightList = geom.getWorldLightList();
if (lightFilter != null) {
filteredLightList.clear();
- lightFilter.filterLights(g, filteredLightList);
+ lightFilter.filterLights(geom, filteredLightList);
lightList = filteredLightList;
}
+ Material material = geom.getMaterial();
+
//if forcedTechnique we try to force it for render,
//if it does not exists in the mat def, we check for forcedMaterial and render the geom if not null
//else the geom is not rendered
if (forcedTechnique != null) {
- if (g.getMaterial().getMaterialDef().getTechniqueDef(forcedTechnique) != null) {
- tmpTech = g.getMaterial().getActiveTechnique() != null ? g.getMaterial().getActiveTechnique().getDef().getName() : "Default";
- g.getMaterial().selectTechnique(forcedTechnique, this);
+ MaterialDef matDef = material.getMaterialDef();
+ if (matDef.getTechniqueDefs(forcedTechnique) != null) {
+
+ Technique activeTechnique = material.getActiveTechnique();
+
+ String previousTechniqueName = activeTechnique != null
+ ? activeTechnique.getDef().getName()
+ : TechniqueDef.DEFAULT_TECHNIQUE_NAME;
+
+ geom.getMaterial().selectTechnique(forcedTechnique, this);
//saving forcedRenderState for future calls
RenderState tmpRs = forcedRenderState;
- if (g.getMaterial().getActiveTechnique().getDef().getForcedRenderState() != null) {
+ if (geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState() != null) {
//forcing forced technique renderState
- forcedRenderState = g.getMaterial().getActiveTechnique().getDef().getForcedRenderState();
+ forcedRenderState = geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState();
}
// use geometry's material
- g.getMaterial().render(g, lightList, this);
- g.getMaterial().selectTechnique(tmpTech, this);
+ material.render(geom, lightList, this);
+ material.selectTechnique(previousTechniqueName, this);
//restoring forcedRenderState
forcedRenderState = tmpRs;
@@ -555,13 +607,13 @@ public class RenderManager {
//If forcedTechnique does not exists, and forcedMaterial is not set, the geom MUST NOT be rendered
} else if (forcedMaterial != null) {
// use forced material
- forcedMaterial.render(g, lightList, this);
+ forcedMaterial.render(geom, lightList, this);
}
} else if (forcedMaterial != null) {
// use forced material
- forcedMaterial.render(g, lightList, this);
+ forcedMaterial.render(geom, lightList, this);
} else {
- g.getMaterial().render(g, lightList, this);
+ material.render(geom, lightList, this);
}
}
@@ -612,7 +664,9 @@ public class RenderManager {
gm.getMaterial().preload(this);
Mesh mesh = gm.getMesh();
- if (mesh != null) {
+ if (mesh != null
+ && mesh.getVertexCount() != 0
+ && mesh.getTriangleCount() != 0) {
for (VertexBuffer vb : mesh.getBufferList().getArray()) {
if (vb.getData() != null && vb.getUsage() != VertexBuffer.Usage.CpuOnly) {
renderer.updateBufferData(vb);
@@ -637,8 +691,10 @@ public class RenderManager {
*
* In addition to enqueuing the visible geometries, this method
* also scenes which cast or receive shadows, by putting them into the
- * RenderQueue's {@link RenderQueue#renderShadowQueue(GeometryList, RenderManager, Camera, boolean) shadow queue}.
- * Each Spatial which has its {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode}
+ * RenderQueue's
+ * {@link RenderQueue#addToShadowQueue(com.jme3.scene.Geometry, com.jme3.renderer.queue.RenderQueue.ShadowMode)
+ * shadow queue}. Each Spatial which has its
+ * {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode}
* set to not off, will be put into the appropriate shadow queue, note that
* this process does not check for frustum culling on any
* {@link ShadowMode#Cast shadow casters}, as they don't have to be
@@ -985,7 +1041,8 @@ public class RenderManager {
* (see {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) })
*
If any objects remained in the render queue, they are removed
* from the queue. This is generally objects added to the
- * {@link RenderQueue#renderShadowQueue(GeometryList, RenderManager, Camera, boolean) shadow queue}
+ * {@link RenderQueue#renderShadowQueue(com.jme3.renderer.queue.RenderQueue.ShadowMode, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean)
+ * shadow queue}
* which were not rendered because of a missing shadow renderer.
*
*
diff --git a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java
index edfd380b4..d6645d24d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java
@@ -43,6 +43,7 @@ import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.util.NativeObject;
import java.nio.ByteBuffer;
+import java.util.EnumMap;
import java.util.EnumSet;
/**
@@ -66,6 +67,13 @@ public interface Renderer {
*/
public EnumSet getCaps();
+ /**
+ * Get the limits of the renderer.
+ *
+ * @return The limits of the renderer.
+ */
+ public EnumMap getLimits();
+
/**
* The statistics allow tracking of how data
* per frame, such as number of objects rendered, number of triangles, etc.
@@ -302,7 +310,21 @@ public interface Renderer {
* @see NativeObject#deleteObject(java.lang.Object)
*/
public void cleanup();
-
+
+ /**
+ * Set the default anisotropic filter level for textures.
+ *
+ * If the
+ * {@link Texture#setAnisotropicFilter(int) texture anisotropic filter} is
+ * set to 0, then the default level is used. Otherwise if the texture level
+ * is 1 or greater, then the texture's value overrides the default value.
+ *
+ * @param level The default anisotropic filter level to use. Default: 1.
+ *
+ * @throws IllegalArgumentException If level is less than 1.
+ */
+ public void setDefaultAnisotropicFilter(int level);
+
/**
* Sets the alpha to coverage state.
*
diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java
index 1b9c3f94d..a4a738152 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java
@@ -45,142 +45,149 @@ import java.nio.ShortBuffer;
*/
public interface GL {
- public static final int GL_ALPHA = 0x1906;
- public static final int GL_ALWAYS = 0x207;
- public static final int GL_ARRAY_BUFFER = 0x8892;
- public static final int GL_BACK = 0x405;
- public static final int GL_BLEND = 0xBE2;
- public static final int GL_BYTE = 0x1400;
- public static final int GL_CLAMP_TO_EDGE = 0x812F;
- public static final int GL_COLOR_BUFFER_BIT = 0x4000;
- public static final int GL_COMPILE_STATUS = 0x8B81;
- public static final int GL_CULL_FACE = 0xB44;
- public static final int GL_DECR = 0x1E03;
- public static final int GL_DECR_WRAP = 0x8508;
- public static final int GL_DEPTH_BUFFER_BIT = 0x100;
- public static final int GL_DEPTH_COMPONENT = 0x1902;
- public static final int GL_DEPTH_COMPONENT16 = 0x81A5;
- public static final int GL_DEPTH_TEST = 0xB71;
- public static final int GL_DOUBLE = 0x140A;
- public static final int GL_DST_COLOR = 0x306;
- public static final int GL_DYNAMIC_DRAW = 0x88E8;
- public static final int GL_ELEMENT_ARRAY_BUFFER = 0x8893;
- public static final int GL_EQUAL = 0x202;
- public static final int GL_EXTENSIONS = 0x1F03;
- public static final int GL_FALSE = 0x0;
- public static final int GL_FLOAT = 0x1406;
- public static final int GL_FRAGMENT_SHADER = 0x8B30;
- public static final int GL_FRONT = 0x404;
- public static final int GL_FRONT_AND_BACK = 0x408;
- public static final int GL_GEQUAL = 0x206;
- public static final int GL_GREATER = 0x204;
- public static final int GL_GREEN = 0x1904;
- public static final int GL_INCR = 0x1E02;
- public static final int GL_INCR_WRAP = 0x8507;
- public static final int GL_INFO_LOG_LENGTH = 0x8B84;
- public static final int GL_INT = 0x1404;
- public static final int GL_INVALID_ENUM = 0x500;
- public static final int GL_INVALID_VALUE = 0x501;
- public static final int GL_INVALID_OPERATION = 0x502;
- public static final int GL_INVERT = 0x150A;
- public static final int GL_KEEP = 0x1E00;
- public static final int GL_LEQUAL = 0x203;
- public static final int GL_LESS = 0x201;
- public static final int GL_LINEAR = 0x2601;
- public static final int GL_LINEAR_MIPMAP_LINEAR = 0x2703;
- public static final int GL_LINEAR_MIPMAP_NEAREST = 0x2701;
- public static final int GL_LINES = 0x1;
- public static final int GL_LINE_LOOP = 0x2;
- public static final int GL_LINE_STRIP = 0x3;
- public static final int GL_LINK_STATUS = 0x8B82;
- public static final int GL_LUMINANCE = 0x1909;
- public static final int GL_LUMINANCE_ALPHA = 0x190A;
- public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C;
- public static final int GL_MAX_TEXTURE_IMAGE_UNITS = 0x8872;
- public static final int GL_MAX_TEXTURE_SIZE = 0xD33;
- public static final int GL_MAX_VERTEX_ATTRIBS = 0x8869;
- public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C;
- public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A;
- public static final int GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB;
- public static final int GL_MIRRORED_REPEAT = 0x8370;
- public static final int GL_NEAREST = 0x2600;
- public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702;
- public static final int GL_NEAREST_MIPMAP_NEAREST = 0x2700;
- public static final int GL_NEVER = 0x200;
- public static final int GL_NO_ERROR = 0x0;
- public static final int GL_NONE = 0x0;
- public static final int GL_NOTEQUAL = 0x205;
- public static final int GL_ONE = 0x1;
- public static final int GL_ONE_MINUS_DST_COLOR = 0x307;
- public static final int GL_ONE_MINUS_SRC_ALPHA = 0x303;
- public static final int GL_ONE_MINUS_SRC_COLOR = 0x301;
- public static final int GL_OUT_OF_MEMORY = 0x505;
- public static final int GL_POINTS = 0x0;
- public static final int GL_POLYGON_OFFSET_FILL = 0x8037;
- public static final int GL_RED = 0x1903;
- public static final int GL_RENDERER = 0x1F01;
- public static final int GL_REPEAT = 0x2901;
- public static final int GL_REPLACE = 0x1E01;
- public static final int GL_RGB = 0x1907;
- public static final int GL_RGB565 = 0x8D62;
- public static final int GL_RGB5_A1 = 0x8057;
- public static final int GL_RGBA = 0x1908;
- public static final int GL_RGBA4 = 0x8056;
- public static final int GL_SCISSOR_TEST = 0xC11;
- public static final int GL_SHADING_LANGUAGE_VERSION = 0x8B8C;
- public static final int GL_SHORT = 0x1402;
- public static final int GL_SRC_ALPHA = 0x302;
- public static final int GL_SRC_COLOR = 0x300;
- public static final int GL_STATIC_DRAW = 0x88E4;
- public static final int GL_STENCIL_BUFFER_BIT = 0x400;
- public static final int GL_STENCIL_TEST = 0xB90;
- public static final int GL_STREAM_DRAW = 0x88E0;
- public static final int GL_STREAM_READ = 0x88E1;
- public static final int GL_TEXTURE = 0x1702;
- public static final int GL_TEXTURE0 = 0x84C0;
- public static final int GL_TEXTURE1 = 0x84C1;
- public static final int GL_TEXTURE2 = 0x84C2;
- public static final int GL_TEXTURE3 = 0x84C3;
- public static final int GL_TEXTURE4 = 0x84C4;
- public static final int GL_TEXTURE5 = 0x84C5;
- public static final int GL_TEXTURE6 = 0x84C6;
- public static final int GL_TEXTURE7 = 0x84C7;
- public static final int GL_TEXTURE8 = 0x84C8;
- public static final int GL_TEXTURE9 = 0x84C9;
- public static final int GL_TEXTURE10 = 0x84CA;
- public static final int GL_TEXTURE11 = 0x84CB;
- public static final int GL_TEXTURE12 = 0x84CC;
- public static final int GL_TEXTURE13 = 0x84CD;
- public static final int GL_TEXTURE14 = 0x84CE;
- public static final int GL_TEXTURE15 = 0x84CF;
- public static final int GL_TEXTURE_2D = 0xDE1;
- public static final int GL_TEXTURE_CUBE_MAP = 0x8513;
- public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515;
- public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516;
- public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517;
- public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518;
- public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519;
- public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A;
- public static final int GL_TEXTURE_BASE_LEVEL = 0x813C;
- public static final int GL_TEXTURE_MAG_FILTER = 0x2800;
- public static final int GL_TEXTURE_MAX_LEVEL = 0x813D;
- public static final int GL_TEXTURE_MIN_FILTER = 0x2801;
- public static final int GL_TEXTURE_WRAP_S = 0x2802;
- public static final int GL_TEXTURE_WRAP_T = 0x2803;
- public static final int GL_TRIANGLES = 0x4;
- public static final int GL_TRIANGLE_FAN = 0x6;
- public static final int GL_TRIANGLE_STRIP = 0x5;
- public static final int GL_TRUE = 0x1;
- public static final int GL_UNPACK_ALIGNMENT = 0xCF5;
- public static final int GL_UNSIGNED_BYTE = 0x1401;
- public static final int GL_UNSIGNED_INT = 0x1405;
- public static final int GL_UNSIGNED_SHORT = 0x1403;
- public static final int GL_UNSIGNED_SHORT_5_6_5 = 0x8363;
- public static final int GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034;
- public static final int GL_VENDOR = 0x1F00;
- public static final int GL_VERSION = 0x1F02;
- public static final int GL_VERTEX_SHADER = 0x8B31;
- public static final int GL_ZERO = 0x0;
+ public static final int GL_ALPHA = 0x1906;
+ public static final int GL_ALWAYS = 0x207;
+ public static final int GL_ARRAY_BUFFER = 0x8892;
+ public static final int GL_BACK = 0x405;
+ public static final int GL_BLEND = 0xBE2;
+ public static final int GL_BYTE = 0x1400;
+ public static final int GL_CLAMP_TO_EDGE = 0x812F;
+ public static final int GL_COLOR_BUFFER_BIT = 0x4000;
+ public static final int GL_COMPILE_STATUS = 0x8B81;
+ public static final int GL_CULL_FACE = 0xB44;
+ public static final int GL_DECR = 0x1E03;
+ public static final int GL_DECR_WRAP = 0x8508;
+ public static final int GL_DEPTH_BUFFER_BIT = 0x100;
+ public static final int GL_DEPTH_COMPONENT = 0x1902;
+ public static final int GL_DEPTH_COMPONENT16 = 0x81A5;
+ public static final int GL_DEPTH_TEST = 0xB71;
+ public static final int GL_DOUBLE = 0x140A;
+ public static final int GL_DST_COLOR = 0x306;
+ public static final int GL_DYNAMIC_DRAW = 0x88E8;
+ public static final int GL_ELEMENT_ARRAY_BUFFER = 0x8893;
+ public static final int GL_EQUAL = 0x202;
+ public static final int GL_EXTENSIONS = 0x1F03;
+ public static final int GL_FALSE = 0x0;
+ public static final int GL_FLOAT = 0x1406;
+ public static final int GL_FRAGMENT_SHADER = 0x8B30;
+ public static final int GL_FRONT = 0x404;
+ public static final int GL_FUNC_ADD = 0x8006;
+ public static final int GL_FUNC_SUBTRACT = 0x800A;
+ public static final int GL_FUNC_REVERSE_SUBTRACT = 0x800B;
+ public static final int GL_FRONT_AND_BACK = 0x408;
+ public static final int GL_GEQUAL = 0x206;
+ public static final int GL_GREATER = 0x204;
+ public static final int GL_GREEN = 0x1904;
+ public static final int GL_INCR = 0x1E02;
+ public static final int GL_INCR_WRAP = 0x8507;
+ public static final int GL_INFO_LOG_LENGTH = 0x8B84;
+ public static final int GL_INT = 0x1404;
+ public static final int GL_INVALID_ENUM = 0x500;
+ public static final int GL_INVALID_VALUE = 0x501;
+ public static final int GL_INVALID_OPERATION = 0x502;
+ public static final int GL_INVERT = 0x150A;
+ public static final int GL_KEEP = 0x1E00;
+ public static final int GL_LEQUAL = 0x203;
+ public static final int GL_LESS = 0x201;
+ public static final int GL_LINEAR = 0x2601;
+ public static final int GL_LINEAR_MIPMAP_LINEAR = 0x2703;
+ public static final int GL_LINEAR_MIPMAP_NEAREST = 0x2701;
+ public static final int GL_LINES = 0x1;
+ public static final int GL_LINE_LOOP = 0x2;
+ public static final int GL_LINE_STRIP = 0x3;
+ public static final int GL_LINK_STATUS = 0x8B82;
+ public static final int GL_LUMINANCE = 0x1909;
+ public static final int GL_LUMINANCE_ALPHA = 0x190A;
+ public static final int GL_MAX = 0x8008;
+ public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C;
+ public static final int GL_MAX_FRAGMENT_UNIFORM_COMPONENTS = 0x8B49;
+ public static final int GL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD;
+ public static final int GL_MAX_TEXTURE_IMAGE_UNITS = 0x8872;
+ public static final int GL_MAX_TEXTURE_SIZE = 0xD33;
+ public static final int GL_MAX_VERTEX_ATTRIBS = 0x8869;
+ public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C;
+ public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A;
+ public static final int GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB;
+ public static final int GL_MIRRORED_REPEAT = 0x8370;
+ public static final int GL_MIN = 0x8007;
+ public static final int GL_NEAREST = 0x2600;
+ public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702;
+ public static final int GL_NEAREST_MIPMAP_NEAREST = 0x2700;
+ public static final int GL_NEVER = 0x200;
+ public static final int GL_NO_ERROR = 0x0;
+ public static final int GL_NONE = 0x0;
+ public static final int GL_NOTEQUAL = 0x205;
+ public static final int GL_ONE = 0x1;
+ public static final int GL_ONE_MINUS_DST_COLOR = 0x307;
+ public static final int GL_ONE_MINUS_SRC_ALPHA = 0x303;
+ public static final int GL_ONE_MINUS_SRC_COLOR = 0x301;
+ public static final int GL_OUT_OF_MEMORY = 0x505;
+ public static final int GL_POINTS = 0x0;
+ public static final int GL_POLYGON_OFFSET_FILL = 0x8037;
+ public static final int GL_RED = 0x1903;
+ public static final int GL_RENDERER = 0x1F01;
+ public static final int GL_REPEAT = 0x2901;
+ public static final int GL_REPLACE = 0x1E01;
+ public static final int GL_RGB = 0x1907;
+ public static final int GL_RGB565 = 0x8D62;
+ public static final int GL_RGB5_A1 = 0x8057;
+ public static final int GL_RGBA = 0x1908;
+ public static final int GL_RGBA4 = 0x8056;
+ public static final int GL_SCISSOR_TEST = 0xC11;
+ public static final int GL_SHADING_LANGUAGE_VERSION = 0x8B8C;
+ public static final int GL_SHORT = 0x1402;
+ public static final int GL_SRC_ALPHA = 0x302;
+ public static final int GL_SRC_COLOR = 0x300;
+ public static final int GL_STATIC_DRAW = 0x88E4;
+ public static final int GL_STENCIL_BUFFER_BIT = 0x400;
+ public static final int GL_STENCIL_TEST = 0xB90;
+ public static final int GL_STREAM_DRAW = 0x88E0;
+ public static final int GL_STREAM_READ = 0x88E1;
+ public static final int GL_TEXTURE = 0x1702;
+ public static final int GL_TEXTURE0 = 0x84C0;
+ public static final int GL_TEXTURE1 = 0x84C1;
+ public static final int GL_TEXTURE2 = 0x84C2;
+ public static final int GL_TEXTURE3 = 0x84C3;
+ public static final int GL_TEXTURE4 = 0x84C4;
+ public static final int GL_TEXTURE5 = 0x84C5;
+ public static final int GL_TEXTURE6 = 0x84C6;
+ public static final int GL_TEXTURE7 = 0x84C7;
+ public static final int GL_TEXTURE8 = 0x84C8;
+ public static final int GL_TEXTURE9 = 0x84C9;
+ public static final int GL_TEXTURE10 = 0x84CA;
+ public static final int GL_TEXTURE11 = 0x84CB;
+ public static final int GL_TEXTURE12 = 0x84CC;
+ public static final int GL_TEXTURE13 = 0x84CD;
+ public static final int GL_TEXTURE14 = 0x84CE;
+ public static final int GL_TEXTURE15 = 0x84CF;
+ public static final int GL_TEXTURE_2D = 0xDE1;
+ public static final int GL_TEXTURE_CUBE_MAP = 0x8513;
+ public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515;
+ public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516;
+ public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517;
+ public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518;
+ public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519;
+ public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A;
+ public static final int GL_TEXTURE_BASE_LEVEL = 0x813C;
+ public static final int GL_TEXTURE_MAG_FILTER = 0x2800;
+ public static final int GL_TEXTURE_MAX_LEVEL = 0x813D;
+ public static final int GL_TEXTURE_MIN_FILTER = 0x2801;
+ public static final int GL_TEXTURE_WRAP_S = 0x2802;
+ public static final int GL_TEXTURE_WRAP_T = 0x2803;
+ public static final int GL_TRIANGLES = 0x4;
+ public static final int GL_TRIANGLE_FAN = 0x6;
+ public static final int GL_TRIANGLE_STRIP = 0x5;
+ public static final int GL_TRUE = 0x1;
+ public static final int GL_UNPACK_ALIGNMENT = 0xCF5;
+ public static final int GL_UNSIGNED_BYTE = 0x1401;
+ public static final int GL_UNSIGNED_INT = 0x1405;
+ public static final int GL_UNSIGNED_SHORT = 0x1403;
+ public static final int GL_UNSIGNED_SHORT_5_6_5 = 0x8363;
+ public static final int GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034;
+ public static final int GL_VENDOR = 0x1F00;
+ public static final int GL_VERSION = 0x1F02;
+ public static final int GL_VERTEX_SHADER = 0x8B31;
+ public static final int GL_ZERO = 0x0;
public void resetStats();
@@ -188,6 +195,7 @@ public interface GL {
public void glAttachShader(int program, int shader);
public void glBindBuffer(int target, int buffer);
public void glBindTexture(int target, int texture);
+ public void glBlendEquationSeparate(int colorMode, int alphaMode);
public void glBlendFunc(int sfactor, int dfactor);
public void glBufferData(int target, long data_size, int usage);
public void glBufferData(int target, FloatBuffer data, int usage);
diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java
index fd18cc7ff..44dc3687a 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java
@@ -100,4 +100,9 @@ public class GLDebugDesktop extends GLDebugES implements GL2, GL3, GL4 {
gl3.glFramebufferTextureLayer(param1, param2, param3, param4, param5);
checkError();
}
+
+ public void glBlendEquationSeparate(int colorMode, int alphaMode) {
+ gl.glBlendEquationSeparate(colorMode, alphaMode);
+ checkError();
+ }
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java
index 2348bd3cd..ed6b336f8 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java
@@ -560,4 +560,9 @@ public class GLDebugES extends GLDebug implements GL, GLFbo, GLExt {
checkError();
return sync;
}
+
+ public void glBlendEquationSeparate(int colorMode, int alphaMode) {
+ gl.glBlendEquationSeparate(colorMode, alphaMode);
+ checkError();
+ }
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java
index 636733583..70d25ccd4 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java
@@ -90,6 +90,7 @@ public final class GLRenderer implements Renderer {
private final Statistics statistics = new Statistics();
private int vpX, vpY, vpW, vpH;
private int clipX, clipY, clipW, clipH;
+ private int defaultAnisotropicFilter = 1;
private boolean linearizeSrgbImages;
private HashSet extensions;
@@ -252,18 +253,14 @@ public final class GLRenderer implements Renderer {
limits.put(Limits.FragmentTextureUnits, getInteger(GL.GL_MAX_TEXTURE_IMAGE_UNITS));
-// gl.glGetInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS, intBuf16);
-// vertexUniforms = intBuf16.get(0);
-// logger.log(Level.FINER, "Vertex Uniforms: {0}", vertexUniforms);
-//
-// gl.glGetInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16);
-// fragUniforms = intBuf16.get(0);
-// logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms);
if (caps.contains(Caps.OpenGLES20)) {
+ limits.put(Limits.FragmentUniformVectors, getInteger(GL.GL_MAX_FRAGMENT_UNIFORM_VECTORS));
limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_VECTORS));
} else {
+ limits.put(Limits.FragmentUniformVectors, getInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS) / 4);
limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS) / 4);
}
+
limits.put(Limits.VertexAttributes, getInteger(GL.GL_MAX_VERTEX_ATTRIBS));
limits.put(Limits.TextureSize, getInteger(GL.GL_MAX_TEXTURE_SIZE));
limits.put(Limits.CubemapSize, getInteger(GL.GL_MAX_CUBE_MAP_TEXTURE_SIZE));
@@ -474,6 +471,17 @@ public final class GLRenderer implements Renderer {
{
sb.append("\t").append(cap.toString()).append("\n");
}
+
+ sb.append("\nHardware limits: \n");
+ for (Limits limit : Limits.values()) {
+ Integer value = limits.get(limit);
+ if (value == null) {
+ value = 0;
+ }
+ sb.append("\t").append(limit.name()).append(" = ")
+ .append(value).append("\n");
+ }
+
logger.log(Level.FINE, sb.toString());
}
@@ -522,7 +530,6 @@ public final class GLRenderer implements Renderer {
gl2.glEnable(GL2.GL_VERTEX_PROGRAM_POINT_SIZE);
if (!caps.contains(Caps.CoreProfile)) {
gl2.glEnable(GL2.GL_POINT_SPRITE);
- context.pointSprite = true;
}
}
}
@@ -594,6 +601,14 @@ public final class GLRenderer implements Renderer {
}
}
+ @Override
+ public void setDefaultAnisotropicFilter(int level) {
+ if (level < 1) {
+ throw new IllegalArgumentException("level cannot be less than 1");
+ }
+ this.defaultAnisotropicFilter = level;
+ }
+
public void setAlphaToCoverage(boolean value) {
if (caps.contains(Caps.Multisample)) {
if (value) {
@@ -735,6 +750,19 @@ public final class GLRenderer implements Renderer {
throw new UnsupportedOperationException("Unrecognized blend mode: "
+ state.getBlendMode());
}
+
+ if (state.getBlendEquation() != context.blendEquation || state.getBlendEquationAlpha() != context.blendEquationAlpha) {
+ int colorMode = convertBlendEquation(state.getBlendEquation());
+ int alphaMode;
+ if (state.getBlendEquationAlpha() == RenderState.BlendEquationAlpha.InheritColor) {
+ alphaMode = colorMode;
+ } else {
+ alphaMode = convertBlendEquationAlpha(state.getBlendEquationAlpha());
+ }
+ gl.glBlendEquationSeparate(colorMode, alphaMode);
+ context.blendEquation = state.getBlendEquation();
+ context.blendEquationAlpha = state.getBlendEquationAlpha();
+ }
}
context.blendMode = state.getBlendMode();
@@ -785,6 +813,41 @@ public final class GLRenderer implements Renderer {
}
}
+ private int convertBlendEquation(RenderState.BlendEquation blendEquation) {
+ switch (blendEquation) {
+ case Add:
+ return GL2.GL_FUNC_ADD;
+ case Subtract:
+ return GL2.GL_FUNC_SUBTRACT;
+ case ReverseSubtract:
+ return GL2.GL_FUNC_REVERSE_SUBTRACT;
+ case Min:
+ return GL2.GL_MIN;
+ case Max:
+ return GL2.GL_MAX;
+ default:
+ throw new UnsupportedOperationException("Unrecognized blend operation: " + blendEquation);
+ }
+ }
+
+ private int convertBlendEquationAlpha(RenderState.BlendEquationAlpha blendEquationAlpha) {
+ //Note: InheritColor mode should already be handled, that is why it does not belong the the switch case.
+ switch (blendEquationAlpha) {
+ case Add:
+ return GL2.GL_FUNC_ADD;
+ case Subtract:
+ return GL2.GL_FUNC_SUBTRACT;
+ case ReverseSubtract:
+ return GL2.GL_FUNC_REVERSE_SUBTRACT;
+ case Min:
+ return GL2.GL_MIN;
+ case Max:
+ return GL2.GL_MAX;
+ default:
+ throw new UnsupportedOperationException("Unrecognized alpha blend operation: " + blendEquationAlpha);
+ }
+ }
+
private int convertStencilOperation(StencilOperation stencilOp) {
switch (stencilOp) {
case Keep:
@@ -964,12 +1027,12 @@ public final class GLRenderer implements Renderer {
gl.glUniform1i(loc, b.booleanValue() ? GL.GL_TRUE : GL.GL_FALSE);
break;
case Matrix3:
- fb = (FloatBuffer) uniform.getValue();
+ fb = uniform.getMultiData();
assert fb.remaining() == 9;
gl.glUniformMatrix3(loc, false, fb);
break;
case Matrix4:
- fb = (FloatBuffer) uniform.getValue();
+ fb = uniform.getMultiData();
assert fb.remaining() == 16;
gl.glUniformMatrix4(loc, false, fb);
break;
@@ -978,23 +1041,23 @@ public final class GLRenderer implements Renderer {
gl.glUniform1(loc, ib);
break;
case FloatArray:
- fb = (FloatBuffer) uniform.getValue();
+ fb = uniform.getMultiData();
gl.glUniform1(loc, fb);
break;
case Vector2Array:
- fb = (FloatBuffer) uniform.getValue();
+ fb = uniform.getMultiData();
gl.glUniform2(loc, fb);
break;
case Vector3Array:
- fb = (FloatBuffer) uniform.getValue();
+ fb = uniform.getMultiData();
gl.glUniform3(loc, fb);
break;
case Vector4Array:
- fb = (FloatBuffer) uniform.getValue();
+ fb = uniform.getMultiData();
gl.glUniform4(loc, fb);
break;
case Matrix4Array:
- fb = (FloatBuffer) uniform.getValue();
+ fb = uniform.getMultiData();
gl.glUniformMatrix4(loc, false, fb);
break;
case Int:
@@ -1872,13 +1935,18 @@ public final class GLRenderer implements Renderer {
gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, convertMinFilter(tex.getMinFilter(), haveMips));
curState.minFilter = tex.getMinFilter();
}
+
+ int desiredAnisoFilter = tex.getAnisotropicFilter() == 0
+ ? defaultAnisotropicFilter
+ : tex.getAnisotropicFilter();
+
if (caps.contains(Caps.TextureFilterAnisotropic)
- && curState.anisoFilter != tex.getAnisotropicFilter()) {
+ && curState.anisoFilter != desiredAnisoFilter) {
bindTextureAndUnit(target, image, unit);
gl.glTexParameterf(target,
GLExt.GL_TEXTURE_MAX_ANISOTROPY_EXT,
- tex.getAnisotropicFilter());
- curState.anisoFilter = tex.getAnisotropicFilter();
+ desiredAnisoFilter);
+ curState.anisoFilter = desiredAnisoFilter;
}
switch (tex.getType()) {
@@ -2689,12 +2757,15 @@ public final class GLRenderer implements Renderer {
}
public void renderMesh(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) {
- if (mesh.getVertexCount() == 0) {
+ if (mesh.getVertexCount() == 0 || mesh.getTriangleCount() == 0 || count == 0) {
return;
}
- //this is kept for backward compatibility.
- if (mesh.getLineWidth() != -1 && context.lineWidth != mesh.getLineWidth()) {
+ if (count > 1 && !caps.contains(Caps.MeshInstancing)) {
+ throw new RendererException("Mesh instancing is not supported by the video hardware");
+ }
+
+ if (mesh.getLineWidth() != 1f && context.lineWidth != mesh.getLineWidth()) {
gl.glLineWidth(mesh.getLineWidth());
context.lineWidth = mesh.getLineWidth();
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java b/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java
index 5529ac84e..09b43b9e8 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java
@@ -99,6 +99,16 @@ public class GeometryList implements Iterable{
return size;
}
+ /**
+ * Sets the element at the given index.
+ *
+ * @param index The index to set
+ * @param value The value
+ */
+ public void set(int index, Geometry value) {
+ geometries[index] = value;
+ }
+
/**
* Returns the element at the given index.
*
diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/OpaqueComparator.java b/jme3-core/src/main/java/com/jme3/renderer/queue/OpaqueComparator.java
index 6ffff5702..4b1305c60 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/queue/OpaqueComparator.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/queue/OpaqueComparator.java
@@ -69,11 +69,12 @@ public class OpaqueComparator implements GeometryComparator {
return spat.queueDistance;
}
+ @Override
public int compare(Geometry o1, Geometry o2) {
Material m1 = o1.getMaterial();
Material m2 = o2.getMaterial();
-
- int compareResult = m2.getSortId() - m1.getSortId();
+
+ int compareResult = Integer.compare(m1.getSortId(), m2.getSortId());
if (compareResult == 0){
// use the same shader.
// sort front-to-back then.
diff --git a/jme3-core/src/main/java/com/jme3/scene/Mesh.java b/jme3-core/src/main/java/com/jme3/scene/Mesh.java
index 6a0b41c8c..84c279536 100644
--- a/jme3-core/src/main/java/com/jme3/scene/Mesh.java
+++ b/jme3-core/src/main/java/com/jme3/scene/Mesh.java
@@ -175,7 +175,7 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
private IntMap buffers = new IntMap();
private VertexBuffer[] lodLevels;
private float pointSize = 1;
- private float lineWidth = -1;
+ private float lineWidth = 1;
private transient int vertexArrayID = -1;
@@ -589,28 +589,26 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
}
/**
- * Returns the size of points for point meshes
+ * @deprecated Always returns 1.0
since point size is
+ * determined in the vertex shader.
*
- * @return the size of points
+ * @return 1.0
*
* @see #setPointSize(float)
*/
+ @Deprecated
public float getPointSize() {
- return pointSize;
+ return 1.0f;
}
/**
- * Set the size of points for meshes of mode {@link Mode#Points}.
- * The point size is specified as on-screen pixels, the default
- * value is 1.0. The point size
- * does nothing if {@link RenderState#setPointSprite(boolean) point sprite}
- * render state is enabled, in that case, the vertex shader must specify the
- * point size by writing to gl_PointSize
.
+ * @deprecated Does nothing, since the size of {@link Mode#Points points} is
+ * determined via the vertex shader's gl_PointSize
output.
*
- * @param pointSize The size of points
+ * @param pointSize ignored
*/
+ @Deprecated
public void setPointSize(float pointSize) {
- this.pointSize = pointSize;
}
/**
@@ -634,6 +632,9 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
*/
@Deprecated
public void setLineWidth(float lineWidth) {
+ if (lineWidth < 1f) {
+ throw new IllegalArgumentException("lineWidth must be greater than or equal to 1.0");
+ }
this.lineWidth = lineWidth;
}
diff --git a/jme3-core/src/main/java/com/jme3/scene/Node.java b/jme3-core/src/main/java/com/jme3/scene/Node.java
index 35526c3ce..6089eda49 100644
--- a/jme3-core/src/main/java/com/jme3/scene/Node.java
+++ b/jme3-core/src/main/java/com/jme3/scene/Node.java
@@ -75,7 +75,6 @@ public class Node extends Spatial {
* requiresUpdate() method.
*/
private SafeArrayList updateList = null;
-
/**
* False if the update list requires rebuilding. This is Node.class
* specific and therefore not included as part of the Spatial update flags.
@@ -100,7 +99,6 @@ public class Node extends Spatial {
*/
public Node(String name) {
super(name);
-
// For backwards compatibility, only clear the "requires
// update" flag if we are not a subclass of Node.
// This prevents subclass from silently failing to receive
@@ -141,10 +139,21 @@ public class Node extends Spatial {
}
}
+ @Override
+ protected void setMatParamOverrideRefresh() {
+ super.setMatParamOverrideRefresh();
+ for (Spatial child : children.getArray()) {
+ if ((child.refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
+ continue;
+ }
+
+ child.setMatParamOverrideRefresh();
+ }
+ }
+
@Override
protected void updateWorldBound(){
super.updateWorldBound();
-
// for a node, the world bound is a combination of all it's children
// bounds
BoundingVolume resultBound = null;
@@ -239,19 +248,19 @@ public class Node extends Spatial {
// This branch has no geometric state that requires updates.
return;
}
-
if ((refreshFlags & RF_LIGHTLIST) != 0){
updateWorldLightList();
}
-
if ((refreshFlags & RF_TRANSFORM) != 0){
// combine with parent transforms- same for all spatial
// subclasses.
updateWorldTransforms();
}
+ if ((refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
+ updateMatParamOverrides();
+ }
refreshFlags &= ~RF_CHILD_LIGHTLIST;
-
if (!children.isEmpty()) {
// the important part- make sure child geometric state is refreshed
// first before updating own world bound. This saves
@@ -287,7 +296,6 @@ public class Node extends Spatial {
return count;
}
-
/**
* getVertexCount
returns the number of vertices contained
* in all sub-branches of this node that contain geometry.
@@ -321,7 +329,6 @@ public class Node extends Spatial {
public int attachChild(Spatial child) {
return attachChildAt(child, children.size());
}
-
/**
*
* attachChildAt
attaches a child to this node at an index. This node
@@ -345,20 +352,18 @@ public class Node extends Spatial {
}
child.setParent(this);
children.add(index, child);
-
// XXX: Not entirely correct? Forces bound update up the
// tree stemming from the attached child. Also forces
// transform update down the tree-
child.setTransformRefresh();
child.setLightListRefresh();
+ child.setMatParamOverrideRefresh();
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,"Child ({0}) attached to this node ({1})",
new Object[]{child.getName(), getName()});
}
-
invalidateUpdateList();
}
-
return children.size();
}
@@ -433,7 +438,8 @@ public class Node extends Spatial {
child.setTransformRefresh();
// lights are also inherited from parent
child.setLightListRefresh();
-
+ child.setMatParamOverrideRefresh();
+
invalidateUpdateList();
}
return child;
@@ -519,7 +525,6 @@ public class Node extends Spatial {
}
return null;
}
-
/**
* determines if the provided Spatial is contained in the children list of
* this node.
@@ -567,39 +572,32 @@ public class Node extends Spatial {
public int collideWith(Collidable other, CollisionResults results){
int total = 0;
-
// optimization: try collideWith BoundingVolume to avoid possibly redundant tests on children
// number 4 in condition is somewhat arbitrary. When there is only one child, the boundingVolume test is redundant at all.
// The idea is when there are few children, it can be too expensive to test boundingVolume first.
/*
I'm removing this change until some issues can be addressed and I really
think it needs to be implemented a better way anyway.
-
First, it causes issues for anyone doing collideWith() with BoundingVolumes
and expecting it to trickle down to the children. For example, children
with BoundingSphere bounding volumes and collideWith(BoundingSphere). Doing
a collision check at the parent level then has to do a BoundingSphere to BoundingBox
collision which isn't resolved. (Having to come up with a collision point in that
case is tricky and the first sign that this is the wrong approach.)
-
Second, the rippling changes this caused to 'optimize' collideWith() for this
special use-case are another sign that this approach was a bit dodgy. The whole
idea of calculating a full collision just to see if the two shapes collide at all
is very wasteful.
-
A proper implementation should support a simpler boolean check that doesn't do
all of that calculation. For example, if 'other' is also a BoundingVolume (ie: 99.9%
of all non-Ray cases) then a direct BV to BV intersects() test can be done. So much
faster. And if 'other' _is_ a Ray then the BV.intersects(Ray) call can be done.
-
I don't have time to do it right now but I'll at least un-break a bunch of peoples'
code until it can be 'optimized' properly. Hopefully it's not too late to back out
the other dodgy ripples this caused. -pspeed (hindsight-expert ;))
-
Note: the code itself is relatively simple to implement but I don't have time to
a) test it, and b) see if '> 4' is still a decent check for it. Could be it's fast
enough to do all the time for > 1.
-
if (children.size() > 4)
{
BoundingVolume bv = this.getWorldBound();
@@ -692,7 +690,6 @@ public class Node extends Spatial {
// Reset the fields of the clone that should be in a 'new' state.
nodeClone.updateList = null;
nodeClone.updateListValid = false; // safe because parent is nulled out in super.clone()
-
return nodeClone;
}
@@ -732,7 +729,6 @@ public class Node extends Spatial {
// cloning this list is fine.
this.updateList = cloner.clone(updateList);
}
-
@Override
public void write(JmeExporter e) throws IOException {
super.write(e);
@@ -744,7 +740,6 @@ public class Node extends Spatial {
// XXX: Load children before loading itself!!
// This prevents empty children list if controls query
// it in Control.setSpatial().
-
children = new SafeArrayList( Spatial.class,
e.getCapsule(this).readSavableArrayList("children", null) );
@@ -754,7 +749,6 @@ public class Node extends Spatial {
child.parent = this;
}
}
-
super.read(e);
}
@@ -775,7 +769,6 @@ public class Node extends Spatial {
}
}
}
-
@Override
public void depthFirstTraversal(SceneGraphVisitor visitor) {
for (Spatial child : children.getArray()) {
@@ -783,7 +776,6 @@ public class Node extends Spatial {
}
visitor.visit(this);
}
-
@Override
protected void breadthFirstTraversal(SceneGraphVisitor visitor, Queue queue) {
queue.addAll(children);
diff --git a/jme3-core/src/main/java/com/jme3/scene/Spatial.java b/jme3-core/src/main/java/com/jme3/scene/Spatial.java
index 15757eee0..452ccce47 100644
--- a/jme3-core/src/main/java/com/jme3/scene/Spatial.java
+++ b/jme3-core/src/main/java/com/jme3/scene/Spatial.java
@@ -38,6 +38,7 @@ import com.jme3.collision.Collidable;
import com.jme3.export.*;
import com.jme3.light.Light;
import com.jme3.light.LightList;
+import com.jme3.material.MatParamOverride;
import com.jme3.material.Material;
import com.jme3.math.*;
import com.jme3.renderer.Camera;
@@ -121,9 +122,10 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
*/
protected static final int RF_TRANSFORM = 0x01, // need light resort + combine transforms
RF_BOUND = 0x02,
- RF_LIGHTLIST = 0x04, // changes in light lists
- RF_CHILD_LIGHTLIST = 0x08; // some child need geometry update
-
+ RF_LIGHTLIST = 0x04, // changes in light lists
+ RF_CHILD_LIGHTLIST = 0x08, // some child need geometry update
+ RF_MATPARAM_OVERRIDE = 0x10;
+
protected CullHint cullHint = CullHint.Inherit;
protected BatchHint batchHint = BatchHint.Inherit;
/**
@@ -135,7 +137,11 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
*/
protected LightList localLights;
protected transient LightList worldLights;
- /**
+
+ protected ArrayList localOverrides;
+ protected ArrayList worldOverrides;
+
+ /**
* This spatial's name.
*/
protected String name;
@@ -195,13 +201,14 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
*/
protected Spatial(String name) {
this.name = name;
-
localTransform = new Transform();
worldTransform = new Transform();
localLights = new LightList(this);
worldLights = new LightList(this);
+ localOverrides = new ArrayList<>();
+ worldOverrides = new ArrayList<>();
refreshFlags |= RF_BOUND;
}
@@ -222,7 +229,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
boolean requiresUpdates() {
return requiresUpdates | !controls.isEmpty();
}
-
/**
* Subclasses can call this with true to denote that they require
* updateLogicalState() to be called even if they contain no controls.
@@ -272,35 +278,33 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
protected void setLightListRefresh() {
refreshFlags |= RF_LIGHTLIST;
-
// Make sure next updateGeometricState() visits this branch
// to update lights.
Spatial p = parent;
while (p != null) {
- //if (p.refreshFlags != 0) {
- // any refresh flag is sufficient,
- // as each propagates to the root Node
-
- // 2015/2/8:
- // This is not true, because using e.g. getWorldBound()
- // or getWorldTransform() activates a "partial refresh"
- // which does not update the lights but does clear
- // the refresh flags on the ancestors!
-
- // return;
- //}
-
if ((p.refreshFlags & RF_CHILD_LIGHTLIST) != 0) {
// The parent already has this flag,
// so must all ancestors.
return;
}
-
p.refreshFlags |= RF_CHILD_LIGHTLIST;
p = p.parent;
}
}
+ protected void setMatParamOverrideRefresh() {
+ refreshFlags |= RF_MATPARAM_OVERRIDE;
+ Spatial p = parent;
+ while (p != null) {
+ if ((p.refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
+ return;
+ }
+
+ p.refreshFlags |= RF_MATPARAM_OVERRIDE;
+ p = p.parent;
+ }
+ }
+
/**
* Indicate that the bounding of this spatial has changed and that
* a refresh is required.
@@ -318,7 +322,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
p = p.parent;
}
}
-
/**
* (Internal use only) Forces a refresh of the given types of data.
*
@@ -424,6 +427,29 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
return worldLights;
}
+ /**
+ * Get the local material parameter overrides.
+ *
+ * @return The list of local material parameter overrides.
+ */
+ public List getLocalMatParamOverrides() {
+ return localOverrides;
+ }
+
+ /**
+ * Get the world material parameter overrides.
+ *
+ * Note that this list is only updated on a call to
+ * {@link #updateGeometricState()}. After update, the world overrides list
+ * will contain the {@link #getParent() parent's} world overrides combined
+ * with this spatial's {@link #getLocalMatParamOverrides() local overrides}.
+ *
+ * @return The list of world material parameter overrides.
+ */
+ public List getWorldMatParamOverrides() {
+ return worldOverrides;
+ }
+
/**
* getWorldRotation
retrieves the absolute rotation of the
* Spatial.
@@ -525,10 +551,8 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
TempVars vars = TempVars.get();
Vector3f compVecA = vars.vect4;
-
compVecA.set(position).subtractLocal(worldTranslation);
getLocalRotation().lookAt(compVecA, upVector);
-
if ( getParent() != null ) {
Quaternion rot=vars.quat1;
rot = rot.set(parent.getWorldRotation()).inverseLocal().multLocal(getLocalRotation());
@@ -555,15 +579,63 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
worldLights.update(localLights, null);
refreshFlags &= ~RF_LIGHTLIST;
} else {
- if ((parent.refreshFlags & RF_LIGHTLIST) == 0) {
- worldLights.update(localLights, parent.worldLights);
- refreshFlags &= ~RF_LIGHTLIST;
- } else {
- assert false;
- }
+ assert (parent.refreshFlags & RF_LIGHTLIST) == 0;
+ worldLights.update(localLights, parent.worldLights);
+ refreshFlags &= ~RF_LIGHTLIST;
+ }
+ }
+
+ protected void updateMatParamOverrides() {
+ refreshFlags &= ~RF_MATPARAM_OVERRIDE;
+
+ worldOverrides.clear();
+ if (parent == null) {
+ worldOverrides.addAll(localOverrides);
+ } else {
+ assert (parent.refreshFlags & RF_MATPARAM_OVERRIDE) == 0;
+ worldOverrides.addAll(parent.worldOverrides);
+ worldOverrides.addAll(localOverrides);
+ }
+ }
+
+ /**
+ * Adds a local material parameter override.
+ *
+ * @param override The override to add.
+ * @see MatParamOverride
+ */
+ public void addMatParamOverride(MatParamOverride override) {
+ if (override == null) {
+ throw new IllegalArgumentException("override cannot be null");
+ }
+ localOverrides.add(override);
+ setMatParamOverrideRefresh();
+ }
+
+ /**
+ * Remove a local material parameter override if it exists.
+ *
+ * @param override The override to remove.
+ * @see MatParamOverride
+ */
+ public void removeMatParamOverride(MatParamOverride override) {
+ if (localOverrides.remove(override)) {
+ setMatParamOverrideRefresh();
}
}
+ /**
+ * Remove all local material parameter overrides.
+ *
+ * @see #addMatParamOverride(com.jme3.material.MatParamOverride)
+ */
+ public void clearMatParamOverrides() {
+ if (!localOverrides.isEmpty()) {
+ setMatParamOverrideRefresh();
+ }
+ localOverrides.clear();
+ }
+
/**
* Should only be called from updateGeometricState().
* In most cases should not be subclassed.
@@ -696,7 +768,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
controls.add(control);
control.setSpatial(this);
boolean after = requiresUpdates();
-
// If the requirement to be updated has changed
// then we need to let the parent node know so it
// can rebuild its update list.
@@ -720,7 +791,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
}
}
boolean after = requiresUpdates();
-
// If the requirement to be updated has changed
// then we need to let the parent node know so it
// can rebuild its update list.
@@ -746,14 +816,12 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
}
boolean after = requiresUpdates();
-
// If the requirement to be updated has changed
// then we need to let the parent node know so it
// can rebuild its update list.
if( parent != null && before != after ) {
parent.invalidateUpdateList();
}
-
return result;
}
@@ -838,7 +906,10 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
if ((refreshFlags & RF_BOUND) != 0) {
updateWorldBound();
}
-
+ if ((refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
+ updateMatParamOverrides();
+ }
+
assert refreshFlags == 0;
}
@@ -1292,6 +1363,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
// the transforms and stuff get refreshed.
clone.setTransformRefresh();
clone.setLightListRefresh();
+ clone.setMatParamOverrideRefresh();
return clone;
}
@@ -1312,6 +1384,13 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
clone.localLights.setOwner(clone);
clone.worldLights.setOwner(clone);
+ clone.worldOverrides = new ArrayList();
+ clone.localOverrides = new ArrayList();
+
+ for (MatParamOverride override : localOverrides) {
+ clone.localOverrides.add((MatParamOverride) override.clone());
+ }
+
// No need to force cloned to update.
// This node already has the refresh flags
// set below so it will have to update anyway.
@@ -1333,6 +1412,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
clone.setBoundRefresh();
clone.setTransformRefresh();
clone.setLightListRefresh();
+ clone.setMatParamOverrideRefresh();
clone.controls = new SafeArrayList(Control.class);
for (int i = 0; i < controls.size(); i++) {
@@ -1388,6 +1468,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
// the transforms and stuff get refreshed.
clone.setTransformRefresh();
clone.setLightListRefresh();
+ clone.setMatParamOverrideRefresh();
return clone;
}
@@ -1419,6 +1500,8 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
this.localLights = cloner.clone(localLights);
this.worldTransform = cloner.clone(worldTransform);
this.localTransform = cloner.clone(localTransform);
+ this.worldOverrides = cloner.clone(worldOverrides);
+ this.localOverrides = cloner.clone(localOverrides);
this.controls = cloner.clone(controls);
// Cloner doesn't handle maps on its own just yet.
@@ -1515,6 +1598,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
capsule.write(shadowMode, "shadow_mode", ShadowMode.Inherit);
capsule.write(localTransform, "transform", Transform.IDENTITY);
capsule.write(localLights, "lights", null);
+ capsule.writeSavableArrayList(localOverrides, "overrides", null);
// Shallow clone the controls array to convert its type.
capsule.writeSavableArrayList(new ArrayList(controls), "controlsList", null);
@@ -1538,6 +1622,12 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
localLights = (LightList) ic.readSavable("lights", null);
localLights.setOwner(this);
+ localOverrides = ic.readSavableArrayList("overrides", null);
+ if (localOverrides == null) {
+ localOverrides = new ArrayList<>();
+ }
+ worldOverrides = new ArrayList<>();
+
//changed for backward compatibility with j3o files generated before the AnimControl/SkeletonControl split
//the AnimControl creates the SkeletonControl for old files and add it to the spatial.
//The SkeletonControl must be the last in the stack so we add the list of all other control before it.
diff --git a/jme3-core/src/main/java/com/jme3/scene/VertexBuffer.java b/jme3-core/src/main/java/com/jme3/scene/VertexBuffer.java
index c67435b78..70d40a64c 100644
--- a/jme3-core/src/main/java/com/jme3/scene/VertexBuffer.java
+++ b/jme3-core/src/main/java/com/jme3/scene/VertexBuffer.java
@@ -108,8 +108,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
* Do not use.
*/
@Deprecated
- MiscAttrib,
-
+ Reserved0,
/**
* Specifies the index buffer, must contain integer data
* (ubyte, ushort, or uint).
@@ -522,6 +521,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
// throw new UnsupportedOperationException("Data has already been sent. Cannot set usage.");
this.usage = usage;
+ this.setUpdateNeeded();
}
/**
diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/WireBox.java b/jme3-core/src/main/java/com/jme3/scene/debug/WireBox.java
index 5d0577c5a..d4e4e1d58 100644
--- a/jme3-core/src/main/java/com/jme3/scene/debug/WireBox.java
+++ b/jme3-core/src/main/java/com/jme3/scene/debug/WireBox.java
@@ -101,14 +101,6 @@ public class WireBox extends Mesh {
);
updateBound();
}
-
- /**
- * Old method retained for compatibility: use makeGeometry instead.
- */
- @Deprecated
- public void fromBoundingBox(BoundingBox bbox) {
- updatePositions(bbox.getXExtent(), bbox.getYExtent(), bbox.getZExtent());
- }
/**
* Create a geometry suitable for visualizing the specified bounding box.
diff --git a/jme3-core/src/main/java/com/jme3/shader/DefineList.java b/jme3-core/src/main/java/com/jme3/shader/DefineList.java
index dd605fc7e..d9b5782aa 100644
--- a/jme3-core/src/main/java/com/jme3/shader/DefineList.java
+++ b/jme3-core/src/main/java/com/jme3/shader/DefineList.java
@@ -1,286 +1,179 @@
-/*
- * Copyright (c) 2009-2012 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.shader;
-
-import com.jme3.export.*;
-import com.jme3.material.MatParam;
-import com.jme3.material.TechniqueDef;
-import com.jme3.util.ListMap;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.TreeMap;
-
-public final class DefineList implements Savable, Cloneable {
-
- private static final String ONE = "1";
-
- private TreeMap defines = new TreeMap();
- private String compiled = null;
- private int cachedHashCode = 0;
-
- public void write(JmeExporter ex) throws IOException{
- OutputCapsule oc = ex.getCapsule(this);
-
- String[] keys = new String[defines.size()];
- String[] vals = new String[defines.size()];
-
- int i = 0;
- for (Map.Entry define : defines.entrySet()){
- keys[i] = define.getKey();
- vals[i] = define.getValue();
- i++;
- }
-
- oc.write(keys, "keys", null);
- oc.write(vals, "vals", null);
- }
-
- public void read(JmeImporter im) throws IOException{
- InputCapsule ic = im.getCapsule(this);
-
- String[] keys = ic.readStringArray("keys", null);
- String[] vals = ic.readStringArray("vals", null);
- for (int i = 0; i < keys.length; i++){
- defines.put(keys[i], vals[i]);
- }
- }
-
- public void clear() {
- defines.clear();
- compiled = "";
- cachedHashCode = 0;
- }
-
- public String get(String key){
- return defines.get(key);
- }
-
- @Override
- public DefineList clone() {
- try {
- DefineList clone = (DefineList) super.clone();
- clone.cachedHashCode = 0;
- clone.compiled = null;
- clone.defines = (TreeMap) defines.clone();
- return clone;
- } catch (CloneNotSupportedException ex) {
- throw new AssertionError();
- }
- }
-
- public boolean set(String key, VarType type, Object val){
- if (val == null){
- defines.remove(key);
- compiled = null;
- cachedHashCode = 0;
- return true;
- }
-
- switch (type){
- case Boolean:
- if (((Boolean) val).booleanValue()) {
- // same literal, != will work
- if (defines.put(key, ONE) != ONE) {
- compiled = null;
- cachedHashCode = 0;
- return true;
- }
- } else if (defines.containsKey(key)) {
- defines.remove(key);
- compiled = null;
- cachedHashCode = 0;
- return true;
- }
-
- break;
- case Float:
- case Int:
- String newValue = val.toString();
- String original = defines.put(key, newValue);
- if (!val.equals(original)) {
- compiled = null;
- cachedHashCode = 0;
- return true;
- }
- break;
- default:
- // same literal, != will work
- if (defines.put(key, ONE) != ONE) {
- compiled = null;
- cachedHashCode = 0;
- return true;
- }
- break;
- }
-
- return false;
- }
-
- public boolean remove(String key){
- if (defines.remove(key) != null) {
- compiled = null;
- cachedHashCode = 0;
- return true;
- }
- return false;
- }
-
- public void addFrom(DefineList other){
- if (other == null) {
- return;
- }
- compiled = null;
- cachedHashCode = 0;
- defines.putAll(other.defines);
- }
-
- public String getCompiled(){
- if (compiled == null){
- StringBuilder sb = new StringBuilder();
- for (Map.Entry entry : defines.entrySet()){
- sb.append("#define ").append(entry.getKey()).append(" ");
- sb.append(entry.getValue()).append('\n');
- }
- compiled = sb.toString();
- }
- return compiled;
- }
-
- @Override
- public boolean equals(Object obj) {
- final DefineList other = (DefineList) obj;
- return defines.equals(other.defines);
- }
-
- /**
- * Update defines if the define list changed based on material parameters.
- * @param params
- * @param def
- * @return true if defines was updated
- */
- public boolean update(ListMap params, TechniqueDef def){
- if(equalsParams(params, def)){
- return false;
- }
- // Defines were changed, update define list
- clear();
- for(int i=0;i entry : defines.entrySet()) {
- sb.append(entry.getKey()).append("=").append(entry.getValue());
- if (i != defines.size() - 1) {
- sb.append(", ");
- }
- i++;
- }
- return sb.toString();
- }
-
-}
+/*
+ * Copyright (c) 2009-2015 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.shader;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * The new define list.
+ *
+ * @author Kirill Vainer
+ */
+public final class DefineList {
+
+ public static final int MAX_DEFINES = 64;
+
+ private long hash;
+ private final int[] vals;
+
+ public DefineList(int numValues) {
+ if (numValues < 0 || numValues > MAX_DEFINES) {
+ throw new IllegalArgumentException("numValues must be between 0 and 64");
+ }
+ vals = new int[numValues];
+ }
+
+ private DefineList(DefineList original) {
+ this.hash = original.hash;
+ this.vals = new int[original.vals.length];
+ System.arraycopy(original.vals, 0, vals, 0, vals.length);
+ }
+
+ public void set(int id, int val) {
+ assert 0 <= id && id < 64;
+ if (val != 0) {
+ hash |= (1L << id);
+ } else {
+ hash &= ~(1L << id);
+ }
+ vals[id] = val;
+ }
+
+ public void set(int id, float val) {
+ set(id, Float.floatToIntBits(val));
+ }
+
+ public void set(int id, boolean val) {
+ set(id, val ? 1 : 0);
+ }
+
+ public void set(int id, VarType type, Object value) {
+ if (value == null) {
+ set(id, 0);
+ return;
+ }
+
+ switch (type) {
+ case Int:
+ set(id, (Integer) value);
+ break;
+ case Float:
+ set(id, (Float) value);
+ break;
+ case Boolean:
+ set(id, ((Boolean) value));
+ break;
+ default:
+ set(id, 1);
+ break;
+ }
+ }
+
+ public void setAll(DefineList other) {
+ for (int i = 0; i < other.vals.length; i++) {
+ if (other.vals[i] != 0) {
+ vals[i] = other.vals[i];
+ }
+ }
+ }
+
+ public void clear() {
+ hash = 0;
+ Arrays.fill(vals, 0);
+ }
+
+ public boolean getBoolean(int id) {
+ return vals[id] != 0;
+ }
+
+ public float getFloat(int id) {
+ return Float.intBitsToFloat(vals[id]);
+ }
+
+ public int getInt(int id) {
+ return vals[id];
+ }
+
+ @Override
+ public int hashCode() {
+ return (int)((hash >> 32) ^ hash);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ DefineList o = (DefineList) other;
+ if (hash == o.hash) {
+ for (int i = 0; i < vals.length; i++) {
+ if (vals[i] != o.vals[i]) return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public DefineList deepClone() {
+ return new DefineList(this);
+ }
+
+ public void generateSource(StringBuilder sb, List defineNames, List defineTypes) {
+ for (int i = 0; i < vals.length; i++) {
+ if (vals[i] != 0) {
+ String defineName = defineNames.get(i);
+
+ sb.append("#define ");
+ sb.append(defineName);
+ sb.append(" ");
+
+ if (defineTypes != null && defineTypes.get(i) == VarType.Float) {
+ float val = Float.intBitsToFloat(vals[i]);
+ if (Float.isInfinite(val) || Float.isNaN(val)) {
+ throw new IllegalArgumentException(
+ "GLSL does not support NaN "
+ + "or Infinite float literals");
+ }
+ sb.append(val);
+ } else {
+ sb.append(vals[i]);
+ }
+
+ sb.append("\n");
+ }
+ }
+ }
+
+ public String generateSource(List defineNames, List defineTypes) {
+ StringBuilder sb = new StringBuilder();
+ generateSource(sb, defineNames, defineTypes);
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/jme3-core/src/main/java/com/jme3/shader/Shader.java b/jme3-core/src/main/java/com/jme3/shader/Shader.java
index eb084f178..d6fc495f2 100644
--- a/jme3-core/src/main/java/com/jme3/shader/Shader.java
+++ b/jme3-core/src/main/java/com/jme3/shader/Shader.java
@@ -45,44 +45,63 @@ public final class Shader extends NativeObject {
/**
* A list of all shader sources currently attached.
*/
- private ArrayList shaderSourceList;
+ private final ArrayList shaderSourceList;
/**
* Maps uniform name to the uniform variable.
*/
- private ListMap uniforms;
+ private final ListMap uniforms;
+
+ /**
+ * Uniforms bound to {@link UniformBinding}s.
+ *
+ * Managed by the {@link UniformBindingManager}.
+ */
+ private final ArrayList boundUniforms;
/**
* Maps attribute name to the location of the attribute in the shader.
*/
- private IntMap attribs;
+ private final IntMap attribs;
/**
* Type of shader. The shader will control the pipeline of it's type.
*/
public static enum ShaderType {
+
/**
* Control fragment rasterization. (e.g color of pixel).
*/
- Fragment,
-
+ Fragment("frag"),
/**
* Control vertex processing. (e.g transform of model to clip space)
*/
- Vertex,
-
+ Vertex("vert"),
/**
- * Control geometry assembly. (e.g compile a triangle list from input data)
+ * Control geometry assembly. (e.g compile a triangle list from input
+ * data)
*/
- Geometry,
+ Geometry("geom"),
/**
- * Controls tesselation factor (e.g how often a input patch should be subdivided)
+ * Controls tesselation factor (e.g how often a input patch should be
+ * subdivided)
*/
- TessellationControl,
+ TessellationControl("tsctrl"),
/**
- * Controls tesselation transform (e.g similar to the vertex shader, but required to mix inputs manual)
+ * Controls tesselation transform (e.g similar to the vertex shader, but
+ * required to mix inputs manual)
*/
- TessellationEvaluation;
+ TessellationEvaluation("tseval");
+
+ private String extension;
+
+ public String getExtension() {
+ return extension;
+ }
+
+ private ShaderType(String extension) {
+ this.extension = extension;
+ }
}
/**
@@ -195,22 +214,16 @@ public final class Shader extends NativeObject {
}
}
- /**
- * Initializes the shader for use, must be called after the
- * constructor without arguments is used.
- */
- public void initialize() {
- shaderSourceList = new ArrayList();
- uniforms = new ListMap();
- attribs = new IntMap();
- }
-
/**
* Creates a new shader, {@link #initialize() } must be called
* after this constructor for the shader to be usable.
*/
public Shader(){
super();
+ shaderSourceList = new ArrayList();
+ uniforms = new ListMap();
+ attribs = new IntMap();
+ boundUniforms = new ArrayList();
}
/**
@@ -225,6 +238,10 @@ public final class Shader extends NativeObject {
for (ShaderSource source : s.shaderSourceList){
shaderSourceList.add( (ShaderSource)source.createDestructableClone() );
}
+
+ uniforms = null;
+ boundUniforms = null;
+ attribs = null;
}
/**
@@ -248,6 +265,18 @@ public final class Shader extends NativeObject {
setUpdateNeeded();
}
+ public void addUniformBinding(UniformBinding binding){
+ String uniformName = "g_" + binding.name();
+ Uniform uniform = uniforms.get(uniformName);
+ if (uniform == null) {
+ uniform = new Uniform();
+ uniform.name = uniformName;
+ uniform.binding = binding;
+ uniforms.put(uniformName, uniform);
+ boundUniforms.add(uniform);
+ }
+ }
+
public Uniform getUniform(String name){
assert name.startsWith("m_") || name.startsWith("g_");
Uniform uniform = uniforms.get(name);
@@ -277,6 +306,10 @@ public final class Shader extends NativeObject {
public ListMap getUniformMap(){
return uniforms;
}
+
+ public ArrayList getBoundUniforms() {
+ return boundUniforms;
+ }
public Collection getSources(){
return shaderSourceList;
diff --git a/jme3-core/src/main/java/com/jme3/shader/ShaderGenerator.java b/jme3-core/src/main/java/com/jme3/shader/ShaderGenerator.java
index f5aeca2ed..d42dccf17 100644
--- a/jme3-core/src/main/java/com/jme3/shader/ShaderGenerator.java
+++ b/jme3-core/src/main/java/com/jme3/shader/ShaderGenerator.java
@@ -57,9 +57,9 @@ public abstract class ShaderGenerator {
*/
protected int indent;
/**
- * the technique to use for the shader generation
+ * the technique def to use for the shader generation
*/
- protected Technique technique = null;
+ protected TechniqueDef techniqueDef = null;
/**
* Build a shaderGenerator
@@ -70,8 +70,8 @@ public abstract class ShaderGenerator {
this.assetManager = assetManager;
}
- public void initialize(Technique technique){
- this.technique = technique;
+ public void initialize(TechniqueDef techniqueDef){
+ this.techniqueDef = techniqueDef;
}
/**
@@ -79,24 +79,29 @@ public abstract class ShaderGenerator {
*
* @return a Shader program
*/
- public Shader generateShader() {
- if(technique == null){
- throw new UnsupportedOperationException("The shaderGenerator was not properly initialized, call initialize(Technique) before any generation");
+ public Shader generateShader(String definesSourceCode) {
+ if (techniqueDef == null) {
+ throw new UnsupportedOperationException("The shaderGenerator was not "
+ + "properly initialized, call "
+ + "initialize(TechniqueDef) before any generation");
}
- DefineList defines = technique.getAllDefines();
- TechniqueDef def = technique.getDef();
- ShaderGenerationInfo info = def.getShaderGenerationInfo();
-
- String vertexSource = buildShader(def.getShaderNodes(), info, ShaderType.Vertex);
- String fragmentSource = buildShader(def.getShaderNodes(), info, ShaderType.Fragment);
+ String techniqueName = techniqueDef.getName();
+ ShaderGenerationInfo info = techniqueDef.getShaderGenerationInfo();
Shader shader = new Shader();
- shader.initialize();
- shader.addSource(Shader.ShaderType.Vertex, technique.getDef().getName() + ".vert", vertexSource, defines.getCompiled(), getLanguageAndVersion(ShaderType.Vertex));
- shader.addSource(Shader.ShaderType.Fragment, technique.getDef().getName() + ".frag", fragmentSource, defines.getCompiled(), getLanguageAndVersion(ShaderType.Fragment));
+ for (ShaderType type : ShaderType.values()) {
+ String extension = type.getExtension();
+ String language = getLanguageAndVersion(type);
+ String shaderSourceCode = buildShader(techniqueDef.getShaderNodes(), info, type);
+
+ if (shaderSourceCode != null) {
+ String shaderSourceAssetName = techniqueName + "." + extension;
+ shader.addSource(type, shaderSourceAssetName, shaderSourceCode, definesSourceCode, language);
+ }
+ }
- technique = null;
+ techniqueDef = null;
return shader;
}
@@ -109,6 +114,14 @@ public abstract class ShaderGenerator {
* @return the code of the generated vertex shader
*/
protected String buildShader(List shaderNodes, ShaderGenerationInfo info, ShaderType type) {
+ if (type == ShaderType.TessellationControl ||
+ type == ShaderType.TessellationEvaluation ||
+ type == ShaderType.Geometry) {
+ // TODO: Those are not supported.
+ // Too much code assumes that type is either Vertex or Fragment
+ return null;
+ }
+
indent = 0;
StringBuilder sourceDeclaration = new StringBuilder();
diff --git a/jme3-core/src/main/java/com/jme3/shader/ShaderKey.java b/jme3-core/src/main/java/com/jme3/shader/ShaderKey.java
deleted file mode 100644
index 23a187250..000000000
--- a/jme3-core/src/main/java/com/jme3/shader/ShaderKey.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (c) 2009-2012 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.shader;
-
-import com.jme3.asset.AssetKey;
-import com.jme3.export.InputCapsule;
-import com.jme3.export.JmeExporter;
-import com.jme3.export.JmeImporter;
-import com.jme3.export.OutputCapsule;
-import java.io.IOException;
-import java.util.EnumMap;
-import java.util.Set;
-
-public class ShaderKey extends AssetKey {
-
- protected EnumMap shaderLanguage;
- protected EnumMap shaderName;
- protected DefineList defines;
- protected int cachedHashedCode = 0;
- protected boolean usesShaderNodes = false;
-
- public ShaderKey(){
- shaderLanguage=new EnumMap(Shader.ShaderType.class);
- shaderName=new EnumMap(Shader.ShaderType.class);
- }
-
- public ShaderKey(DefineList defines, EnumMap shaderLanguage,EnumMap shaderName){
- super("");
- this.name = reducePath(getShaderName(Shader.ShaderType.Vertex));
- this.shaderLanguage=new EnumMap(Shader.ShaderType.class);
- this.shaderName=new EnumMap(Shader.ShaderType.class);
- this.defines = defines;
- for (Shader.ShaderType shaderType : shaderName.keySet()) {
- this.shaderName.put(shaderType,shaderName.get(shaderType));
- this.shaderLanguage.put(shaderType,shaderLanguage.get(shaderType));
- }
- }
-
- @Override
- public ShaderKey clone() {
- ShaderKey clone = (ShaderKey) super.clone();
- clone.cachedHashedCode = 0;
- clone.defines = defines.clone();
- return clone;
- }
-
- @Override
- public String toString(){
- //todo:
- return "V="+name+";";
- }
-
- private final String getShaderName(Shader.ShaderType type) {
- if (shaderName == null) {
- return "";
- }
- String shName = shaderName.get(type);
- return shName != null ? shName : "";
- }
-
- //todo: make equals and hashCode work
- @Override
- public boolean equals(Object obj) {
- final ShaderKey other = (ShaderKey) obj;
- if (name.equals(other.name) && getShaderName(Shader.ShaderType.Fragment).equals(other.getShaderName(Shader.ShaderType.Fragment))){
- if (defines != null && other.defines != null) {
- return defines.equals(other.defines);
- } else if (defines != null || other.defines != null) {
- return false;
- } else {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- if (cachedHashedCode == 0) {
- int hash = 7;
- hash = 41 * hash + name.hashCode();
- hash = 41 * hash + getShaderName(Shader.ShaderType.Fragment).hashCode();
- hash = getShaderName(Shader.ShaderType.Geometry) == null ? hash : 41 * hash + getShaderName(Shader.ShaderType.Geometry).hashCode();
- hash = getShaderName(Shader.ShaderType.TessellationControl) == null ? hash : 41 * hash + getShaderName(Shader.ShaderType.TessellationControl).hashCode();
- hash = getShaderName(Shader.ShaderType.TessellationEvaluation) == null ? hash : 41 * hash + getShaderName(Shader.ShaderType.TessellationEvaluation).hashCode();
- hash = 41 * hash + (defines != null ? defines.hashCode() : 0);
- cachedHashedCode = hash;
- }
- return cachedHashedCode;
- }
-
- public DefineList getDefines() {
- return defines;
- }
-
- public String getVertName(){
- return getShaderName(Shader.ShaderType.Vertex);
- }
-
- public String getFragName() {
- return getShaderName(Shader.ShaderType.Fragment);
- }
-
- /**
- * @deprecated Use {@link #getVertexShaderLanguage() } instead.
- */
- @Deprecated
- public String getLanguage() {
- return shaderLanguage.get(Shader.ShaderType.Vertex);
- }
-
- public String getVertexShaderLanguage() {
- return shaderLanguage.get(Shader.ShaderType.Vertex);
- }
-
- public String getFragmentShaderLanguage() {
- return shaderLanguage.get(Shader.ShaderType.Vertex);
- }
-
- public boolean isUsesShaderNodes() {
- return usesShaderNodes;
- }
-
- public void setUsesShaderNodes(boolean usesShaderNodes) {
- this.usesShaderNodes = usesShaderNodes;
- }
-
- public Set getUsedShaderPrograms(){
- return shaderName.keySet();
- }
-
- public String getShaderProgramLanguage(Shader.ShaderType shaderType){
- return shaderLanguage.get(shaderType);
- }
-
- public String getShaderProgramName(Shader.ShaderType shaderType){
- return getShaderName(shaderType);
- }
-
- @Override
- public void write(JmeExporter ex) throws IOException{
- super.write(ex);
- OutputCapsule oc = ex.getCapsule(this);
- oc.write(shaderName.get(Shader.ShaderType.Fragment), "fragment_name", null);
- oc.write(shaderName.get(Shader.ShaderType.Geometry), "geometry_name", null);
- oc.write(shaderName.get(Shader.ShaderType.TessellationControl), "tessControl_name", null);
- oc.write(shaderName.get(Shader.ShaderType.TessellationEvaluation), "tessEval_name", null);
- oc.write(shaderLanguage.get(Shader.ShaderType.Vertex), "language", null);
- oc.write(shaderLanguage.get(Shader.ShaderType.Fragment), "frag_language", null);
- oc.write(shaderLanguage.get(Shader.ShaderType.Geometry), "geom_language", null);
- oc.write(shaderLanguage.get(Shader.ShaderType.TessellationControl), "tsctrl_language", null);
- oc.write(shaderLanguage.get(Shader.ShaderType.TessellationEvaluation), "tseval_language", null);
-
- }
-
- @Override
- public void read(JmeImporter im) throws IOException{
- super.read(im);
- InputCapsule ic = im.getCapsule(this);
- shaderName.put(Shader.ShaderType.Vertex,name);
- shaderName.put(Shader.ShaderType.Fragment,ic.readString("fragment_name", null));
- shaderName.put(Shader.ShaderType.Geometry,ic.readString("geometry_name", null));
- shaderName.put(Shader.ShaderType.TessellationControl,ic.readString("tessControl_name", null));
- shaderName.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tessEval_name", null));
- shaderLanguage.put(Shader.ShaderType.Vertex,ic.readString("language", null));
- shaderLanguage.put(Shader.ShaderType.Fragment,ic.readString("frag_language", null));
- shaderLanguage.put(Shader.ShaderType.Geometry,ic.readString("geom_language", null));
- shaderLanguage.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrl_language", null));
- shaderLanguage.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tseval_language", null));
- }
-
-}
diff --git a/jme3-core/src/main/java/com/jme3/shader/Uniform.java b/jme3-core/src/main/java/com/jme3/shader/Uniform.java
index 5d5fd2fe3..7ed468528 100644
--- a/jme3-core/src/main/java/com/jme3/shader/Uniform.java
+++ b/jme3-core/src/main/java/com/jme3/shader/Uniform.java
@@ -70,6 +70,30 @@ public class Uniform extends ShaderVariable {
*/
protected boolean setByCurrentMaterial = false;
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 31 * hash + (this.value != null ? this.value.hashCode() : 0);
+ hash = 31 * hash + (this.varType != null ? this.varType.hashCode() : 0);
+ hash = 31 * hash + (this.binding != null ? this.binding.hashCode() : 0);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ final Uniform other = (Uniform) obj;
+ if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) {
+ return false;
+ }
+ return this.binding == other.binding && this.varType == other.varType;
+ }
+
@Override
public String toString(){
StringBuilder sb = new StringBuilder();
@@ -102,6 +126,10 @@ public class Uniform extends ShaderVariable {
public Object getValue(){
return value;
}
+
+ public FloatBuffer getMultiData() {
+ return multiData;
+ }
public boolean isSetByCurrentMaterial() {
return setByCurrentMaterial;
@@ -111,21 +139,6 @@ public class Uniform extends ShaderVariable {
setByCurrentMaterial = false;
}
- private static void setVector4(Vector4f vec, Object value) {
- if (value instanceof ColorRGBA) {
- ColorRGBA color = (ColorRGBA) value;
- vec.set(color.r, color.g, color.b, color.a);
- } else if (value instanceof Quaternion) {
- Quaternion quat = (Quaternion) value;
- vec.set(quat.getX(), quat.getY(), quat.getZ(), quat.getW());
- } else if (value instanceof Vector4f) {
- Vector4f vec4 = (Vector4f) value;
- vec.set(vec4);
- } else{
- throw new IllegalArgumentException();
- }
- }
-
public void clearValue(){
updateNeeded = true;
@@ -182,27 +195,43 @@ public class Uniform extends ShaderVariable {
}
if (value == null) {
- throw new NullPointerException();
+ throw new IllegalArgumentException("for uniform " + name + ": value cannot be null");
}
setByCurrentMaterial = true;
switch (type){
case Matrix3:
+ if (value.equals(this.value)) {
+ return;
+ }
Matrix3f m3 = (Matrix3f) value;
if (multiData == null) {
multiData = BufferUtils.createFloatBuffer(9);
}
m3.fillFloatBuffer(multiData, true);
multiData.clear();
+ if (this.value == null) {
+ this.value = new Matrix3f(m3);
+ } else {
+ ((Matrix3f)this.value).set(m3);
+ }
break;
case Matrix4:
+ if (value.equals(this.value)) {
+ return;
+ }
Matrix4f m4 = (Matrix4f) value;
if (multiData == null) {
multiData = BufferUtils.createFloatBuffer(16);
}
m4.fillFloatBuffer(multiData, true);
multiData.clear();
+ if (this.value == null) {
+ this.value = new Matrix4f(m4);
+ } else {
+ ((Matrix4f)this.value).copy(m4);
+ }
break;
case IntArray:
int[] ia = (int[]) value;
@@ -283,11 +312,32 @@ public class Uniform extends ShaderVariable {
}
multiData.clear();
break;
+ case Vector4:
+ if (value.equals(this.value)) {
+ return;
+ }
+ if (value instanceof ColorRGBA) {
+ if (this.value == null) {
+ this.value = new ColorRGBA();
+ }
+ ((ColorRGBA) this.value).set((ColorRGBA) value);
+ } else if (value instanceof Vector4f) {
+ if (this.value == null) {
+ this.value = new Vector4f();
+ }
+ ((Vector4f) this.value).set((Vector4f) value);
+ } else {
+ if (this.value == null) {
+ this.value = new Quaternion();
+ }
+ ((Quaternion) this.value).set((Quaternion) value);
+ }
+ break;
// Only use check if equals optimization for primitive values
case Int:
case Float:
case Boolean:
- if (this.value != null && this.value.equals(value)) {
+ if (value.equals(this.value)) {
return;
}
this.value = value;
@@ -297,39 +347,38 @@ public class Uniform extends ShaderVariable {
break;
}
- if (multiData != null) {
- this.value = multiData;
- }
+// if (multiData != null) {
+// this.value = multiData;
+// }
varType = type;
updateNeeded = true;
}
public void setVector4Length(int length){
- if (location == -1)
+ if (location == -1) {
return;
-
- FloatBuffer fb = (FloatBuffer) value;
- if (fb == null || fb.capacity() < length * 4) {
- value = BufferUtils.createFloatBuffer(length * 4);
}
-
+
+ multiData = BufferUtils.ensureLargeEnough(multiData, length * 4);
+ value = multiData;
varType = VarType.Vector4Array;
updateNeeded = true;
setByCurrentMaterial = true;
}
public void setVector4InArray(float x, float y, float z, float w, int index){
- if (location == -1)
+ if (location == -1) {
return;
+ }
- if (varType != null && varType != VarType.Vector4Array)
- throw new IllegalArgumentException("Expected a "+varType.name()+" value!");
+ if (varType != null && varType != VarType.Vector4Array) {
+ throw new IllegalArgumentException("Expected a " + varType.name() + " value!");
+ }
- FloatBuffer fb = (FloatBuffer) value;
- fb.position(index * 4);
- fb.put(x).put(y).put(z).put(w);
- fb.rewind();
+ multiData.position(index * 4);
+ multiData.put(x).put(y).put(z).put(w);
+ multiData.rewind();
updateNeeded = true;
setByCurrentMaterial = true;
}
diff --git a/jme3-core/src/main/java/com/jme3/shader/UniformBindingManager.java b/jme3-core/src/main/java/com/jme3/shader/UniformBindingManager.java
index af2df5a94..f9ead8979 100644
--- a/jme3-core/src/main/java/com/jme3/shader/UniformBindingManager.java
+++ b/jme3-core/src/main/java/com/jme3/shader/UniformBindingManager.java
@@ -36,7 +36,7 @@ import com.jme3.math.*;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.system.Timer;
-import java.util.List;
+import java.util.ArrayList;
/**
* UniformBindingManager
helps {@link RenderManager} to manage
@@ -84,7 +84,8 @@ public class UniformBindingManager {
* Updates the given list of uniforms with {@link UniformBinding uniform bindings}
* based on the current world state.
*/
- public void updateUniformBindings(List params) {
+ public void updateUniformBindings(Shader shader) {
+ ArrayList params = shader.getBoundUniforms();
for (int i = 0; i < params.size(); i++) {
Uniform u = params.get(i);
switch (u.getBinding()) {
diff --git a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java
index b55c6b2d2..d1b4586b3 100644
--- a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java
@@ -330,12 +330,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
public void initialize(RenderManager rm, ViewPort vp) {
renderManager = rm;
viewPort = vp;
- //checking for caps to chosse the appropriate post material technique
- if (renderManager.getRenderer().getCaps().contains(Caps.GLSL150)) {
- postTechniqueName = "PostShadow15";
- } else {
- postTechniqueName = "PostShadow";
- }
+ postTechniqueName = "PostShadow";
if(zFarOverride>0 && frustumCam == null){
initFrustumCam();
}
@@ -587,7 +582,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
for (int i = 0; i < l.size(); i++) {
Material mat = l.get(i).getMaterial();
//checking if the material has the post technique and adding it to the material cache
- if (mat.getMaterialDef().getTechniqueDef(postTechniqueName) != null) {
+ if (mat.getMaterialDef().getTechniqueDefs(postTechniqueName) != null) {
if (!matCache.contains(mat)) {
matCache.add(mat);
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java
index e06b5c337..a4f06df41 100644
--- a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java
@@ -355,12 +355,7 @@ public class PssmShadowRenderer implements SceneProcessor {
public void initialize(RenderManager rm, ViewPort vp) {
renderManager = rm;
viewPort = vp;
- //checking for caps to chosse the appropriate post material technique
- if (renderManager.getRenderer().getCaps().contains(Caps.GLSL150)) {
- postTechniqueName = "PostShadow15";
- } else {
- postTechniqueName = "PostShadow";
- }
+ postTechniqueName = "PostShadow";
}
public boolean isInitialized() {
@@ -533,7 +528,7 @@ public class PssmShadowRenderer implements SceneProcessor {
for (int i = 0; i < l.size(); i++) {
Material mat = l.get(i).getMaterial();
//checking if the material has the post technique and adding it to the material cache
- if (mat.getMaterialDef().getTechniqueDef(postTechniqueName) != null) {
+ if (mat.getMaterialDef().getTechniqueDefs(postTechniqueName) != null) {
if (!matCache.contains(mat)) {
matCache.add(mat);
}
diff --git a/jme3-core/src/main/java/com/jme3/system/NullContext.java b/jme3-core/src/main/java/com/jme3/system/NullContext.java
index 41204e6c9..54ee59c42 100644
--- a/jme3-core/src/main/java/com/jme3/system/NullContext.java
+++ b/jme3-core/src/main/java/com/jme3/system/NullContext.java
@@ -128,12 +128,13 @@ public class NullContext implements JmeContext, Runnable {
public void run(){
initInThread();
- while (!needClose.get()){
+ do {
listener.update();
- if (frameRate > 0)
+ if (frameRate > 0) {
sync(frameRate);
- }
+ }
+ } while (!needClose.get());
deinitInThread();
diff --git a/jme3-core/src/main/java/com/jme3/system/NullRenderer.java b/jme3-core/src/main/java/com/jme3/system/NullRenderer.java
index f2e029af4..293c5e2c7 100644
--- a/jme3-core/src/main/java/com/jme3/system/NullRenderer.java
+++ b/jme3-core/src/main/java/com/jme3/system/NullRenderer.java
@@ -39,6 +39,7 @@ import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Matrix4f;
import com.jme3.renderer.Caps;
+import com.jme3.renderer.Limits;
import com.jme3.renderer.Renderer;
import com.jme3.renderer.Statistics;
import com.jme3.scene.Mesh;
@@ -48,15 +49,25 @@ import com.jme3.shader.Shader.ShaderSource;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
+import java.util.EnumMap;
public class NullRenderer implements Renderer {
- private static final EnumSet caps = EnumSet.noneOf(Caps.class);
- private static final Statistics stats = new Statistics();
+ private final EnumSet caps = EnumSet.allOf(Caps.class);
+ private final EnumMap limits = new EnumMap<>(Limits.class);
+ private final Statistics stats = new Statistics();
public void initialize() {
+ for (Limits limit : Limits.values()) {
+ limits.put(limit, Integer.MAX_VALUE);
+ }
}
-
+
+ @Override
+ public EnumMap getLimits() {
+ return limits;
+ }
+
public EnumSet getCaps() {
return caps;
}
@@ -164,4 +175,7 @@ public class NullRenderer implements Renderer {
public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) {
}
+ @Override
+ public void setDefaultAnisotropicFilter(int level) {
+ }
}
diff --git a/jme3-core/src/main/java/com/jme3/texture/image/LastTextureState.java b/jme3-core/src/main/java/com/jme3/texture/image/LastTextureState.java
index 32c1b718b..4df767b0b 100644
--- a/jme3-core/src/main/java/com/jme3/texture/image/LastTextureState.java
+++ b/jme3-core/src/main/java/com/jme3/texture/image/LastTextureState.java
@@ -58,7 +58,7 @@ public final class LastTextureState {
rWrap = null;
magFilter = null;
minFilter = null;
- anisoFilter = 0;
+ anisoFilter = 1;
// The default in OpenGL is OFF, so we avoid setting this per texture
// if its not used.
diff --git a/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java b/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java
index 4b812006f..3cc2b5576 100644
--- a/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java
+++ b/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java
@@ -207,10 +207,10 @@ public class Cloner {
// Check the index to see if we already have it
Object clone = index.get(object);
- if( clone != null ) {
+ if( clone != null || index.containsKey(object) ) {
if( log.isLoggable(Level.FINER) ) {
log.finer("cloned:" + object.getClass() + "@" + System.identityHashCode(object)
- + " as cached:" + clone.getClass() + "@" + System.identityHashCode(clone));
+ + " as cached:" + (clone == null ? "null" : (clone.getClass() + "@" + System.identityHashCode(clone))));
}
return type.cast(clone);
}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
index a0f31aeb0..4d5c36046 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
@@ -114,10 +114,10 @@ MaterialDef Phong Lighting {
//For instancing
Boolean UseInstancing
- Boolean BackfaceShadows: false
+ Boolean BackfaceShadows : false
}
- Technique {
+ Technique {
LightMode SinglePass
VertexShader GLSL100: Common/MatDefs/Light/SPLighting.vert
@@ -149,7 +149,7 @@ MaterialDef Phong Lighting {
SEPARATE_TEXCOORD : SeparateTexCoord
DISCARD_ALPHA : AlphaDiscardThreshold
USE_REFLECTION : EnvMap
- SPHERE_MAP : SphereMap
+ SPHERE_MAP : EnvMapAsSphereMap
NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
}
@@ -188,7 +188,7 @@ MaterialDef Phong Lighting {
SEPARATE_TEXCOORD : SeparateTexCoord
DISCARD_ALPHA : AlphaDiscardThreshold
USE_REFLECTION : EnvMap
- SPHERE_MAP : SphereMap
+ SPHERE_MAP : EnvMapAsSphereMap
NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
}
@@ -209,7 +209,6 @@ MaterialDef Phong Lighting {
}
Defines {
- COLOR_MAP : ColorMap
DISCARD_ALPHA : AlphaDiscardThreshold
NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
@@ -218,7 +217,7 @@ MaterialDef Phong Lighting {
}
- Technique PostShadow15{
+ Technique PostShadow {
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow.vert
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow.frag
@@ -234,8 +233,7 @@ MaterialDef Phong Lighting {
HARDWARE_SHADOWS : HardwareShadows
FILTER_MODE : FilterMode
PCFEDGE : PCFEdge
- DISCARD_ALPHA : AlphaDiscardThreshold
- COLOR_MAP : ColorMap
+ DISCARD_ALPHA : AlphaDiscardThreshold
SHADOWMAP_SIZE : ShadowMapSize
FADE : FadeInfo
PSSM : Splits
@@ -268,8 +266,7 @@ MaterialDef Phong Lighting {
HARDWARE_SHADOWS : HardwareShadows
FILTER_MODE : FilterMode
PCFEDGE : PCFEdge
- DISCARD_ALPHA : AlphaDiscardThreshold
- COLOR_MAP : ColorMap
+ DISCARD_ALPHA : AlphaDiscardThreshold
SHADOWMAP_SIZE : ShadowMapSize
FADE : FadeInfo
PSSM : Splits
@@ -343,10 +340,6 @@ MaterialDef Phong Lighting {
Defines {
VERTEX_COLOR : UseVertexColor
MATERIAL_COLORS : UseMaterialColors
- V_TANGENT : VTangent
- MINNAERT : Minnaert
- WARDISO : WardIso
-
DIFFUSEMAP : DiffuseMap
NORMALMAP : NormalMap
SPECULARMAP : SpecularMap
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md b/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
index 68f07f98d..f02348a06 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
@@ -148,7 +148,7 @@ MaterialDef Unshaded {
}
- Technique PostShadow15{
+ Technique PostShadow {
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow.vert
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow.frag
@@ -181,7 +181,7 @@ MaterialDef Unshaded {
}
}
- Technique PostShadow{
+ Technique PostShadow {
VertexShader GLSL100: Common/MatDefs/Shadow/PostShadow.vert
FragmentShader GLSL100: Common/MatDefs/Shadow/PostShadow.frag
diff --git a/jme3-core/src/main/resources/com/jme3/asset/General.cfg b/jme3-core/src/main/resources/com/jme3/asset/General.cfg
index c56b62146..66ed68e49 100644
--- a/jme3-core/src/main/resources/com/jme3/asset/General.cfg
+++ b/jme3-core/src/main/resources/com/jme3/asset/General.cfg
@@ -22,5 +22,4 @@ LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material
LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene
LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend
LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, geom, tsctrl, tseval, glsl, glsllib
-LOADER com.jme3.scene.plugins.fbx.SceneLoader : fbx
-LOADER com.jme3.scene.plugins.fbx.SceneWithAnimationLoader : fba
+LOADER com.jme3.scene.plugins.fbx.FbxLoader : fbx
diff --git a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
index 402ce6d47..509642e4c 100644
--- a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
+++ b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
@@ -31,8 +31,12 @@
*/
package com.jme3.material.plugins;
+import com.jme3.material.logic.MultiPassLightingLogic;
+import com.jme3.material.logic.SinglePassLightingLogic;
+import com.jme3.material.logic.DefaultTechniqueDefLogic;
import com.jme3.asset.*;
import com.jme3.material.*;
+import com.jme3.material.RenderState.BlendEquation;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.material.RenderState.FaceCullMode;
import com.jme3.material.TechniqueDef.LightMode;
@@ -40,6 +44,7 @@ import com.jme3.material.TechniqueDef.ShadowMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
+import com.jme3.shader.DefineList;
import com.jme3.shader.Shader;
import com.jme3.shader.VarType;
import com.jme3.texture.Texture;
@@ -73,15 +78,16 @@ public class J3MLoader implements AssetLoader {
private Material material;
private TechniqueDef technique;
private RenderState renderState;
+ private ArrayList presetDefines = new ArrayList();
- private EnumMap shaderLanguage;
- private EnumMap shaderName;
+ private EnumMap shaderLanguages;
+ private EnumMap shaderNames;
private static final String whitespacePattern = "\\p{javaWhitespace}+";
public J3MLoader() {
- shaderLanguage = new EnumMap(Shader.ShaderType.class);
- shaderName = new EnumMap(Shader.ShaderType.class);
+ shaderLanguages = new EnumMap<>(Shader.ShaderType.class);
+ shaderNames = new EnumMap<>(Shader.ShaderType.class);
}
@@ -104,8 +110,8 @@ public class J3MLoader implements AssetLoader {
}
private void readShaderDefinition(Shader.ShaderType shaderType, String name, String language) {
- shaderName.put(shaderType, name);
- shaderLanguage.put(shaderType, language);
+ shaderNames.put(shaderType, name);
+ shaderLanguages.put(shaderType, language);
}
// LightMode
@@ -443,9 +449,12 @@ public class J3MLoader implements AssetLoader {
renderState.setDepthTest(parseBoolean(split[1]));
}else if (split[0].equals("Blend")){
renderState.setBlendMode(BlendMode.valueOf(split[1]));
+ }else if (split[0].equals("BlendEquation")){
+ renderState.setBlendEquation(BlendEquation.valueOf(split[1]));
+ }else if (split[0].equals("BlendEquationAlpha")){
+ renderState.setBlendEquationAlpha(RenderState.BlendEquationAlpha.valueOf(split[1]));
}else if (split[0].equals("AlphaTestFalloff")){
- renderState.setAlphaTest(true);
- renderState.setAlphaFallOff(Float.parseFloat(split[1]));
+ // Ignore for backwards compatbility
}else if (split[0].equals("PolyOffset")){
float factor = Float.parseFloat(split[1]);
float units = Float.parseFloat(split[2]);
@@ -453,7 +462,7 @@ public class J3MLoader implements AssetLoader {
}else if (split[0].equals("ColorWrite")){
renderState.setColorWrite(parseBoolean(split[1]));
}else if (split[0].equals("PointSprite")){
- renderState.setPointSprite(parseBoolean(split[1]));
+ // Ignore for backwards compatbility
}else if (split[0].equals("DepthFunc")){
renderState.setDepthFunc(RenderState.TestFunction.valueOf(split[1]));
}else if (split[0].equals("AlphaFunc")){
@@ -495,10 +504,22 @@ public class J3MLoader implements AssetLoader {
private void readDefine(String statement) throws IOException{
String[] split = statement.split(":");
if (split.length == 1){
- // add preset define
- technique.addShaderPresetDefine(split[0].trim(), VarType.Boolean, true);
+ String defineName = split[0].trim();
+ presetDefines.add(defineName);
}else if (split.length == 2){
- technique.addShaderParamDefine(split[1].trim(), split[0].trim());
+ String defineName = split[0].trim();
+ String paramName = split[1].trim();
+ MatParam param = materialDef.getMaterialParam(paramName);
+ if (param == null) {
+ logger.log(Level.WARNING, "In technique ''{0}'':\n"
+ + "Define ''{1}'' mapped to non-existent"
+ + " material parameter ''{2}'', ignoring.",
+ new Object[]{technique.getName(), defineName, paramName});
+ return;
+ }
+
+ VarType paramType = param.getVarType();
+ technique.addShaderParamDefine(paramName, paramType, defineName);
}else{
throw new IOException("Define syntax incorrect");
}
@@ -560,37 +581,80 @@ public class J3MLoader implements AssetLoader {
}
material.setTransparent(parseBoolean(split[1]));
}
+
+ private static String createShaderPrologue(List presetDefines) {
+ DefineList dl = new DefineList(presetDefines.size());
+ for (int i = 0; i < presetDefines.size(); i++) {
+ dl.set(i, 1);
+ }
+ StringBuilder sb = new StringBuilder();
+ dl.generateSource(sb, presetDefines, null);
+ return sb.toString();
+ }
private void readTechnique(Statement techStat) throws IOException{
isUseNodes = false;
String[] split = techStat.getLine().split(whitespacePattern);
+
+ String name;
if (split.length == 1) {
- technique = new TechniqueDef(null);
+ name = TechniqueDef.DEFAULT_TECHNIQUE_NAME;
} else if (split.length == 2) {
- String techName = split[1];
- technique = new TechniqueDef(techName);
+ name = split[1];
} else {
throw new IOException("Technique statement syntax incorrect");
}
+ String techniqueUniqueName = materialDef.getAssetName() + "@" + name;
+ technique = new TechniqueDef(name, techniqueUniqueName.hashCode());
+
for (Statement statement : techStat.getContents()){
readTechniqueStatement(statement);
}
if(isUseNodes){
nodesLoaderDelegate.computeConditions();
+
//used for caching later, the shader here is not a file.
+
+ // KIRILL 9/19/2015
+ // Not sure if this is needed anymore, since shader caching
+ // is now done by TechniqueDef.
technique.setShaderFile(technique.hashCode() + "", technique.hashCode() + "", "GLSL100", "GLSL100");
- }
-
- if (shaderName.containsKey(Shader.ShaderType.Vertex) && shaderName.containsKey(Shader.ShaderType.Fragment)) {
- technique.setShaderFile(shaderName, shaderLanguage);
+ }else if (shaderNames.containsKey(Shader.ShaderType.Vertex) && shaderNames.containsKey(Shader.ShaderType.Fragment)) {
+ technique.setShaderFile(shaderNames, shaderLanguages);
+ } else {
+ technique = null;
+ shaderLanguages.clear();
+ shaderNames.clear();
+ presetDefines.clear();
+ logger.log(Level.WARNING, "Fixed function technique was ignored");
+ logger.log(Level.WARNING, "Fixed function technique ''{0}'' was ignored for material {1}",
+ new Object[]{name, key});
+ return;
+ }
+
+ technique.setShaderPrologue(createShaderPrologue(presetDefines));
+
+ switch (technique.getLightMode()) {
+ case Disable:
+ technique.setLogic(new DefaultTechniqueDefLogic(technique));
+ break;
+ case MultiPass:
+ technique.setLogic(new MultiPassLightingLogic(technique));
+ break;
+ case SinglePass:
+ technique.setLogic(new SinglePassLightingLogic(technique));
+ break;
+ default:
+ throw new UnsupportedOperationException();
}
materialDef.addTechniqueDef(technique);
technique = null;
- shaderLanguage.clear();
- shaderName.clear();
+ shaderLanguages.clear();
+ shaderNames.clear();
+ presetDefines.clear();
}
private void loadFromRoot(List roots) throws IOException{
@@ -711,7 +775,7 @@ public class J3MLoader implements AssetLoader {
protected void initNodesLoader() {
if (!isUseNodes) {
- isUseNodes = shaderName.get(Shader.ShaderType.Vertex) == null && shaderName.get(Shader.ShaderType.Fragment) == null;
+ isUseNodes = shaderNames.get(Shader.ShaderType.Vertex) == null && shaderNames.get(Shader.ShaderType.Fragment) == null;
if (isUseNodes) {
if (nodesLoaderDelegate == null) {
nodesLoaderDelegate = new ShaderNodeLoaderDelegate();
diff --git a/jme3-core/src/plugins/java/com/jme3/material/plugins/ShaderNodeLoaderDelegate.java b/jme3-core/src/plugins/java/com/jme3/material/plugins/ShaderNodeLoaderDelegate.java
index 7cc902f95..efdf28f4b 100644
--- a/jme3-core/src/plugins/java/com/jme3/material/plugins/ShaderNodeLoaderDelegate.java
+++ b/jme3-core/src/plugins/java/com/jme3/material/plugins/ShaderNodeLoaderDelegate.java
@@ -44,6 +44,7 @@ import com.jme3.shader.ShaderNodeDefinition;
import com.jme3.shader.ShaderNodeVariable;
import com.jme3.shader.ShaderUtils;
import com.jme3.shader.UniformBinding;
+import com.jme3.shader.VarType;
import com.jme3.shader.VariableMapping;
import com.jme3.util.blockparser.Statement;
import java.io.IOException;
@@ -583,7 +584,7 @@ public class ShaderNodeLoaderDelegate {
//multiplicity is not an int attempting to find for a material parameter.
MatParam mp = findMatParam(multiplicity);
if (mp != null) {
- addDefine(multiplicity);
+ addDefine(multiplicity, VarType.Int);
multiplicity = multiplicity.toUpperCase();
} else {
throw new MatParseException("Wrong multiplicity for variable" + mapping.getLeftVariable().getName() + ". " + multiplicity + " should be an int or a declared material parameter.", statement);
@@ -625,9 +626,9 @@ public class ShaderNodeLoaderDelegate {
*
* @param paramName
*/
- public void addDefine(String paramName) {
+ public void addDefine(String paramName, VarType paramType) {
if (techniqueDef.getShaderParamDefine(paramName) == null) {
- techniqueDef.addShaderParamDefine(paramName, paramName.toUpperCase());
+ techniqueDef.addShaderParamDefine(paramName, paramType, paramName.toUpperCase());
}
}
@@ -660,7 +661,7 @@ public class ShaderNodeLoaderDelegate {
for (String string : defines) {
MatParam param = findMatParam(string);
if (param != null) {
- addDefine(param.getName());
+ addDefine(param.getName(), param.getVarType());
} else {
throw new MatParseException("Invalid condition, condition must match a Material Parameter named " + cond, statement);
}
diff --git a/jme3-core/src/plugins/java/com/jme3/scene/plugins/MTLLoader.java b/jme3-core/src/plugins/java/com/jme3/scene/plugins/MTLLoader.java
index f09eae150..cdc3655d6 100644
--- a/jme3-core/src/plugins/java/com/jme3/scene/plugins/MTLLoader.java
+++ b/jme3-core/src/plugins/java/com/jme3/scene/plugins/MTLLoader.java
@@ -149,8 +149,7 @@ public class MTLLoader implements AssetLoader {
if (transparent){
material.setTransparent(true);
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
- material.getAdditionalRenderState().setAlphaTest(true);
- material.getAdditionalRenderState().setAlphaFallOff(0.01f);
+ material.setFloat("AlphaDiscardThreshold", 0.01f);
}
matList.put(matName, material);
diff --git a/jme3-core/src/main/java/com/jme3/animation/BoneAnimation.java b/jme3-core/src/test/java/com/jme3/asset/LoadShaderSourceTest.java
similarity index 67%
rename from jme3-core/src/main/java/com/jme3/animation/BoneAnimation.java
rename to jme3-core/src/test/java/com/jme3/asset/LoadShaderSourceTest.java
index 735ee05a5..4e9999b20 100644
--- a/jme3-core/src/main/java/com/jme3/animation/BoneAnimation.java
+++ b/jme3-core/src/test/java/com/jme3/asset/LoadShaderSourceTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2015 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,16 +29,24 @@
* 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.animation;
+package com.jme3.asset;
-/**
- * @deprecated use Animation instead with tracks of selected type (ie. BoneTrack, SpatialTrack, MeshTrack)
- */
-@Deprecated
-public final class BoneAnimation extends Animation {
+import com.jme3.asset.plugins.ClasspathLocator;
+import com.jme3.shader.plugins.GLSLLoader;
+import com.jme3.system.JmeSystem;
+import com.jme3.system.MockJmeSystemDelegate;
+import org.junit.Test;
+
+public class LoadShaderSourceTest {
- @Deprecated
- public BoneAnimation(String name, float length) {
- super(name, length);
+ @Test
+ public void testLoadShaderSource() {
+ JmeSystem.setSystemDelegate(new MockJmeSystemDelegate());
+ AssetManager assetManager = new DesktopAssetManager();
+ assetManager.registerLocator(null, ClasspathLocator.class);
+ assetManager.registerLoader(GLSLLoader.class, "frag");
+ String showNormals = (String) assetManager.loadAsset("Common/MatDefs/Misc/ShowNormals.frag");
+ System.out.println(showNormals);
}
+
}
diff --git a/jme3-core/src/test/java/com/jme3/material/MaterialMatParamOverrideTest.java b/jme3-core/src/test/java/com/jme3/material/MaterialMatParamOverrideTest.java
new file mode 100644
index 000000000..defd850ba
--- /dev/null
+++ b/jme3-core/src/test/java/com/jme3/material/MaterialMatParamOverrideTest.java
@@ -0,0 +1,600 @@
+/*
+ * 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.scene.Node;
+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.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Before;
+
+/**
+ * Validates how {@link MatParamOverride MPOs} work on the material level.
+ *
+ * @author Kirill Vainer
+ */
+public class MaterialMatParamOverrideTest {
+
+ private static final HashSet IGNORED_UNIFORMS = new HashSet(
+ Arrays.asList(new String[]{"m_ParallaxHeight", "m_Shininess", "m_BackfaceShadows"}));
+
+ @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 testForcedOverride() {
+ material("Common/MatDefs/Light/Lighting.j3md");
+ inputMp(mpoFloat("AlphaDiscardThreshold", 3.12f));
+ inputMpo(mpoFloat("AlphaDiscardThreshold", 2.79f));
+ inputFpo(mpoFloat("AlphaDiscardThreshold", 1.23f));
+ outDefines(def("DISCARD_ALPHA", VarType.Float, 1.23f));
+ outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 1.23f));
+
+ reset();
+ root.clearMatParamOverrides();
+ root.updateGeometricState();
+ outDefines(def("DISCARD_ALPHA", VarType.Float, 2.79f));
+ outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 2.79f));
+ }
+
+ @Test
+ public void testChildOverridesParent() {
+ material("Common/MatDefs/Light/Lighting.j3md");
+
+ inputParentMpo(mpoFloat("AlphaDiscardThreshold", 3.12f));
+ inputMpo(mpoFloat("AlphaDiscardThreshold", 2.79f));
+
+ outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 2.79f));
+ outDefines(def("DISCARD_ALPHA", VarType.Float, 2.79f));
+ }
+
+ @Test
+ public void testMpoDisable() {
+ material("Common/MatDefs/Light/Lighting.j3md");
+ inputMp(mpoFloat("AlphaDiscardThreshold", 3.12f));
+
+ MatParamOverride override = mpoFloat("AlphaDiscardThreshold", 2.79f);
+ inputMpo(override);
+ outDefines(def("DISCARD_ALPHA", VarType.Float, 2.79f));
+ outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 2.79f));
+
+ reset();
+ override.setEnabled(false);
+ outDefines(def("DISCARD_ALPHA", VarType.Float, 3.12f));
+ outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 3.12f));
+
+ reset();
+ override.setEnabled(true);
+ 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();
+ root.updateGeometricState();
+ 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();
+ root.updateGeometricState();
+ 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();
+ root.updateGeometricState();
+ 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();
+ root.updateGeometricState();
+ 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 Node root = new Node("Root Node");
+ private final LightList lightList = new LightList(geometry);
+
+ @Before
+ public void setUp() {
+ root.attachChild(geometry);
+ }
+
+ private final NullRenderer renderer = new NullRenderer() {
+ @Override
+ public void setShader(Shader shader) {
+ MaterialMatParamOverrideTest.this.usedShader = shader;
+ evaluated = true;
+ }
+
+ @Override
+ public void setTexture(int unit, Texture texture) {
+ MaterialMatParamOverrideTest.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);
+ }
+ root.updateGeometricState();
+ }
+
+ private void inputParentMpo(MatParamOverride... overrides) {
+ if (evaluated) {
+ throw new IllegalStateException();
+ }
+ for (MatParamOverride override : overrides) {
+ root.addMatParamOverride(override);
+ }
+ root.updateGeometricState();
+ }
+
+ private void inputFpo(MatParamOverride... overrides) {
+ if (evaluated) {
+ throw new IllegalStateException();
+ }
+ for (MatParamOverride override : overrides) {
+ renderManager.addForcedMatParam(override);
+ }
+ }
+
+ private void reset() {
+ evaluated = false;
+ usedShader = null;
+ Arrays.fill(usedTextures, null);
+ for (MatParamOverride override : new ArrayList<>(renderManager.getForcedMatParams())) {
+ renderManager.removeForcedMatParam(override);
+ }
+ }
+
+ 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 nameToDefineMap = new HashMap();
+ 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) {
+ if (!evaluated) {
+ evaluateTechniqueDef();
+ }
+
+ HashSet actualUniforms = new HashSet<>();
+
+ for (Uniform uniform : usedShader.getUniformMap().values()) {
+ if (uniform.getName().startsWith("m_")
+ && !IGNORED_UNIFORMS.contains(uniform.getName())) {
+ actualUniforms.add(uniform);
+ }
+ }
+
+ HashSet expectedUniforms = new HashSet<>(Arrays.asList(uniforms));
+
+ if (!expectedUniforms.equals(actualUniforms)) {
+ Assert.fail("Uniform lists must match: " + expectedUniforms + " != " + actualUniforms);
+ }
+ }
+}
diff --git a/jme3-core/src/test/java/com/jme3/material/MaterialTest.java b/jme3-core/src/test/java/com/jme3/material/MaterialTest.java
new file mode 100644
index 000000000..e186f5e65
--- /dev/null
+++ b/jme3-core/src/test/java/com/jme3/material/MaterialTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.renderer.Caps;
+import com.jme3.renderer.RenderManager;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+import com.jme3.system.NullRenderer;
+import com.jme3.system.TestUtil;
+import java.util.Arrays;
+import java.util.EnumSet;
+import static org.junit.Assert.*;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MaterialTest {
+
+ private Material material;
+ private final Geometry geometry = new Geometry("Geometry", new Box(1, 1, 1));
+ private final EnumSet myCaps = EnumSet.noneOf(Caps.class);
+ private final RenderManager renderManager = new RenderManager(new NullRenderer() {
+ @Override
+ public EnumSet getCaps() {
+ return MaterialTest.this.myCaps;
+ }
+ });
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSelectNonExistentTechnique() {
+ material("Common/MatDefs/Gui/Gui.j3md");
+ material.selectTechnique("Doesn't Exist", renderManager);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testSelectDefaultTechnique_NoCaps() {
+ material("Common/MatDefs/Gui/Gui.j3md");
+ material.selectTechnique("Default", renderManager);
+ }
+
+ @Test
+ public void testSelectDefaultTechnique_GLSL100Cap() {
+ supportGlsl(100);
+ material("Common/MatDefs/Gui/Gui.j3md");
+
+ material.selectTechnique("Default", renderManager);
+
+ checkRequiredCaps(Caps.GLSL100);
+ }
+
+ @Test
+ public void testSelectDefaultTechnique_GLSL150Cap() {
+ supportGlsl(150);
+ material("Common/MatDefs/Gui/Gui.j3md");
+
+ material.selectTechnique("Default", renderManager);
+
+ checkRequiredCaps(Caps.GLSL150);
+ }
+
+ @Test
+ public void testSelectDefaultTechnique_GLSL120Cap_MultipleLangs() {
+ supportGlsl(120);
+ material("Common/MatDefs/Misc/Particle.j3md");
+
+ material.selectTechnique("Default", renderManager);
+
+ checkRequiredCaps(Caps.GLSL100, Caps.GLSL120);
+ }
+
+ @Test
+ public void testSelectDefaultTechnique_GLSL100Cap_MultipleLangs() {
+ supportGlsl(100);
+ material("Common/MatDefs/Misc/Particle.j3md");
+
+ material.selectTechnique("Default", renderManager);
+
+ checkRequiredCaps(Caps.GLSL100);
+ }
+
+ @Test
+ public void testSelectNamedTechnique_GLSL150Cap() {
+ supportGlsl(150);
+ material("Common/MatDefs/Light/Lighting.j3md");
+
+ material.selectTechnique("PostShadow", renderManager);
+
+ checkRequiredCaps(Caps.GLSL150);
+ }
+
+ @Test
+ public void testSelectNamedTechnique_GLSL100Cap() {
+ supportGlsl(100);
+ material("Common/MatDefs/Light/Lighting.j3md");
+
+ material.selectTechnique("PostShadow", renderManager);
+
+ checkRequiredCaps(Caps.GLSL100);
+ }
+
+ private void checkRequiredCaps(Caps... caps) {
+ EnumSet expected = EnumSet.noneOf(Caps.class);
+ expected.addAll(Arrays.asList(caps));
+
+ Technique tech = material.getActiveTechnique();
+
+ assertEquals(expected, tech.getDef().getRequiredCaps());
+ }
+
+ private void supportGlsl(int version) {
+ switch (version) {
+ case 150:
+ myCaps.add(Caps.GLSL150);
+ case 140:
+ myCaps.add(Caps.GLSL140);
+ case 130:
+ myCaps.add(Caps.GLSL130);
+ case 120:
+ myCaps.add(Caps.GLSL120);
+ case 110:
+ myCaps.add(Caps.GLSL110);
+ case 100:
+ myCaps.add(Caps.GLSL100);
+ break;
+ }
+ }
+
+ private void caps(Caps... caps) {
+ myCaps.addAll(Arrays.asList(caps));
+ }
+
+ private void material(String path) {
+ AssetManager assetManager = TestUtil.createAssetManager();
+ material = new Material(assetManager, path);
+ geometry.setMaterial(material);
+ }
+
+}
diff --git a/jme3-core/src/test/java/com/jme3/material/plugins/J3MLoaderTest.java b/jme3-core/src/test/java/com/jme3/material/plugins/J3MLoaderTest.java
index f45eb9bdf..b60e82c64 100644
--- a/jme3-core/src/test/java/com/jme3/material/plugins/J3MLoaderTest.java
+++ b/jme3-core/src/test/java/com/jme3/material/plugins/J3MLoaderTest.java
@@ -7,8 +7,11 @@ import com.jme3.asset.TextureKey;
import com.jme3.material.MatParamTexture;
import com.jme3.material.Material;
import com.jme3.material.MaterialDef;
+import com.jme3.renderer.Caps;
import com.jme3.shader.VarType;
import com.jme3.texture.Texture;
+import java.io.IOException;
+import java.util.EnumSet;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -18,6 +21,7 @@ import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
+import static org.junit.Assert.*;
import static org.mockito.Mockito.when;
/**
@@ -51,6 +55,30 @@ public class J3MLoaderTest {
j3MLoader = new J3MLoader();
}
+ @Test
+ public void noDefaultTechnique_shouldBeSupported() throws IOException {
+ when(assetInfo.openStream()).thenReturn(J3MLoader.class.getResourceAsStream("/no-default-technique.j3md"));
+ MaterialDef def = (MaterialDef) j3MLoader.load(assetInfo);
+ assertEquals(1, def.getTechniqueDefs("Test").size());
+ }
+
+ @Test
+ public void fixedPipelineTechnique_shouldBeIgnored() throws IOException {
+ when(assetInfo.openStream()).thenReturn(J3MLoader.class.getResourceAsStream("/no-shader-specified.j3md"));
+ MaterialDef def = (MaterialDef) j3MLoader.load(assetInfo);
+ assertEquals(null, def.getTechniqueDefs("A"));
+ assertEquals(1, def.getTechniqueDefs("B").size());
+ }
+
+ @Test
+ public void multipleSameNamedTechniques_shouldBeSupported() throws IOException {
+ when(assetInfo.openStream()).thenReturn(J3MLoader.class.getResourceAsStream("/same-name-technique.j3md"));
+ MaterialDef def = (MaterialDef) j3MLoader.load(assetInfo);
+ assertEquals(2, def.getTechniqueDefs("Test").size());
+ assertEquals(EnumSet.of(Caps.GLSL150), def.getTechniqueDefs("Test").get(0).getRequiredCaps());
+ assertEquals(EnumSet.of(Caps.GLSL100), def.getTechniqueDefs("Test").get(1).getRequiredCaps());
+ }
+
@Test
public void oldStyleTextureParameters_shouldBeSupported() throws Exception {
when(assetInfo.openStream()).thenReturn(J3MLoader.class.getResourceAsStream("/texture-parameters-oldstyle.j3m"));
@@ -107,7 +135,7 @@ public class J3MLoaderTest {
}
private TextureKey setupMockForTexture(final String paramName, final String path, final boolean flipY, final Texture texture) {
- when(materialDef.getMaterialParam(paramName)).thenReturn(new MatParamTexture(VarType.Texture2D, paramName, texture, 0, null));
+ when(materialDef.getMaterialParam(paramName)).thenReturn(new MatParamTexture(VarType.Texture2D, paramName, texture, null));
final TextureKey textureKey = new TextureKey(path, flipY);
textureKey.setGenerateMips(true);
diff --git a/jme3-core/src/test/java/com/jme3/material/plugins/LoadJ3mdTest.java b/jme3-core/src/test/java/com/jme3/material/plugins/LoadJ3mdTest.java
new file mode 100644
index 000000000..ea47129a7
--- /dev/null
+++ b/jme3-core/src/test/java/com/jme3/material/plugins/LoadJ3mdTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.plugins;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.*;
+import com.jme3.renderer.*;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+import com.jme3.shader.Shader;
+import com.jme3.system.*;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.*;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LoadJ3mdTest {
+
+ private Material material;
+ private final Geometry geometry = new Geometry("Geometry", new Box(1, 1, 1));
+ private final EnumSet myCaps = EnumSet.noneOf(Caps.class);
+ private final RenderManager renderManager = new RenderManager(new NullRenderer() {
+ @Override
+ public EnumSet getCaps() {
+ return LoadJ3mdTest.this.myCaps;
+ }
+ });
+
+ @Test
+ public void testShaderNodesMaterialDefLoading() {
+ supportGlsl(100);
+ material("testMatDef.j3md");
+ material.selectTechnique("Default", renderManager);
+
+ assertEquals(material.getActiveTechnique().getDef().getShaderNodes().size(), 2);
+ Shader s = material.getActiveTechnique().getDef().getShader(TestUtil.createAssetManager(), myCaps, material.getActiveTechnique().getDynamicDefines());
+ assertEquals(s.getSources().size(), 2);
+ }
+
+ private void supportGlsl(int version) {
+ switch (version) {
+ case 150:
+ myCaps.add(Caps.GLSL150);
+ case 140:
+ myCaps.add(Caps.GLSL140);
+ case 130:
+ myCaps.add(Caps.GLSL130);
+ case 120:
+ myCaps.add(Caps.GLSL120);
+ case 110:
+ myCaps.add(Caps.GLSL110);
+ case 100:
+ myCaps.add(Caps.GLSL100);
+ break;
+ }
+ }
+ private void caps(Caps... caps) {
+ myCaps.addAll(Arrays.asList(caps));
+ }
+
+ private void material(String path) {
+ AssetManager assetManager = TestUtil.createAssetManager();
+ material = new Material(assetManager, path);
+ geometry.setMaterial(material);
+ }
+
+}
diff --git a/jme3-core/src/test/java/com/jme3/math/FastMathTest.java b/jme3-core/src/test/java/com/jme3/math/FastMathTest.java
index a74390d42..709f0829c 100644
--- a/jme3-core/src/test/java/com/jme3/math/FastMathTest.java
+++ b/jme3-core/src/test/java/com/jme3/math/FastMathTest.java
@@ -33,6 +33,9 @@ package com.jme3.math;
import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import org.junit.Ignore;
+
/**
* Verifies that algorithms in {@link FastMath} are working correctly.
*
@@ -56,4 +59,39 @@ public class FastMathTest {
assert nextPowerOf2 == nearestPowerOfTwoSlow(i);
}
}
+
+ private static int fastCounterClockwise(Vector2f p0, Vector2f p1, Vector2f p2) {
+ float result = (p1.x - p0.x) * (p2.y - p1.y) - (p1.y - p0.y) * (p2.x - p1.x);
+ return (int) Math.signum(result);
+ }
+
+ private static Vector2f randomVector() {
+ return new Vector2f(FastMath.nextRandomFloat(),
+ FastMath.nextRandomFloat());
+ }
+
+ @Ignore
+ @Test
+ public void testCounterClockwise() {
+ for (int i = 0; i < 100; i++) {
+ Vector2f p0 = randomVector();
+ Vector2f p1 = randomVector();
+ Vector2f p2 = randomVector();
+
+ int fastResult = fastCounterClockwise(p0, p1, p2);
+ int slowResult = FastMath.counterClockwise(p0, p1, p2);
+
+ assert fastResult == slowResult;
+ }
+
+ // duplicate test
+ Vector2f p0 = new Vector2f(0,0);
+ Vector2f p1 = new Vector2f(0,0);
+ Vector2f p2 = new Vector2f(0,1);
+
+ int fastResult = fastCounterClockwise(p0, p1, p2);
+ int slowResult = FastMath.counterClockwise(p0, p1, p2);
+
+ assertEquals(slowResult, fastResult);
+ }
}
diff --git a/jme3-core/src/test/java/com/jme3/renderer/OpaqueComparatorTest.java b/jme3-core/src/test/java/com/jme3/renderer/OpaqueComparatorTest.java
new file mode 100644
index 000000000..ee4d279fd
--- /dev/null
+++ b/jme3-core/src/test/java/com/jme3/renderer/OpaqueComparatorTest.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2009-2015 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.renderer;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.ColorRGBA;
+import com.jme3.renderer.queue.GeometryList;
+import com.jme3.renderer.queue.OpaqueComparator;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.shape.Box;
+import com.jme3.system.TestUtil;
+import com.jme3.texture.Image;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture2D;
+import com.jme3.texture.image.ColorSpace;
+import com.jme3.util.BufferUtils;
+import java.nio.ByteBuffer;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class OpaqueComparatorTest {
+
+ private final Mesh mesh = new Box(1,1,1);
+ private Camera cam = new Camera(1, 1);
+ private RenderManager renderManager;
+ private AssetManager assetManager;
+ private OpaqueComparator comparator = new OpaqueComparator();
+
+ @Before
+ public void setUp() {
+ assetManager = TestUtil.createAssetManager();
+ renderManager = TestUtil.createRenderManager();
+ comparator.setCamera(cam);
+ }
+
+ /**
+ * Given a correctly sorted list of materials, check if the
+ * opaque comparator can sort a reversed list of them.
+ *
+ * Each material will be cloned so that none of them will be equal to each other
+ * in reference, forcing the comparator to compare the material sort ID.
+ *
+ * E.g. for a list of materials A, B, C, the following list will be generated:
+ * C, B, A, C, B, A, C, B, A
, it should result in
+ * A, A, A, B, B, B, C, C, C
.
+ *
+ * @param materials The pre-sorted list of materials to check sorting for.
+ */
+ private void testSort(Material ... materials) {
+ GeometryList gl = new GeometryList(comparator);
+ for (int g = 0; g < 5; g++) {
+ for (int i = materials.length - 1; i >= 0; i--) {
+ Geometry geom = new Geometry("geom", mesh);
+ Material clonedMaterial = materials[i].clone();
+
+ if (materials[i].getActiveTechnique() != null) {
+ String techniqueName = materials[i].getActiveTechnique().getDef().getName();
+ clonedMaterial.selectTechnique(techniqueName, renderManager);
+ } else {
+ clonedMaterial.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager);
+ }
+
+ geom.setMaterial(clonedMaterial);
+ gl.add(geom);
+ }
+ }
+ gl.sort();
+
+ for (int i = 0; i < gl.size(); i++) {
+ Material mat = gl.get(i).getMaterial();
+ String sortId = Integer.toHexString(mat.getSortId()).toUpperCase();
+ System.out.print(sortId + "\t");
+ System.out.println(mat);
+ }
+
+ Set alreadySeen = new HashSet();
+ Material current = null;
+ for (int i = 0; i < gl.size(); i++) {
+ Material mat = gl.get(i).getMaterial();
+ if (current == null) {
+ current = mat;
+ } else if (!current.getName().equals(mat.getName())) {
+ assert !alreadySeen.contains(mat.getName());
+ alreadySeen.add(current.getName());
+ current = mat;
+ }
+ }
+
+ for (int i = 0; i < materials.length; i++) {
+ for (int g = 0; g < 5; g++) {
+ int index = i * 5 + g;
+ Material mat1 = gl.get(index).getMaterial();
+ Material mat2 = materials[i];
+ assert mat1.getName().equals(mat2.getName()) :
+ mat1.getName() + " != " + mat2.getName() + " for index " + index;
+ }
+ }
+ }
+
+ @Test
+ public void testSortByMaterialDef() {
+ Material lightingMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Material particleMat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ Material unshadedMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ Material skyMat = new Material(assetManager, "Common/MatDefs/Misc/Sky.j3md");
+
+ lightingMat.setName("MatLight");
+ particleMat.setName("MatParticle");
+ unshadedMat.setName("MatUnshaded");
+ skyMat.setName("MatSky");
+ testSort(skyMat, lightingMat, particleMat, unshadedMat);
+ }
+
+ @Test
+ public void testSortByTechnique() {
+ Material lightingMatDefault = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Material lightingPreShadow = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Material lightingPostShadow = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Material lightingMatPreNormalPass = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Material lightingMatGBuf = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Material lightingMatGlow = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+
+ lightingMatDefault.setName("TechDefault");
+ lightingMatDefault.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager);
+
+ lightingPostShadow.setName("TechPostShad");
+ lightingPostShadow.selectTechnique("PostShadow", renderManager);
+
+ lightingPreShadow.setName("TechPreShad");
+ lightingPreShadow.selectTechnique("PreShadow", renderManager);
+
+ lightingMatPreNormalPass.setName("TechNorm");
+ lightingMatPreNormalPass.selectTechnique("PreNormalPass", renderManager);
+
+ lightingMatGBuf.setName("TechGBuf");
+ lightingMatGBuf.selectTechnique("GBuf", renderManager);
+
+ lightingMatGlow.setName("TechGlow");
+ lightingMatGlow.selectTechnique("Glow", renderManager);
+
+ testSort(lightingMatGlow, lightingPreShadow, lightingMatPreNormalPass,
+ lightingMatDefault, lightingPostShadow, lightingMatGBuf);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testNoSortByParam() {
+ Material sameMat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ Material sameMat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+
+ sameMat1.setName("MatRed");
+ sameMat1.setColor("Color", ColorRGBA.Red);
+
+ sameMat2.setName("MatBlue");
+ sameMat2.setColor("Color", ColorRGBA.Blue);
+
+ testSort(sameMat1, sameMat2);
+ }
+
+ private Texture createTexture(String name) {
+ ByteBuffer bb = BufferUtils.createByteBuffer(3);
+ Image image = new Image(Format.RGB8, 1, 1, bb, ColorSpace.sRGB);
+ Texture2D texture = new Texture2D(image);
+ texture.setName(name);
+ return texture;
+ }
+
+ @Test
+ public void testSortByTexture() {
+ Material texture1Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ Material texture2Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ Material texture3Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+
+ Texture tex1 = createTexture("A");
+ tex1.getImage().setId(1);
+
+ Texture tex2 = createTexture("B");
+ tex2.getImage().setId(2);
+
+ Texture tex3 = createTexture("C");
+ tex3.getImage().setId(3);
+
+ texture1Mat.setName("TexA");
+ texture1Mat.setTexture("ColorMap", tex1);
+
+ texture2Mat.setName("TexB");
+ texture2Mat.setTexture("ColorMap", tex2);
+
+ texture3Mat.setName("TexC");
+ texture3Mat.setTexture("ColorMap", tex3);
+
+ testSort(texture1Mat, texture2Mat, texture3Mat);
+ }
+
+ @Test
+ public void testSortByShaderDefines() {
+ Material lightingMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Material lightingMatVColor = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Material lightingMatVLight = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Material lightingMatTC = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Material lightingMatVColorLight = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Material lightingMatTCVColorLight = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+
+ lightingMat.setName("DefNone");
+
+ lightingMatVColor.setName("DefVC");
+ lightingMatVColor.setBoolean("UseVertexColor", true);
+
+ lightingMatVLight.setName("DefVL");
+ lightingMatVLight.setBoolean("VertexLighting", true);
+
+ lightingMatTC.setName("DefTC");
+ lightingMatTC.setBoolean("SeparateTexCoord", true);
+
+ lightingMatVColorLight.setName("DefVCVL");
+ lightingMatVColorLight.setBoolean("UseVertexColor", true);
+ lightingMatVColorLight.setBoolean("VertexLighting", true);
+
+ lightingMatTCVColorLight.setName("DefVCVLTC");
+ lightingMatTCVColorLight.setBoolean("UseVertexColor", true);
+ lightingMatTCVColorLight.setBoolean("VertexLighting", true);
+ lightingMatTCVColorLight.setBoolean("SeparateTexCoord", true);
+
+ testSort(lightingMat, lightingMatVColor, lightingMatVLight,
+ lightingMatVColorLight, lightingMatTC, lightingMatTCVColorLight);
+ }
+
+ @Test
+ public void testSortByAll() {
+ Material matBase1 = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Material matBase2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+
+ Texture texBase = createTexture("BASE");
+ texBase.getImage().setId(1);
+ Texture tex1 = createTexture("1");
+ tex1.getImage().setId(2);
+ Texture tex2 = createTexture("2");
+ tex2.getImage().setId(3);
+
+ matBase1.setName("BASE");
+ matBase1.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager);
+ matBase1.setBoolean("UseVertexColor", true);
+ matBase1.setTexture("DiffuseMap", texBase);
+
+ Material mat1100 = matBase1.clone();
+ mat1100.setName("1100");
+ mat1100.selectTechnique("PreShadow", renderManager);
+
+ Material mat1101 = matBase1.clone();
+ mat1101.setName("1101");
+ mat1101.selectTechnique("PreShadow", renderManager);
+ mat1101.setTexture("DiffuseMap", tex1);
+
+ Material mat1102 = matBase1.clone();
+ mat1102.setName("1102");
+ mat1102.selectTechnique("PreShadow", renderManager);
+ mat1102.setTexture("DiffuseMap", tex2);
+
+ Material mat1110 = matBase1.clone();
+ mat1110.setName("1110");
+ mat1110.selectTechnique("PreShadow", renderManager);
+ mat1110.setFloat("AlphaDiscardThreshold", 2f);
+
+ Material mat1120 = matBase1.clone();
+ mat1120.setName("1120");
+ mat1120.selectTechnique("PreShadow", renderManager);
+ mat1120.setBoolean("UseInstancing", true);
+
+ Material mat1121 = matBase1.clone();
+ mat1121.setName("1121");
+ mat1121.selectTechnique("PreShadow", renderManager);
+ mat1121.setBoolean("UseInstancing", true);
+ mat1121.setTexture("DiffuseMap", tex1);
+
+ Material mat1122 = matBase1.clone();
+ mat1122.setName("1122");
+ mat1122.selectTechnique("PreShadow", renderManager);
+ mat1122.setBoolean("UseInstancing", true);
+ mat1122.setTexture("DiffuseMap", tex2);
+
+ Material mat1140 = matBase1.clone();
+ mat1140.setName("1140");
+ mat1140.selectTechnique("PreShadow", renderManager);
+ mat1140.setFloat("AlphaDiscardThreshold", 2f);
+ mat1140.setBoolean("UseInstancing", true);
+
+ Material mat1200 = matBase1.clone();
+ mat1200.setName("1200");
+ mat1200.selectTechnique("PostShadow", renderManager);
+
+ Material mat1210 = matBase1.clone();
+ mat1210.setName("1210");
+ mat1210.selectTechnique("PostShadow", renderManager);
+ mat1210.setFloat("AlphaDiscardThreshold", 2f);
+
+ Material mat1220 = matBase1.clone();
+ mat1220.setName("1220");
+ mat1220.selectTechnique("PostShadow", renderManager);
+ mat1220.setBoolean("UseInstancing", true);
+
+ Material mat2000 = matBase2.clone();
+ mat2000.setName("2000");
+
+ testSort(mat1100, mat1101, mat1102, mat1110,
+ mat1120, mat1121, mat1122, mat1140,
+ mat1200, mat1210, mat1220, mat2000);
+ }
+}
diff --git a/jme3-core/src/test/java/com/jme3/scene/MPOTestUtils.java b/jme3-core/src/test/java/com/jme3/scene/MPOTestUtils.java
new file mode 100644
index 000000000..183dece70
--- /dev/null
+++ b/jme3-core/src/test/java/com/jme3/scene/MPOTestUtils.java
@@ -0,0 +1,173 @@
+/*
+ * 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.scene;
+
+import com.jme3.material.MatParamOverride;
+import com.jme3.math.Matrix4f;
+import com.jme3.renderer.Camera;
+import com.jme3.shader.VarType;
+import com.jme3.texture.Texture2D;
+import java.lang.reflect.Field;
+import java.util.HashSet;
+import java.util.Set;
+import static org.junit.Assert.assertEquals;
+
+public class MPOTestUtils {
+
+ private static final Camera DUMMY_CAM = new Camera(640, 480);
+
+ private static final SceneGraphVisitor VISITOR = new SceneGraphVisitor() {
+ @Override
+ public void visit(Spatial spatial) {
+ validateSubScene(spatial);
+ }
+ };
+
+ private static void validateSubScene(Spatial scene) {
+ scene.checkCulling(DUMMY_CAM);
+
+ Set actualOverrides = new HashSet();
+ for (MatParamOverride override : scene.getWorldMatParamOverrides()) {
+ actualOverrides.add(override);
+ }
+
+ Set expectedOverrides = new HashSet();
+ Spatial current = scene;
+ while (current != null) {
+ for (MatParamOverride override : current.getLocalMatParamOverrides()) {
+ expectedOverrides.add(override);
+ }
+ current = current.getParent();
+ }
+
+ assertEquals("For " + scene, expectedOverrides, actualOverrides);
+ }
+
+ public static void validateScene(Spatial scene) {
+ scene.updateGeometricState();
+ scene.depthFirstTraversal(VISITOR);
+ }
+
+ public static MatParamOverride mpoInt(String name, int value) {
+ return new MatParamOverride(VarType.Int, name, value);
+ }
+
+ public static MatParamOverride mpoBool(String name, boolean value) {
+ return new MatParamOverride(VarType.Boolean, name, value);
+ }
+
+ public static MatParamOverride mpoFloat(String name, float value) {
+ return new MatParamOverride(VarType.Float, name, value);
+ }
+
+ public static MatParamOverride mpoMatrix4Array(String name, Matrix4f[] value) {
+ return new MatParamOverride(VarType.Matrix4Array, name, value);
+ }
+
+ public static MatParamOverride mpoTexture2D(String name, Texture2D texture) {
+ return new MatParamOverride(VarType.Texture2D, name, texture);
+ }
+
+ private static int getRefreshFlags(Spatial scene) {
+ try {
+ Field refreshFlagsField = Spatial.class.getDeclaredField("refreshFlags");
+ refreshFlagsField.setAccessible(true);
+ return (Integer) refreshFlagsField.get(scene);
+ } catch (NoSuchFieldException ex) {
+ throw new AssertionError(ex);
+ } catch (SecurityException ex) {
+ throw new AssertionError(ex);
+ } catch (IllegalArgumentException ex) {
+ throw new AssertionError(ex);
+ } catch (IllegalAccessException ex) {
+ throw new AssertionError(ex);
+ }
+ }
+
+ private static void dumpSceneRF(Spatial scene, String indent, boolean last, int refreshFlagsMask) {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(indent);
+ if (last) {
+ if (!indent.isEmpty()) {
+ sb.append("└─");
+ } else {
+ sb.append(" ");
+ }
+ indent += " ";
+ } else {
+ sb.append("├─");
+ indent += "│ ";
+ }
+ sb.append(scene.getName());
+ int rf = getRefreshFlags(scene) & refreshFlagsMask;
+ if (rf != 0) {
+ sb.append("(");
+ if ((rf & 0x1) != 0) {
+ sb.append("T");
+ }
+ if ((rf & 0x2) != 0) {
+ sb.append("B");
+ }
+ if ((rf & 0x4) != 0) {
+ sb.append("L");
+ }
+ if ((rf & 0x8) != 0) {
+ sb.append("l");
+ }
+ if ((rf & 0x10) != 0) {
+ sb.append("O");
+ }
+ sb.append(")");
+ }
+
+ if (!scene.getLocalMatParamOverrides().isEmpty()) {
+ sb.append(" [MPO]");
+ }
+
+ System.out.println(sb);
+
+ if (scene instanceof Node) {
+ Node node = (Node) scene;
+ int childIndex = 0;
+ for (Spatial child : node.getChildren()) {
+ boolean childLast = childIndex == node.getQuantity() - 1;
+ dumpSceneRF(child, indent, childLast, refreshFlagsMask);
+ childIndex++;
+ }
+ }
+ }
+
+ public static void dumpSceneRF(Spatial scene, int refreshFlagsMask) {
+ dumpSceneRF(scene, "", true, refreshFlagsMask);
+ }
+}
diff --git a/jme3-core/src/test/java/com/jme3/scene/SceneMatParamOverrideTest.java b/jme3-core/src/test/java/com/jme3/scene/SceneMatParamOverrideTest.java
new file mode 100644
index 000000000..a615d5c92
--- /dev/null
+++ b/jme3-core/src/test/java/com/jme3/scene/SceneMatParamOverrideTest.java
@@ -0,0 +1,278 @@
+/*
+ * 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.scene;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.binary.BinaryExporter;
+import com.jme3.material.MatParamOverride;
+import org.junit.Test;
+
+import static com.jme3.scene.MPOTestUtils.*;
+import static org.junit.Assert.*;
+
+import com.jme3.system.TestUtil;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Validates how {@link MatParamOverride MPOs} work on the scene level.
+ *
+ * @author Kirill Vainer
+ */
+public class SceneMatParamOverrideTest {
+
+ private static Node createDummyScene() {
+ Node scene = new Node("Scene Node");
+
+ Node a = new Node("A");
+ Node b = new Node("B");
+
+ Node c = new Node("C");
+ Node d = new Node("D");
+
+ Node e = new Node("E");
+ Node f = new Node("F");
+
+ Node g = new Node("G");
+ Node h = new Node("H");
+ Node j = new Node("J");
+
+ scene.attachChild(a);
+ scene.attachChild(b);
+
+ a.attachChild(c);
+ a.attachChild(d);
+
+ b.attachChild(e);
+ b.attachChild(f);
+
+ c.attachChild(g);
+ c.attachChild(h);
+ c.attachChild(j);
+
+ return scene;
+ }
+
+ @Test
+ public void testOverrides_Empty() {
+ Node n = new Node("Node");
+ assertTrue(n.getLocalMatParamOverrides().isEmpty());
+ assertTrue(n.getWorldMatParamOverrides().isEmpty());
+
+ n.updateGeometricState();
+ assertTrue(n.getLocalMatParamOverrides().isEmpty());
+ assertTrue(n.getWorldMatParamOverrides().isEmpty());
+ }
+
+ @Test
+ public void testOverrides_AddRemove() {
+ MatParamOverride override = mpoBool("Test", true);
+ Node n = new Node("Node");
+
+ n.removeMatParamOverride(override);
+ assertTrue(n.getLocalMatParamOverrides().isEmpty());
+ assertTrue(n.getWorldMatParamOverrides().isEmpty());
+
+ n.addMatParamOverride(override);
+
+ assertSame(n.getLocalMatParamOverrides().get(0), override);
+ assertTrue(n.getWorldMatParamOverrides().isEmpty());
+ n.updateGeometricState();
+
+ assertSame(n.getLocalMatParamOverrides().get(0), override);
+ assertSame(n.getWorldMatParamOverrides().get(0), override);
+
+ n.removeMatParamOverride(override);
+ assertTrue(n.getLocalMatParamOverrides().isEmpty());
+ assertSame(n.getWorldMatParamOverrides().get(0), override);
+
+ n.updateGeometricState();
+ assertTrue(n.getLocalMatParamOverrides().isEmpty());
+ assertTrue(n.getWorldMatParamOverrides().isEmpty());
+ }
+
+ @Test
+ public void testOverrides_Clear() {
+ MatParamOverride override = mpoBool("Test", true);
+ Node n = new Node("Node");
+
+ n.clearMatParamOverrides();
+ assertTrue(n.getLocalMatParamOverrides().isEmpty());
+ assertTrue(n.getWorldMatParamOverrides().isEmpty());
+
+ n.addMatParamOverride(override);
+ n.clearMatParamOverrides();
+ assertTrue(n.getLocalMatParamOverrides().isEmpty());
+ assertTrue(n.getWorldMatParamOverrides().isEmpty());
+
+ n.addMatParamOverride(override);
+ n.updateGeometricState();
+ n.clearMatParamOverrides();
+ assertTrue(n.getLocalMatParamOverrides().isEmpty());
+ assertSame(n.getWorldMatParamOverrides().get(0), override);
+
+ n.updateGeometricState();
+ assertTrue(n.getLocalMatParamOverrides().isEmpty());
+ assertTrue(n.getWorldMatParamOverrides().isEmpty());
+
+ n.addMatParamOverride(override);
+ n.clearMatParamOverrides();
+ n.updateGeometricState();
+ assertTrue(n.getLocalMatParamOverrides().isEmpty());
+ assertTrue(n.getWorldMatParamOverrides().isEmpty());
+ }
+
+ @Test
+ public void testOverrides_AddAfterAttach() {
+ Node scene = createDummyScene();
+ scene.updateGeometricState();
+
+ Node root = new Node("Root Node");
+ root.updateGeometricState();
+
+ root.attachChild(scene);
+ scene.getChild("A").addMatParamOverride(mpoInt("val", 5));
+
+ validateScene(root);
+ }
+
+ @Test
+ public void testOverrides_AddBeforeAttach() {
+ Node scene = createDummyScene();
+ scene.getChild("A").addMatParamOverride(mpoInt("val", 5));
+ scene.updateGeometricState();
+
+ Node root = new Node("Root Node");
+ root.updateGeometricState();
+
+ root.attachChild(scene);
+
+ validateScene(root);
+ }
+
+ @Test
+ public void testOverrides_RemoveBeforeAttach() {
+ Node scene = createDummyScene();
+ scene.updateGeometricState();
+
+ Node root = new Node("Root Node");
+ root.updateGeometricState();
+
+ scene.getChild("A").addMatParamOverride(mpoInt("val", 5));
+ validateScene(scene);
+
+ scene.getChild("A").clearMatParamOverrides();
+ validateScene(scene);
+
+ root.attachChild(scene);
+ validateScene(root);
+ }
+
+ @Test
+ public void testOverrides_RemoveAfterAttach() {
+ Node scene = createDummyScene();
+ scene.updateGeometricState();
+
+ Node root = new Node("Root Node");
+ root.updateGeometricState();
+
+ scene.getChild("A").addMatParamOverride(mpoInt("val", 5));
+
+ root.attachChild(scene);
+ validateScene(root);
+
+ scene.getChild("A").clearMatParamOverrides();
+ validateScene(root);
+ }
+
+ @Test
+ public void testOverrides_IdenticalNames() {
+ Node scene = createDummyScene();
+
+ scene.getChild("A").addMatParamOverride(mpoInt("val", 5));
+ scene.getChild("C").addMatParamOverride(mpoInt("val", 7));
+
+ validateScene(scene);
+ }
+
+ @Test
+ public void testOverrides_CloningScene_DoesntCloneMPO() {
+ Node originalScene = createDummyScene();
+
+ originalScene.getChild("A").addMatParamOverride(mpoInt("int", 5));
+ originalScene.getChild("A").addMatParamOverride(mpoBool("bool", true));
+ originalScene.getChild("A").addMatParamOverride(mpoFloat("float", 3.12f));
+
+ Node clonedScene = originalScene.clone(false);
+
+ validateScene(clonedScene);
+ validateScene(originalScene);
+
+ List clonedOverrides = clonedScene.getChild("A").getLocalMatParamOverrides();
+ List originalOverrides = originalScene.getChild("A").getLocalMatParamOverrides();
+
+ assertNotSame(clonedOverrides, originalOverrides);
+ assertEquals(clonedOverrides, originalOverrides);
+
+ for (int i = 0; i < clonedOverrides.size(); i++) {
+ assertNotSame(clonedOverrides.get(i), originalOverrides.get(i));
+ assertEquals(clonedOverrides.get(i), originalOverrides.get(i));
+ }
+ }
+
+ @Test
+ public void testOverrides_SaveAndLoad_KeepsMPOs() {
+ MatParamOverride override = mpoInt("val", 5);
+ Node scene = createDummyScene();
+ scene.getChild("A").addMatParamOverride(override);
+
+ AssetManager assetManager = TestUtil.createAssetManager();
+ Node loadedScene = BinaryExporter.saveAndLoad(assetManager, scene);
+
+ Node root = new Node("Root Node");
+ root.attachChild(loadedScene);
+ validateScene(root);
+ validateScene(scene);
+
+ assertNotSame(override, loadedScene.getChild("A").getLocalMatParamOverrides().get(0));
+ assertEquals(override, loadedScene.getChild("A").getLocalMatParamOverrides().get(0));
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(mpoInt("val", 5), mpoInt("val", 5));
+ assertEquals(mpoBool("val", true), mpoBool("val", true));
+ assertNotEquals(mpoInt("val", 5), mpoInt("val", 6));
+ assertNotEquals(mpoInt("val1", 5), mpoInt("val2", 5));
+ assertNotEquals(mpoBool("val", true), mpoInt("val", 1));
+ }
+}
diff --git a/jme3-core/src/test/java/com/jme3/shader/DefineListTest.java b/jme3-core/src/test/java/com/jme3/shader/DefineListTest.java
new file mode 100644
index 000000000..35812b7c3
--- /dev/null
+++ b/jme3-core/src/test/java/com/jme3/shader/DefineListTest.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2009-2015 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.shader;
+
+import com.jme3.math.FastMath;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class DefineListTest {
+
+ private static final List DEFINE_NAMES = Arrays.asList("BOOL_VAR", "INT_VAR", "FLOAT_VAR");
+ private static final List DEFINE_TYPES = Arrays.asList(VarType.Boolean, VarType.Int, VarType.Float);
+ private static final int NUM_DEFINES = DEFINE_NAMES.size();
+ private static final int BOOL_VAR = 0;
+ private static final int INT_VAR = 1;
+ private static final int FLOAT_VAR = 2;
+ private static final DefineList EMPTY = new DefineList(NUM_DEFINES);
+
+ @Test
+ public void testHashCollision() {
+ DefineList dl1 = new DefineList(64);
+ DefineList dl2 = new DefineList(64);
+
+ // Try to cause a hash collision
+ // (since bit #32 is aliased to bit #1 in 32-bit ints)
+ dl1.set(0, 123);
+ dl1.set(32, 0);
+
+ dl2.set(32, 0);
+ dl2.set(0, 123);
+
+ assert dl1.hashCode() == dl2.hashCode();
+ assert dl1.equals(dl2);
+ }
+
+ @Test
+ public void testGetSet() {
+ DefineList dl = new DefineList(NUM_DEFINES);
+
+ assertFalse(dl.getBoolean(BOOL_VAR));
+ assertEquals(dl.getInt(INT_VAR), 0);
+ assertEquals(dl.getFloat(FLOAT_VAR), 0f, 0f);
+
+ dl.set(BOOL_VAR, true);
+ dl.set(INT_VAR, -1);
+ dl.set(FLOAT_VAR, Float.NaN);
+
+ assertTrue(dl.getBoolean(BOOL_VAR));
+ assertEquals(dl.getInt(INT_VAR), -1);
+ assertTrue(Float.isNaN(dl.getFloat(FLOAT_VAR)));
+ }
+
+ private String generateSource(DefineList dl) {
+ StringBuilder sb = new StringBuilder();
+ dl.generateSource(sb, DEFINE_NAMES, DEFINE_TYPES);
+ return sb.toString();
+ }
+
+ @Test
+ public void testSourceInitial() {
+ DefineList dl = new DefineList(NUM_DEFINES);
+ assert dl.hashCode() == 0;
+ assert generateSource(dl).equals("");
+ }
+
+ @Test
+ public void testSourceBooleanDefine() {
+ DefineList dl = new DefineList(NUM_DEFINES);
+
+ dl.set(BOOL_VAR, true);
+ assert dl.hashCode() == 1;
+ assert generateSource(dl).equals("#define BOOL_VAR 1\n");
+
+ dl.set(BOOL_VAR, false);
+ assert dl.hashCode() == 0;
+ assert generateSource(dl).equals("");
+ }
+
+ @Test
+ public void testSourceIntDefine() {
+ DefineList dl = new DefineList(NUM_DEFINES);
+
+ int hashCodeWithInt = 1 << INT_VAR;
+
+ dl.set(INT_VAR, 123);
+ assert dl.hashCode() == hashCodeWithInt;
+ assert generateSource(dl).equals("#define INT_VAR 123\n");
+
+ dl.set(INT_VAR, 0);
+ assert dl.hashCode() == 0;
+ assert generateSource(dl).equals("");
+
+ dl.set(INT_VAR, -99);
+ assert dl.hashCode() == hashCodeWithInt;
+ assert generateSource(dl).equals("#define INT_VAR -99\n");
+
+ dl.set(INT_VAR, Integer.MAX_VALUE);
+ assert dl.hashCode() == hashCodeWithInt;
+ assert generateSource(dl).equals("#define INT_VAR 2147483647\n");
+ }
+
+ @Test
+ public void testSourceFloatDefine() {
+ DefineList dl = new DefineList(NUM_DEFINES);
+
+ dl.set(FLOAT_VAR, 1f);
+ assert dl.hashCode() == (1 << FLOAT_VAR);
+ assert generateSource(dl).equals("#define FLOAT_VAR 1.0\n");
+
+ dl.set(FLOAT_VAR, 0f);
+ assert dl.hashCode() == 0;
+ assert generateSource(dl).equals("");
+
+ dl.set(FLOAT_VAR, -1f);
+ assert generateSource(dl).equals("#define FLOAT_VAR -1.0\n");
+
+ dl.set(FLOAT_VAR, FastMath.FLT_EPSILON);
+ assert generateSource(dl).equals("#define FLOAT_VAR 1.1920929E-7\n");
+
+ dl.set(FLOAT_VAR, FastMath.PI);
+ assert generateSource(dl).equals("#define FLOAT_VAR 3.1415927\n");
+
+ try {
+ dl.set(FLOAT_VAR, Float.NaN);
+ generateSource(dl);
+ assert false;
+ } catch (IllegalArgumentException ex) { }
+
+ try {
+ dl.set(FLOAT_VAR, Float.POSITIVE_INFINITY);
+ generateSource(dl);
+ assert false;
+ } catch (IllegalArgumentException ex) { }
+
+ try {
+ dl.set(FLOAT_VAR, Float.NEGATIVE_INFINITY);
+ generateSource(dl);
+ assert false;
+ } catch (IllegalArgumentException ex) { }
+ }
+
+ @Test
+ public void testEqualsAndHashCode() {
+ DefineList dl1 = new DefineList(NUM_DEFINES);
+ DefineList dl2 = new DefineList(NUM_DEFINES);
+
+ assertTrue(dl1.hashCode() == 0);
+ assertEquals(dl1, dl2);
+
+ dl1.set(BOOL_VAR, true);
+
+ assertTrue(dl1.hashCode() == 1);
+ assertNotSame(dl1, dl2);
+
+ dl2.set(BOOL_VAR, true);
+
+ assertEquals(dl1, dl2);
+
+ dl1.set(INT_VAR, 2);
+
+ assertTrue(dl1.hashCode() == (1|2));
+ assertNotSame(dl1, dl2);
+
+ dl2.set(INT_VAR, 2);
+
+ assertEquals(dl1, dl2);
+
+ dl1.set(BOOL_VAR, false);
+
+ assertTrue(dl1.hashCode() == 2);
+ assertNotSame(dl1, dl2);
+ }
+
+ @Test
+ public void testDeepClone() {
+ DefineList dl1 = new DefineList(NUM_DEFINES);
+ DefineList dl2 = dl1.deepClone();
+
+ assertFalse(dl1 == dl2);
+ assertTrue(dl1.equals(dl2));
+ assertTrue(dl1.hashCode() == dl2.hashCode());
+
+ dl1.set(BOOL_VAR, true);
+ dl2 = dl1.deepClone();
+
+ assertTrue(dl1.equals(dl2));
+ assertTrue(dl1.hashCode() == dl2.hashCode());
+
+ dl1.set(INT_VAR, 123);
+
+ assertFalse(dl1.equals(dl2));
+ assertFalse(dl1.hashCode() == dl2.hashCode());
+
+ dl2 = dl1.deepClone();
+
+ assertTrue(dl1.equals(dl2));
+ assertTrue(dl1.hashCode() == dl2.hashCode());
+ }
+
+ @Test
+ public void testGenerateSource() {
+ DefineList dl = new DefineList(NUM_DEFINES);
+
+ assertEquals("", generateSource(dl));
+
+ dl.set(BOOL_VAR, true);
+
+ assertEquals("#define BOOL_VAR 1\n", generateSource(dl));
+
+ dl.set(INT_VAR, 123);
+
+ assertEquals("#define BOOL_VAR 1\n" +
+ "#define INT_VAR 123\n", generateSource(dl));
+
+ dl.set(BOOL_VAR, false);
+
+ assertEquals("#define INT_VAR 123\n", generateSource(dl));
+
+ dl.set(BOOL_VAR, true);
+
+ // should have predictable ordering based on defineId
+ assertEquals("#define BOOL_VAR 1\n" +
+ "#define INT_VAR 123\n", generateSource(dl));
+ }
+
+ private static String doLookup(HashMap map, boolean boolVal, int intVal, float floatVal) {
+ DefineList dl = new DefineList(NUM_DEFINES);
+ dl.set(BOOL_VAR, boolVal);
+ dl.set(INT_VAR, intVal);
+ dl.set(FLOAT_VAR, floatVal);
+ return map.get(dl);
+ }
+
+ @Test
+ public void testHashLookup() {
+ String STR_EMPTY = "This is an empty define list";
+ String STR_INT = "This define list has an int value";
+ String STR_BOOL = "This define list just has boolean value set";
+ String STR_BOOL_INT = "This define list has both a boolean and int value";
+ String STR_BOOL_INT_FLOAT = "This define list has a boolean, int, and float value";
+
+ HashMap map = new HashMap();
+
+ DefineList lookup = new DefineList(NUM_DEFINES);
+
+ map.put(lookup.deepClone(), STR_EMPTY);
+
+ lookup.set(BOOL_VAR, true);
+ map.put(lookup.deepClone(), STR_BOOL);
+
+ lookup.set(BOOL_VAR, false);
+ lookup.set(INT_VAR, 123);
+ map.put(lookup.deepClone(), STR_INT);
+
+ lookup.set(BOOL_VAR, true);
+ map.put(lookup.deepClone(), STR_BOOL_INT);
+
+ lookup.set(FLOAT_VAR, FastMath.PI);
+ map.put(lookup.deepClone(), STR_BOOL_INT_FLOAT);
+
+ assertEquals(doLookup(map, false, 0, 0f), STR_EMPTY);
+ assertEquals(doLookup(map, false, 123, 0f), STR_INT);
+ assertEquals(doLookup(map, true, 0, 0f), STR_BOOL);
+ assertEquals(doLookup(map, true, 123, 0f), STR_BOOL_INT);
+ assertEquals(doLookup(map, true, 123, FastMath.PI), STR_BOOL_INT_FLOAT);
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/effect/ParticleComparator.java b/jme3-core/src/test/java/com/jme3/system/MockJmeSystemDelegate.java
similarity index 57%
rename from jme3-core/src/main/java/com/jme3/effect/ParticleComparator.java
rename to jme3-core/src/test/java/com/jme3/system/MockJmeSystemDelegate.java
index 78ee034d7..b9beac7f6 100644
--- a/jme3-core/src/main/java/com/jme3/effect/ParticleComparator.java
+++ b/jme3-core/src/test/java/com/jme3/system/MockJmeSystemDelegate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2015 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,48 +29,50 @@
* 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.effect;
+package com.jme3.system;
-import com.jme3.renderer.Camera;
-import java.util.Comparator;
+import com.jme3.audio.AudioRenderer;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URL;
+import java.nio.ByteBuffer;
-@Deprecated
-class ParticleComparator implements Comparator {
+public class MockJmeSystemDelegate extends JmeSystemDelegate {
- private Camera cam;
+ @Override
+ public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {
+ }
- public void setCamera(Camera cam){
- this.cam = cam;
+ @Override
+ public void showErrorDialog(String message) {
}
- public int compare(Particle p1, Particle p2) {
- return 0; // unused
- /*
- if (p1.life <= 0 || p2.life <= 0)
- return 0;
+ @Override
+ public boolean showSettingsDialog(AppSettings sourceSettings, boolean loadFromRegistry) {
+ return false;
+ }
-// if (p1.life <= 0)
-// return 1;
-// else if (p2.life <= 0)
-// return -1;
+ @Override
+ public URL getPlatformAssetConfigURL() {
+ return Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/General.cfg");
+ }
- float d1 = p1.distToCam, d2 = p2.distToCam;
+ @Override
+ public JmeContext newContext(AppSettings settings, JmeContext.Type contextType) {
+ return null;
+ }
- if (d1 == -1){
- d1 = cam.distanceToNearPlane(p1.position);
- p1.distToCam = d1;
- }
- if (d2 == -1){
- d2 = cam.distanceToNearPlane(p2.position);
- p2.distToCam = d2;
- }
+ @Override
+ public AudioRenderer newAudioRenderer(AppSettings settings) {
+ return null;
+ }
+
+ @Override
+ public void initialize(AppSettings settings) {
+ }
- if (d1 < d2)
- return 1;
- else if (d1 > d2)
- return -1;
- else
- return 0;
- */
+ @Override
+ public void showSoftKeyboard(boolean show) {
}
-}
\ No newline at end of file
+
+}
diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageHeightmap.java b/jme3-core/src/test/java/com/jme3/system/TestUtil.java
similarity index 69%
rename from jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageHeightmap.java
rename to jme3-core/src/test/java/com/jme3/system/TestUtil.java
index a61000e84..124b59ba7 100644
--- a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageHeightmap.java
+++ b/jme3-core/src/test/java/com/jme3/system/TestUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2015 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,27 +29,27 @@
* 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.terrain.heightmap;
+package com.jme3.system;
-/**
- * A heightmap that is built off an image.
- * If you want to be able to supply different Image types to
- * ImageBaseHeightMapGrid, you need to implement this interface,
- * and have that class extend Abstract heightmap.
- *
- * @author bowens
- * @deprecated
- */
-public interface ImageHeightmap {
+import com.jme3.asset.AssetConfig;
+import com.jme3.asset.AssetManager;
+import com.jme3.asset.DesktopAssetManager;
+import com.jme3.renderer.RenderManager;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class TestUtil {
+
+ static {
+ JmeSystem.setSystemDelegate(new MockJmeSystemDelegate());
+ }
- /**
- * Set the image to use for this heightmap
- */
- //public void setImage(Image image);
+ public static AssetManager createAssetManager() {
+ Logger.getLogger(AssetConfig.class.getName()).setLevel(Level.OFF);
+ return new DesktopAssetManager(true);
+ }
- /**
- * The BufferedImage.TYPE_ that is supported
- * by this ImageHeightmap
- */
- //public int getSupportedImageType();
+ public static RenderManager createRenderManager() {
+ return new RenderManager(new NullRenderer());
+ }
}
diff --git a/jme3-core/src/test/resources/no-default-technique.j3md b/jme3-core/src/test/resources/no-default-technique.j3md
new file mode 100644
index 000000000..03a7405ac
--- /dev/null
+++ b/jme3-core/src/test/resources/no-default-technique.j3md
@@ -0,0 +1,6 @@
+MaterialDef Test Material {
+ Technique Test {
+ VertexShader GLSL100 : test.vert
+ FragmentShader GLSL100 : test.frag
+ }
+}
diff --git a/jme3-core/src/test/resources/no-shader-specified.j3md b/jme3-core/src/test/resources/no-shader-specified.j3md
new file mode 100644
index 000000000..a81893c69
--- /dev/null
+++ b/jme3-core/src/test/resources/no-shader-specified.j3md
@@ -0,0 +1,8 @@
+MaterialDef Test Material {
+ Technique A {
+ }
+ Technique B {
+ VertexShader GLSL100 : test.vert
+ FragmentShader GLSL100 : test.frag
+ }
+}
diff --git a/jme3-core/src/test/resources/same-name-technique.j3md b/jme3-core/src/test/resources/same-name-technique.j3md
new file mode 100644
index 000000000..f3fde1876
--- /dev/null
+++ b/jme3-core/src/test/resources/same-name-technique.j3md
@@ -0,0 +1,10 @@
+MaterialDef Test Material {
+ Technique Test {
+ VertexShader GLSL150 : test150.vert
+ FragmentShader GLSL150 : test150.frag
+ }
+ Technique Test {
+ VertexShader GLSL100 : test.vert
+ FragmentShader GLSL100 : test.frag
+ }
+}
diff --git a/jme3-core/src/test/resources/testMatDef.j3md b/jme3-core/src/test/resources/testMatDef.j3md
new file mode 100644
index 000000000..bf70b1e2a
--- /dev/null
+++ b/jme3-core/src/test/resources/testMatDef.j3md
@@ -0,0 +1,34 @@
+MaterialDef Simple {
+ MaterialParameters {
+ Color Color
+ }
+ Technique {
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ VertexShaderNodes {
+ ShaderNode CommonVert {
+ Definition : CommonVert : Common/MatDefs/ShaderNodes/Common/CommonVert.j3sn
+ InputMappings {
+ worldViewProjectionMatrix = WorldParam.WorldViewProjectionMatrix
+ modelPosition = Global.position.xyz
+ }
+ OutputMappings {
+ Global.position = projPosition
+ }
+ }
+ }
+ FragmentShaderNodes {
+ ShaderNode ColorMult {
+ Definition : ColorMult : Common/MatDefs/ShaderNodes/Basic/ColorMult.j3sn
+ InputMappings {
+ color1 = MatParam.Color
+ color2 = Global.color
+ }
+ OutputMappings {
+ Global.color = outColor
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/jme3-core/src/tools/java/jme3tools/optimize/TextureAtlas.java b/jme3-core/src/tools/java/jme3tools/optimize/TextureAtlas.java
index 98347067c..9ca739014 100644
--- a/jme3-core/src/tools/java/jme3tools/optimize/TextureAtlas.java
+++ b/jme3-core/src/tools/java/jme3tools/optimize/TextureAtlas.java
@@ -504,7 +504,6 @@ public class TextureAtlas {
geom.setMesh(mesh);
Material mat = new Material(mgr, "Common/MatDefs/Light/Lighting.j3md");
- mat.getAdditionalRenderState().setAlphaTest(true);
Texture diffuseMap = atlas.getAtlasTexture("DiffuseMap");
Texture normalMap = atlas.getAtlasTexture("NormalMap");
Texture specularMap = atlas.getAtlasTexture("SpecularMap");
diff --git a/jme3-core/src/tools/java/jme3tools/shadercheck/ShaderCheck.java b/jme3-core/src/tools/java/jme3tools/shadercheck/ShaderCheck.java
index c77fa2b2e..98d379b38 100644
--- a/jme3-core/src/tools/java/jme3tools/shadercheck/ShaderCheck.java
+++ b/jme3-core/src/tools/java/jme3tools/shadercheck/ShaderCheck.java
@@ -6,11 +6,12 @@ import com.jme3.asset.plugins.FileLocator;
import com.jme3.material.MaterialDef;
import com.jme3.material.TechniqueDef;
import com.jme3.material.plugins.J3MLoader;
+import com.jme3.renderer.Caps;
import com.jme3.shader.DefineList;
import com.jme3.shader.Shader;
-import com.jme3.shader.ShaderKey;
import com.jme3.shader.plugins.GLSLLoader;
import com.jme3.system.JmeSystem;
+import java.util.EnumSet;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -33,23 +34,22 @@ public class ShaderCheck {
assetManager.registerLoader(GLSLLoader.class, "vert", "frag","geom","tsctrl","tseval","glsllib");
}
- private static void checkMatDef(String matdefName){
+ private static void checkMatDef(String matdefName) {
MaterialDef def = (MaterialDef) assetManager.loadAsset(matdefName);
- for (TechniqueDef techDef : def.getDefaultTechniques()){
- DefineList dl = new DefineList();
- dl.addFrom(techDef.getShaderPresetDefines());
- ShaderKey shaderKey = new ShaderKey(dl,techDef.getShaderProgramLanguages(),techDef.getShaderProgramNames());
-
- Shader shader = assetManager.loadShader(shaderKey);
-
- for (Validator validator : validators){
+ EnumSet rendererCaps = EnumSet.noneOf(Caps.class);
+ rendererCaps.add(Caps.GLSL100);
+ for (TechniqueDef techDef : def.getTechniqueDefs(TechniqueDef.DEFAULT_TECHNIQUE_NAME)) {
+ DefineList defines = techDef.createDefineList();
+ Shader shader = techDef.getShader(assetManager, rendererCaps, defines);
+ for (Validator validator : validators) {
StringBuilder sb = new StringBuilder();
validator.validate(shader, sb);
- System.out.println("==== Validator: " + validator.getName() + " " +
- validator.getInstalledVersion() + " ====");
+ System.out.println("==== Validator: " + validator.getName() + " "
+ + validator.getInstalledVersion() + " ====");
System.out.println(sb.toString());
}
}
+ throw new UnsupportedOperationException();
}
public static void main(String[] args){
diff --git a/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java b/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java
index 37a01e8ed..d02b5d21c 100644
--- a/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java
+++ b/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java
@@ -43,6 +43,7 @@ import com.jme3.system.JmeContext.Type;
import com.jme3.util.Screenshots;
import java.awt.EventQueue;
import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
@@ -116,12 +117,16 @@ public class JmeDesktopSystem extends JmeSystemDelegate {
@Override
public void showErrorDialog(String message) {
- final String msg = message;
- EventQueue.invokeLater(new Runnable() {
- public void run() {
- ErrorDialog.showDialog(msg);
- }
- });
+ if (!GraphicsEnvironment.isHeadless()) {
+ final String msg = message;
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ ErrorDialog.showDialog(msg);
+ }
+ });
+ } else {
+ System.err.println("[JME ERROR] " + message);
+ }
}
@Override
@@ -129,6 +134,9 @@ public class JmeDesktopSystem extends JmeSystemDelegate {
if (SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("Cannot run from EDT");
}
+ if (GraphicsEnvironment.isHeadless()) {
+ throw new IllegalStateException("Cannot show dialog in headless environment");
+ }
final AppSettings settings = new AppSettings(false);
settings.copyFrom(sourceSettings);
@@ -333,27 +341,13 @@ public class JmeDesktopSystem extends JmeSystemDelegate {
if (initialized) {
return;
}
-
initialized = true;
- try {
- if (!lowPermissions) {
- // can only modify logging settings
- // if permissions are available
-// JmeFormatter formatter = new JmeFormatter();
-// Handler fileHandler = new FileHandler("jme.log");
-// fileHandler.setFormatter(formatter);
-// Logger.getLogger("").addHandler(fileHandler);
-// Handler consoleHandler = new ConsoleHandler();
-// consoleHandler.setFormatter(formatter);
-// Logger.getLogger("").removeHandler(Logger.getLogger("").getHandlers()[0]);
-// Logger.getLogger("").addHandler(consoleHandler);
+ logger.log(Level.INFO, getBuildInfo());
+ if (!lowPermissions) {
+ if (NativeLibraryLoader.isUsingNativeBullet()) {
+ NativeLibraryLoader.loadNativeLibrary("bulletjme", true);
}
-// } catch (IOException ex){
-// logger.log(Level.SEVERE, "I/O Error while creating log file", ex);
- } catch (SecurityException ex) {
- logger.log(Level.SEVERE, "Security error in creating log file", ex);
}
- logger.log(Level.INFO, getBuildInfo());
}
@Override
diff --git a/jme3-desktop/src/main/java/com/jme3/system/Natives.java b/jme3-desktop/src/main/java/com/jme3/system/Natives.java
deleted file mode 100644
index 423fda882..000000000
--- a/jme3-desktop/src/main/java/com/jme3/system/Natives.java
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Copyright (c) 2009-2012 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.system;
-
-import java.io.*;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Helper class for extracting the natives (dll, so) from the jars.
- * This class should only be used internally.
- *
- * @deprecated Use {@link NativeLibraryLoader} instead.
- */
-@Deprecated
-public final class Natives {
-
- private static final Logger logger = Logger.getLogger(Natives.class.getName());
- private static final byte[] buf = new byte[1024 * 100];
- private static File extractionDirOverride = null;
- private static File extractionDir = null;
-
- public static void setExtractionDir(String name) {
- extractionDirOverride = new File(name).getAbsoluteFile();
- }
-
- public static File getExtractionDir() {
- if (extractionDirOverride != null) {
- return extractionDirOverride;
- }
- if (extractionDir == null) {
- File workingFolder = new File("").getAbsoluteFile();
- if (!workingFolder.canWrite()) {
- setStorageExtractionDir();
- } else {
- try {
- File file = new File(workingFolder.getAbsolutePath() + File.separator + ".jmetestwrite");
- file.createNewFile();
- file.delete();
- extractionDir = workingFolder;
- } catch (Exception e) {
- setStorageExtractionDir();
- }
- }
- }
- return extractionDir;
- }
-
- private static void setStorageExtractionDir() {
- logger.log(Level.WARNING, "Working directory is not writable. Using home directory instead.");
- extractionDir = new File(JmeSystem.getStorageFolder(),
- "natives_" + Integer.toHexString(computeNativesHash()));
- if (!extractionDir.exists()) {
- extractionDir.mkdir();
- }
- }
-
- private static int computeNativesHash() {
- URLConnection conn = null;
- try {
- String classpath = System.getProperty("java.class.path");
- URL url = Thread.currentThread().getContextClassLoader().getResource("com/jme3/system/Natives.class");
-
- StringBuilder sb = new StringBuilder(url.toString());
- if (sb.indexOf("jar:") == 0) {
- sb.delete(0, 4);
- sb.delete(sb.indexOf("!"), sb.length());
- sb.delete(sb.lastIndexOf("/") + 1, sb.length());
- }
- try {
- url = new URL(sb.toString());
- } catch (MalformedURLException ex) {
- throw new UnsupportedOperationException(ex);
- }
-
- conn = url.openConnection();
- int hash = classpath.hashCode() ^ (int) conn.getLastModified();
- return hash;
- } catch (IOException ex) {
- throw new UnsupportedOperationException(ex);
- } finally {
- if (conn != null) {
- try {
- conn.getInputStream().close();
- conn.getOutputStream().close();
- } catch (IOException ex) { }
- }
- }
- }
-
- public static void extractNativeLib(String sysName, String name) throws IOException {
- extractNativeLib(sysName, name, false, true);
- }
-
- public static void extractNativeLib(String sysName, String name, boolean load) throws IOException {
- extractNativeLib(sysName, name, load, true);
- }
-
- public static void extractNativeLib(String sysName, String name, boolean load, boolean warning) throws IOException {
- String fullname;
- String path;
- //XXX: hack to allow specifying the extension via supplying an extension in the name (e.g. "blah.dylib")
- // this is needed on osx where the openal.dylib always needs to be extracted as dylib
- // and never as jnilib, even if that is the platform JNI lib suffix (OpenAL is no JNI library)
- if(!name.contains(".")){
- // automatic name mapping
- fullname = System.mapLibraryName(name);
- path = "native/" + sysName + "/" + fullname;
- //XXX: Hack to extract jnilib to dylib on OSX Java 1.7+
- // This assumes all jni libs for osx are stored as "jnilib" in the jar file.
- // It will be extracted with the name required for the platform.
- // At a later stage this should probably inverted so that dylib is the default name.
- if(sysName.equals("macosx")){
- path = path.replaceAll("dylib","jnilib");
- }
- } else{
- fullname = name;
- path = "native/" + sysName + "/" + fullname;
- }
-
- URL url = Thread.currentThread().getContextClassLoader().getResource(path);
-
- // Also check for binaries that are not packed in folders by jme team, e.g. maven artifacts
- if(url == null){
- path = fullname;
- if(sysName.equals("macosx") && !name.contains(".")){
- path = path.replaceAll("dylib","jnilib");
- }
- url = Thread.currentThread().getContextClassLoader().getResource(path);
- }
-
- if(url == null){
- if (!warning) {
- logger.log(Level.WARNING, "Cannot locate native library in classpath: {0}/{1}",
- new String[]{sysName, fullname});
- }
- // Still try loading the library without a filename, maybe it is
- // accessible otherwise
- try{
- System.loadLibrary(name);
- } catch(UnsatisfiedLinkError e){
- if (!warning) {
- logger.log(Level.WARNING, "Cannot load native library: {0}/{1}",
- new String[]{sysName, fullname});
- }
- }
- return;
- }
-
- URLConnection conn = url.openConnection();
- InputStream in = conn.getInputStream();
- File targetFile = new File(getExtractionDir(), fullname);
- OutputStream out = null;
- try {
- if (targetFile.exists()) {
- // OK, compare last modified date of this file to
- // file in jar
- long targetLastModified = targetFile.lastModified();
- long sourceLastModified = conn.getLastModified();
-
- // Allow ~1 second range for OSes that only support low precision
- if (targetLastModified + 1000 > sourceLastModified) {
- logger.log(Level.FINE, "Not copying library {0}. Latest already extracted.", fullname);
- return;
- }
- }
-
- out = new FileOutputStream(targetFile);
- int len;
- while ((len = in.read(buf)) > 0) {
- out.write(buf, 0, len);
- }
- in.close();
- in = null;
- out.close();
- out = null;
-
- // NOTE: On OSes that support "Date Created" property,
- // this will cause the last modified date to be lower than
- // date created which makes no sense
- targetFile.setLastModified(conn.getLastModified());
- } catch (FileNotFoundException ex) {
- if (ex.getMessage().contains("used by another process")) {
- return;
- }
-
- throw ex;
- } finally {
- if (load) {
- System.load(targetFile.getAbsolutePath());
- }
- if(in != null){
- in.close();
- }
- if(out != null){
- out.close();
- }
- }
- logger.log(Level.FINE, "Copied {0} to {1}", new Object[]{fullname, targetFile});
- }
-
- protected static boolean isUsingNativeBullet() {
- try {
- Class clazz = Class.forName("com.jme3.bullet.util.NativeMeshUtil");
- return clazz != null;
- } catch (ClassNotFoundException ex) {
- return false;
- }
- }
-
- public static void extractNativeLibs(Platform platform, AppSettings settings) throws IOException {
- if (true) {
- throw new UnsupportedEncodingException("Now, why would you EVER want to do that?");
- }
-
- String renderer = settings.getRenderer();
- String audioRenderer = settings.getAudioRenderer();
- boolean needLWJGL = false;
- boolean needOAL = false;
- boolean needJInput = false;
- boolean needNativeBullet = isUsingNativeBullet();
-
- if (renderer != null) {
- if (renderer.startsWith("LWJGL")) {
- needLWJGL = true;
- }
- }
- if (audioRenderer != null) {
- if (audioRenderer.equals("LWJGL")) {
- needLWJGL = true;
- needOAL = true;
- }
- }
- needJInput = settings.useJoysticks();
-
- String libraryPath = getExtractionDir().toString();
- if (needLWJGL) {
- logger.log(Level.INFO, "Extraction Directory: {0}", getExtractionDir().toString());
-
- // LWJGL supports this feature where
- // it can load libraries from this path.
- System.setProperty("org.lwjgl.librarypath", libraryPath);
- }
- if (needJInput) {
- // AND Luckily enough JInput supports the same feature.
- System.setProperty("net.java.games.input.librarypath", libraryPath);
- }
-
- switch (platform) {
- case Windows64:
- if (needLWJGL) {
- extractNativeLib("windows", "lwjgl64");
- }
- if (needOAL) {
- extractNativeLib("windows", "OpenAL64", true, false);
- }
- if (needJInput) {
- extractNativeLib("windows", "jinput-dx8_64");
- extractNativeLib("windows", "jinput-raw_64");
- }
- if (needNativeBullet) {
- extractNativeLib("windows", "bulletjme64", true, false);
- }
- break;
- case Windows32:
- if (needLWJGL) {
- extractNativeLib("windows", "lwjgl");
- }
- if (needOAL) {
- extractNativeLib("windows", "OpenAL32", true, false);
- }
- if (needJInput) {
- extractNativeLib("windows", "jinput-dx8");
- extractNativeLib("windows", "jinput-raw");
- }
- if (needNativeBullet) {
- extractNativeLib("windows", "bulletjme", true, false);
- }
- break;
- case Linux64:
- if (needLWJGL) {
- extractNativeLib("linux", "lwjgl64");
- }
- if (needJInput) {
- extractNativeLib("linux", "jinput-linux64");
- }
- if (needOAL) {
- extractNativeLib("linux", "openal64");
- }
- if (needNativeBullet) {
- extractNativeLib("linux", "bulletjme64", true, false);
- }
- break;
- case Linux32:
- if (needLWJGL) {
- extractNativeLib("linux", "lwjgl");
- }
- if (needJInput) {
- extractNativeLib("linux", "jinput-linux");
- }
- if (needOAL) {
- extractNativeLib("linux", "openal");
- }
- if (needNativeBullet) {
- extractNativeLib("linux", "bulletjme", true, false);
- }
- break;
- case MacOSX_PPC32:
- case MacOSX32:
- case MacOSX_PPC64:
- case MacOSX64:
- if (needLWJGL) {
- extractNativeLib("macosx", "lwjgl");
- }
- if (needOAL){
- extractNativeLib("macosx", "openal.dylib");
- }
- if (needJInput) {
- extractNativeLib("macosx", "jinput-osx");
- }
- if (needNativeBullet) {
- extractNativeLib("macosx", "bulletjme", true, false);
- }
- break;
- }
- }
-}
diff --git a/jme3-examples/build.gradle b/jme3-examples/build.gradle
index ce7a7cbd6..be2e106a6 100644
--- a/jme3-examples/build.gradle
+++ b/jme3-examples/build.gradle
@@ -12,7 +12,9 @@ task run(dependsOn: 'build', type:JavaExec) {
jvmArgs "-Djava.awt.headless=true"
}
- systemProperty "java.util.logging.config.file", System.getProperty("java.util.logging.config.file")
+ if (System.properties['java.util.logging.config.file'] != null) {
+ systemProperty "java.util.logging.config.file", System.properties['java.util.logging.config.file']
+ }
if( assertions == "true" ){
enableAssertions = true;
diff --git a/jme3-examples/src/main/java/jme3test/animation/TestCameraMotionPath.java b/jme3-examples/src/main/java/jme3test/animation/TestCameraMotionPath.java
index ffe65a888..baeb41a31 100644
--- a/jme3-examples/src/main/java/jme3test/animation/TestCameraMotionPath.java
+++ b/jme3-examples/src/main/java/jme3test/animation/TestCameraMotionPath.java
@@ -139,7 +139,8 @@ public class TestCameraMotionPath extends SimpleApplication {
rootNode.attachChild(teapot);
- Geometry soil = new Geometry("soil", new Box(new Vector3f(0, -1.0f, 0), 50, 1, 50));
+ Geometry soil = new Geometry("soil", new Box(50, 1, 50));
+ soil.setLocalTranslation(0, -1, 0);
soil.setMaterial(matSoil);
rootNode.attachChild(soil);
DirectionalLight light = new DirectionalLight();
diff --git a/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java b/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java
index f0200bc91..a066426e4 100644
--- a/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java
+++ b/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java
@@ -222,7 +222,8 @@ public class TestCinematic extends SimpleApplication {
matSoil.setColor("Diffuse", ColorRGBA.Green);
matSoil.setColor("Specular", ColorRGBA.Black);
- Geometry soil = new Geometry("soil", new Box(new Vector3f(0, -6.0f, 0), 50, 1, 50));
+ Geometry soil = new Geometry("soil", new Box(50, 1, 50));
+ soil.setLocalTranslation(0, -6, 0);
soil.setMaterial(matSoil);
soil.setShadowMode(ShadowMode.Receive);
rootNode.attachChild(soil);
diff --git a/jme3-examples/src/main/java/jme3test/animation/TestMotionPath.java b/jme3-examples/src/main/java/jme3test/animation/TestMotionPath.java
index 57584f7c5..51268b6bc 100644
--- a/jme3-examples/src/main/java/jme3test/animation/TestMotionPath.java
+++ b/jme3-examples/src/main/java/jme3test/animation/TestMotionPath.java
@@ -136,7 +136,8 @@ public class TestMotionPath extends SimpleApplication {
rootNode.attachChild(teapot);
- Geometry soil = new Geometry("soil", new Box(new Vector3f(0, -1.0f, 0), 50, 1, 50));
+ Geometry soil = new Geometry("soil", new Box(50, 1, 50));
+ soil.setLocalTranslation(0, -1, 0);
soil.setMaterial(matSoil);
rootNode.attachChild(soil);
diff --git a/jme3-examples/src/main/java/jme3test/app/TestAppStateLifeCycle.java b/jme3-examples/src/main/java/jme3test/app/TestAppStateLifeCycle.java
index f22424252..ebca77683 100644
--- a/jme3-examples/src/main/java/jme3test/app/TestAppStateLifeCycle.java
+++ b/jme3-examples/src/main/java/jme3test/app/TestAppStateLifeCycle.java
@@ -57,7 +57,7 @@ public class TestAppStateLifeCycle extends SimpleApplication {
@Override
public void simpleInitApp() {
- Box b = new Box(Vector3f.ZERO, 1, 1, 1);
+ Box b = new Box(1, 1, 1);
Geometry geom = new Geometry("Box", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
diff --git a/jme3-examples/src/main/java/jme3test/app/TestBareBonesApp.java b/jme3-examples/src/main/java/jme3test/app/TestBareBonesApp.java
index 5d3298279..491f4817b 100644
--- a/jme3-examples/src/main/java/jme3test/app/TestBareBonesApp.java
+++ b/jme3-examples/src/main/java/jme3test/app/TestBareBonesApp.java
@@ -56,7 +56,7 @@ public class TestBareBonesApp extends LegacyApplication {
System.out.println("Initialize");
// create a box
- boxGeom = new Geometry("Box", new Box(Vector3f.ZERO, 2, 2, 2));
+ boxGeom = new Geometry("Box", new Box(2, 2, 2));
// load some default material
boxGeom.setMaterial(assetManager.loadMaterial("Interface/Logo/Logo.j3m"));
diff --git a/jme3-examples/src/main/java/jme3test/app/TestNativeLoader.java b/jme3-examples/src/main/java/jme3test/app/TestNativeLoader.java
deleted file mode 100644
index 2854fd217..000000000
--- a/jme3-examples/src/main/java/jme3test/app/TestNativeLoader.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2009-2012 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 jme3test.app;
-
-import com.jme3.system.NativeLibraryLoader;
-import java.io.File;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Try to load some natives.
- *
- * @author Kirill Vainer
- */
-public class TestNativeLoader {
-
- private static final File WORKING_FOLDER = new File(System.getProperty("user.dir"));
-
- private static void tryLoadLwjgl() {
- NativeLibraryLoader.loadNativeLibrary("lwjgl", true);
- System.out.println("Succeeded in loading LWJGL.\n\tVersion: " +
- org.lwjgl.Sys.getVersion());
- }
-
- private static void tryLoadJinput() {
- NativeLibraryLoader.loadNativeLibrary("jinput", true);
- NativeLibraryLoader.loadNativeLibrary("jinput-dx8", true);
-
- net.java.games.input.ControllerEnvironment ce =
- net.java.games.input.ControllerEnvironment.getDefaultEnvironment();
- if (ce.isSupported()) {
- net.java.games.input.Controller[] c =
- ce.getControllers();
-
- System.out.println("Succeeded in loading JInput.\n\tVersion: " +
- net.java.games.util.Version.getVersion());
- }
- }
-
- private static void tryLoadOpenAL() {
- NativeLibraryLoader.loadNativeLibrary("openal", true);
-
- try {
- org.lwjgl.openal.AL.create();
- String renderer = org.lwjgl.openal.AL10.alGetString(org.lwjgl.openal.AL10.AL_RENDERER);
- String vendor = org.lwjgl.openal.AL10.alGetString(org.lwjgl.openal.AL10.AL_VENDOR);
- String version = org.lwjgl.openal.AL10.alGetString(org.lwjgl.openal.AL10.AL_VERSION);
- System.out.println("Succeeded in loading OpenAL.");
- System.out.println("\tVersion: " + version);
- } catch (org.lwjgl.LWJGLException ex) {
- throw new RuntimeException(ex);
- } finally {
- if (org.lwjgl.openal.AL.isCreated()) {
- org.lwjgl.openal.AL.destroy();
- }
- }
- }
-
- private static void tryLoadOpenGL() {
- org.lwjgl.opengl.Pbuffer pb = null;
- try {
- pb = new org.lwjgl.opengl.Pbuffer(1, 1, new org.lwjgl.opengl.PixelFormat(0, 0, 0), null);
- pb.makeCurrent();
- String version = org.lwjgl.opengl.GL11.glGetString(org.lwjgl.opengl.GL11.GL_VERSION);
- System.out.println("Succeeded in loading OpenGL.\n\tVersion: " + version);
- } catch (org.lwjgl.LWJGLException ex) {
- throw new RuntimeException(ex);
- } finally {
- if (pb != null) {
- pb.destroy();
- }
- }
- }
-
- private static void tryLoadBulletJme() {
- if (NativeLibraryLoader.isUsingNativeBullet()) {
- NativeLibraryLoader.loadNativeLibrary("bulletjme", true);
-
- com.jme3.bullet.PhysicsSpace physSpace = new com.jme3.bullet.PhysicsSpace();
-
- System.out.println("Succeeded in loading BulletJme.");
- } else {
- System.out.println("Native bullet not included. Cannot test loading.");
- }
- }
-
- private static void cleanupNativesFolder(File folder) {
- for (File file : folder.listFiles()) {
- String lowerCaseName = file.getName().toLowerCase();
- if (lowerCaseName.contains("lwjgl") ||
- lowerCaseName.contains("jinput") ||
- lowerCaseName.contains("openal") ||
- lowerCaseName.contains("bulletjme")) {
- file.delete();
- }
- }
- }
-
- public static void main(String[] args) {
- Logger.getLogger("").getHandlers()[0].setLevel(Level.WARNING);
- Logger.getLogger(NativeLibraryLoader.class.getName()).setLevel(Level.ALL);
-
- // Get a bit more output from LWJGL about issues.
- // System.setProperty("org.lwjgl.util.Debug", "true");
-
- // Extracting to working folder is no brainer.
- // Choose some random path, then load LWJGL.
- File customNativesFolder = new File("CustomNativesFolder");
- customNativesFolder.mkdirs();
-
- if (!customNativesFolder.isDirectory()) {
- throw new IllegalStateException("Failed to make custom natives folder");
- }
-
- // Let's cleanup our folders first.
- cleanupNativesFolder(WORKING_FOLDER);
- cleanupNativesFolder(customNativesFolder);
-
- NativeLibraryLoader.setCustomExtractionFolder(customNativesFolder.getAbsolutePath());
-
- tryLoadLwjgl();
- tryLoadOpenGL();
- tryLoadOpenAL();
- tryLoadJinput();
- tryLoadBulletJme();
- }
-}
diff --git a/jme3-examples/src/main/java/jme3test/app/TestReleaseDirectMemory.java b/jme3-examples/src/main/java/jme3test/app/TestReleaseDirectMemory.java
index 280212b71..28947c400 100644
--- a/jme3-examples/src/main/java/jme3test/app/TestReleaseDirectMemory.java
+++ b/jme3-examples/src/main/java/jme3test/app/TestReleaseDirectMemory.java
@@ -50,7 +50,7 @@ public class TestReleaseDirectMemory extends SimpleApplication {
@Override
public void simpleInitApp() {
- Box b = new Box(Vector3f.ZERO, 1, 1, 1);
+ Box b = new Box(1, 1, 1);
Geometry geom = new Geometry("Box", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
diff --git a/jme3-examples/src/main/java/jme3test/audio/TestAmbient.java b/jme3-examples/src/main/java/jme3test/audio/TestAmbient.java
index cf90cc96a..2703d53da 100644
--- a/jme3-examples/src/main/java/jme3test/audio/TestAmbient.java
+++ b/jme3-examples/src/main/java/jme3test/audio/TestAmbient.java
@@ -69,7 +69,7 @@ public class TestAmbient extends SimpleApplication {
nature.play();
// just a blue box to mark the spot
- Box box1 = new Box(Vector3f.ZERO, .5f, .5f, .5f);
+ Box box1 = new Box(.5f, .5f, .5f);
Geometry player = new Geometry("Player", box1);
Material mat1 = new Material(assetManager,
"Common/MatDefs/Misc/Unshaded.j3md");
diff --git a/jme3-examples/src/main/java/jme3test/audio/TestDoppler.java b/jme3-examples/src/main/java/jme3test/audio/TestDoppler.java
index 60136bcff..1065e1cee 100644
--- a/jme3-examples/src/main/java/jme3test/audio/TestDoppler.java
+++ b/jme3-examples/src/main/java/jme3test/audio/TestDoppler.java
@@ -33,72 +33,62 @@
package jme3test.audio;
import com.jme3.app.SimpleApplication;
+import com.jme3.audio.AudioData;
import com.jme3.audio.AudioNode;
-import com.jme3.audio.Environment;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
-import org.lwjgl.openal.AL10;
-import org.lwjgl.openal.AL11;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.scene.shape.Torus;
/**
* Test Doppler Effect
*/
public class TestDoppler extends SimpleApplication {
- private AudioNode ufo;
+ private float pos = -5;
+ private float vel = 5;
+ private AudioNode ufoNode;
- private float x = 20, z = 0;
- private float rate = -0.05f;
- private float xDist = 20;
- private float zDist = 5;
- private float angle = FastMath.TWO_PI;
-
public static void main(String[] args){
TestDoppler test = new TestDoppler();
test.start();
}
@Override
- public void simpleInitApp(){
- audioRenderer.setEnvironment(Environment.Dungeon);
- AL10.alDistanceModel(AL11.AL_EXPONENT_DISTANCE);
-
- ufo = new AudioNode(assetManager, "Sound/Effects/Beep.ogg", false);
- ufo.setPositional(true);
- ufo.setLooping(true);
- ufo.setReverbEnabled(true);
- ufo.setRefDistance(100000000);
- ufo.setMaxDistance(100000000);
- ufo.play();
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(10);
+
+ Torus torus = new Torus(10, 6, 1, 3);
+ Geometry g = new Geometry("Torus Geom", torus);
+ g.rotate(-FastMath.HALF_PI, 0, 0);
+ g.center();
+
+ g.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+// rootNode.attachChild(g);
+
+ ufoNode = new AudioNode(assetManager, "Sound/Effects/Beep.ogg", AudioData.DataType.Buffer);
+ ufoNode.setLooping(true);
+ ufoNode.setPitch(0.5f);
+ ufoNode.setRefDistance(1);
+ ufoNode.setMaxDistance(100000000);
+ ufoNode.setVelocityFromTranslation(true);
+ ufoNode.play();
+
+ Geometry ball = new Geometry("Beeper", new Sphere(10, 10, 0.1f));
+ ball.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ ufoNode.attachChild(ball);
+
+ rootNode.attachChild(ufoNode);
}
+
@Override
- public void simpleUpdate(float tpf){
- //float x = (float) (Math.cos(angle) * xDist);
- float dx = (float) Math.sin(angle) * xDist;
-
- //float z = (float) (Math.sin(angle) * zDist);
- float dz = (float)(-Math.cos(angle) * zDist);
-
- x += dx * tpf * 0.05f;
- z += dz * tpf * 0.05f;
-
- angle += tpf * rate;
-
- if (angle > FastMath.TWO_PI){
- angle = FastMath.TWO_PI;
- rate = -rate;
- }else if (angle < -0){
- angle = -0;
- rate = -rate;
+ public void simpleUpdate(float tpf) {
+ pos += tpf * vel;
+ if (pos < -10 || pos > 10) {
+ vel *= -1;
}
-
- ufo.setVelocity(new Vector3f(dx, 0, dz));
- ufo.setLocalTranslation(x, 0, z);
- ufo.updateGeometricState();
-
- System.out.println("LOC: " + (int)x +", " + (int)z +
- ", VEL: " + (int)dx + ", " + (int)dz);
+ ufoNode.setLocalTranslation(new Vector3f(pos, 0, 0));
}
-
}
diff --git a/jme3-examples/src/main/java/jme3test/audio/TestOgg.java b/jme3-examples/src/main/java/jme3test/audio/TestOgg.java
index 2d2343c11..3e4099c66 100644
--- a/jme3-examples/src/main/java/jme3test/audio/TestOgg.java
+++ b/jme3-examples/src/main/java/jme3test/audio/TestOgg.java
@@ -33,6 +33,7 @@
package jme3test.audio;
import com.jme3.app.SimpleApplication;
+import com.jme3.audio.AudioData.DataType;
import com.jme3.audio.AudioNode;
import com.jme3.audio.AudioSource;
import com.jme3.audio.LowPassFilter;
@@ -49,7 +50,7 @@ public class TestOgg extends SimpleApplication {
@Override
public void simpleInitApp(){
System.out.println("Playing without filter");
- audioSource = new AudioNode(assetManager, "Sound/Effects/Foot steps.ogg", true);
+ audioSource = new AudioNode(assetManager, "Sound/Effects/Foot steps.ogg", DataType.Buffer);
audioSource.play();
}
@@ -59,7 +60,7 @@ public class TestOgg extends SimpleApplication {
audioRenderer.deleteAudioData(audioSource.getAudioData());
System.out.println("Playing with low pass filter");
- audioSource = new AudioNode(assetManager, "Sound/Effects/Foot steps.ogg", true);
+ audioSource = new AudioNode(assetManager, "Sound/Effects/Foot steps.ogg", DataType.Buffer);
audioSource.setDryFilter(new LowPassFilter(1f, .1f));
audioSource.setVolume(3);
audioSource.play();
diff --git a/jme3-examples/src/main/java/jme3test/awt/TestAwtPanels.java b/jme3-examples/src/main/java/jme3test/awt/TestAwtPanels.java
index 0f47d0c26..5c00e5008 100644
--- a/jme3-examples/src/main/java/jme3test/awt/TestAwtPanels.java
+++ b/jme3-examples/src/main/java/jme3test/awt/TestAwtPanels.java
@@ -90,7 +90,7 @@ public class TestAwtPanels extends SimpleApplication {
public void simpleInitApp() {
flyCam.setDragToRotate(true);
- Box b = new Box(Vector3f.ZERO, 1, 1, 1);
+ Box b = new Box(1, 1, 1);
Geometry geom = new Geometry("Box", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
diff --git a/jme3-examples/src/main/java/jme3test/awt/TestSafeCanvas.java b/jme3-examples/src/main/java/jme3test/awt/TestSafeCanvas.java
index 88451f5d7..6264f8246 100644
--- a/jme3-examples/src/main/java/jme3test/awt/TestSafeCanvas.java
+++ b/jme3-examples/src/main/java/jme3test/awt/TestSafeCanvas.java
@@ -59,7 +59,7 @@ public class TestSafeCanvas extends SimpleApplication {
public void simpleInitApp() {
flyCam.setDragToRotate(true);
- Box b = new Box(Vector3f.ZERO, 1, 1, 1);
+ Box b = new Box(1, 1, 1);
Geometry geom = new Geometry("Box", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
diff --git a/jme3-examples/src/main/java/jme3test/batching/TestBatchNode.java b/jme3-examples/src/main/java/jme3test/batching/TestBatchNode.java
index af0292864..db7e7a85e 100644
--- a/jme3-examples/src/main/java/jme3test/batching/TestBatchNode.java
+++ b/jme3-examples/src/main/java/jme3test/batching/TestBatchNode.java
@@ -82,7 +82,7 @@ public class TestBatchNode extends SimpleApplication {
* A cube with a color "bleeding" through transparent texture. Uses
* Texture from jme3-test-data library!
*/
- Box boxshape4 = new Box(Vector3f.ZERO, 1f, 1f, 1f);
+ Box boxshape4 = new Box(1f, 1f, 1f);
cube = new Geometry("cube1", boxshape4);
Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
cube.setMaterial(mat);
@@ -93,7 +93,7 @@ public class TestBatchNode extends SimpleApplication {
* A cube with a color "bleeding" through transparent texture. Uses
* Texture from jme3-test-data library!
*/
- Box box = new Box(Vector3f.ZERO, 1f, 1f, 1f);
+ Box box = new Box(1f, 1f, 1f);
cube2 = new Geometry("cube2", box);
cube2.setMaterial(mat);
diff --git a/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeCluster.java b/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeCluster.java
index 4559acfdc..3d88fb408 100644
--- a/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeCluster.java
+++ b/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeCluster.java
@@ -166,7 +166,7 @@ public class TestBatchNodeCluster extends SimpleApplication {
public void randomGenerator() {
for (int i = startAt; i < maxCubes - 1; i++) {
randomize();
- Geometry box = new Geometry("Box" + i, new Box(Vector3f.ZERO, 1, 1, 1));
+ Geometry box = new Geometry("Box" + i, new Box(1, 1, 1));
box.setLocalTranslation(new Vector3f(xPosition.get(xPosition.size() - 1),
yPosition.get(yPosition.size() - 1),
zPosition.get(zPosition.size() - 1)));
diff --git a/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeTower.java b/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeTower.java
index 0147c4435..a13dc6168 100644
--- a/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeTower.java
+++ b/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeTower.java
@@ -193,7 +193,7 @@ public class TestBatchNodeTower extends SimpleApplication {
}
public void initFloor() {
- Box floorBox = new Box(Vector3f.ZERO, 10f, 0.1f, 5f);
+ Box floorBox = new Box(10f, 0.1f, 5f);
floorBox.scaleTextureCoordinates(new Vector2f(3, 6));
Geometry floor = new Geometry("floor", floorBox);
diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestAttachDriver.java b/jme3-examples/src/main/java/jme3test/bullet/TestAttachDriver.java
index 8f9447ea1..1de5b0118 100644
--- a/jme3-examples/src/main/java/jme3test/bullet/TestAttachDriver.java
+++ b/jme3-examples/src/main/java/jme3test/bullet/TestAttachDriver.java
@@ -112,7 +112,7 @@ public class TestAttachDriver extends SimpleApplication implements ActionListene
tex.setMinFilter(Texture.MinFilter.Trilinear);
mat.setTexture("ColorMap", tex);
- Box floor = new Box(Vector3f.ZERO, 100, 1f, 100);
+ Box floor = new Box(100, 1f, 100);
Geometry floorGeom = new Geometry("Floor", floor);
floorGeom.setMaterial(mat);
floorGeom.setLocalTranslation(new Vector3f(0f, -3, 0f));
diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestBrickTower.java b/jme3-examples/src/main/java/jme3test/bullet/TestBrickTower.java
index bcadf623d..7b0df933d 100644
--- a/jme3-examples/src/main/java/jme3test/bullet/TestBrickTower.java
+++ b/jme3-examples/src/main/java/jme3test/bullet/TestBrickTower.java
@@ -126,7 +126,7 @@ public class TestBrickTower extends SimpleApplication {
bullet.setTextureMode(TextureMode.Projected);
bulletCollisionShape = new SphereCollisionShape(0.4f);
- brick = new Box(Vector3f.ZERO, brickWidth, brickHeight, brickDepth);
+ brick = new Box(brickWidth, brickHeight, brickDepth);
brick.scaleTextureCoordinates(new Vector2f(1f, .5f));
//bulletAppState.getPhysicsSpace().enableDebug(assetManager);
initMaterial();
@@ -204,7 +204,7 @@ public class TestBrickTower extends SimpleApplication {
}
public void initFloor() {
- Box floorBox = new Box(Vector3f.ZERO, 10f, 0.1f, 5f);
+ Box floorBox = new Box(10f, 0.1f, 5f);
floorBox.scaleTextureCoordinates(new Vector2f(3, 6));
Geometry floor = new Geometry("floor", floorBox);
diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestBrickWall.java b/jme3-examples/src/main/java/jme3test/bullet/TestBrickWall.java
index b190e8c6c..0173f1a44 100644
--- a/jme3-examples/src/main/java/jme3test/bullet/TestBrickWall.java
+++ b/jme3-examples/src/main/java/jme3test/bullet/TestBrickWall.java
@@ -90,7 +90,7 @@ public class TestBrickWall extends SimpleApplication {
bullet = new Sphere(32, 32, 0.4f, true, false);
bullet.setTextureMode(TextureMode.Projected);
bulletCollisionShape = new SphereCollisionShape(0.4f);
- brick = new Box(Vector3f.ZERO, bLength, bHeight, bWidth);
+ brick = new Box(bLength, bHeight, bWidth);
brick.scaleTextureCoordinates(new Vector2f(1f, .5f));
initMaterial();
@@ -151,7 +151,7 @@ public class TestBrickWall extends SimpleApplication {
}
public void initFloor() {
- Box floorBox = new Box(Vector3f.ZERO, 10f, 0.1f, 5f);
+ Box floorBox = new Box(10f, 0.1f, 5f);
floorBox.scaleTextureCoordinates(new Vector2f(3, 6));
Geometry floor = new Geometry("floor", floorBox);
diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestCcd.java b/jme3-examples/src/main/java/jme3test/bullet/TestCcd.java
index cda07bc85..58cb77c65 100644
--- a/jme3-examples/src/main/java/jme3test/bullet/TestCcd.java
+++ b/jme3-examples/src/main/java/jme3test/bullet/TestCcd.java
@@ -98,7 +98,7 @@ public class TestCcd extends SimpleApplication implements ActionListener {
Node node2 = new Node();
node2.setName("mesh");
node2.setLocalTranslation(new Vector3f(2.5f, 0, 0f));
- node2.addControl(new RigidBodyControl(new MeshCollisionShape(new Box(Vector3f.ZERO, 4, 4, 0.1f)), 0));
+ node2.addControl(new RigidBodyControl(new MeshCollisionShape(new Box(4, 4, 0.1f)), 0));
rootNode.attachChild(node2);
getPhysicsSpace().add(node2);
diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestCollisionGroups.java b/jme3-examples/src/main/java/jme3test/bullet/TestCollisionGroups.java
index 410c125d2..516345d47 100644
--- a/jme3-examples/src/main/java/jme3test/bullet/TestCollisionGroups.java
+++ b/jme3-examples/src/main/java/jme3test/bullet/TestCollisionGroups.java
@@ -85,7 +85,7 @@ public class TestCollisionGroups extends SimpleApplication {
getPhysicsSpace().add(node2);
// the floor, does not move (mass=0)
- Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Box(Vector3f.ZERO, 100f, 0.2f, 100f)), 0);
+ Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Box(100f, 0.2f, 100f)), 0);
node3.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -6, 0f));
rootNode.attachChild(node3);
getPhysicsSpace().add(node3);
diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestGhostObject.java b/jme3-examples/src/main/java/jme3test/bullet/TestGhostObject.java
index 74a7c1e1e..2ea1af0ab 100644
--- a/jme3-examples/src/main/java/jme3test/bullet/TestGhostObject.java
+++ b/jme3-examples/src/main/java/jme3test/bullet/TestGhostObject.java
@@ -65,7 +65,7 @@ public class TestGhostObject extends SimpleApplication {
bulletAppState.setDebugEnabled(true);
// Mesh to be shared across several boxes.
- Box boxGeom = new Box(Vector3f.ZERO, 1f, 1f, 1f);
+ Box boxGeom = new Box(1f, 1f, 1f);
// CollisionShape to be shared across several boxes.
CollisionShape shape = new BoxCollisionShape(new Vector3f(1, 1, 1));
diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java b/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java
index 9785ed250..5b9e948c8 100644
--- a/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java
+++ b/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java
@@ -139,7 +139,7 @@ public class TestRagdollCharacter extends SimpleApplication implements AnimEvent
}
public void initWall(float bLength, float bWidth, float bHeight) {
- Box brick = new Box(Vector3f.ZERO, bLength, bHeight, bWidth);
+ Box brick = new Box(bLength, bHeight, bWidth);
brick.scaleTextureCoordinates(new Vector2f(1f, .5f));
Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg");
diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java b/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java
index a66a6ecc1..c7e937c0b 100644
--- a/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java
+++ b/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java
@@ -171,7 +171,7 @@ public class TestWalkingChar extends SimpleApplication implements ActionListener
float zOff = -40;
float startpt = bLength / 4 - xOff;
float height = 6.1f;
- brick = new Box(Vector3f.ZERO, bLength, bHeight, bWidth);
+ brick = new Box(bLength, bHeight, bWidth);
brick.scaleTextureCoordinates(new Vector2f(1f, .5f));
for (int j = 0; j < 15; j++) {
for (int i = 0; i < 4; i++) {
diff --git a/jme3-examples/src/main/java/jme3test/collision/TestMousePick.java b/jme3-examples/src/main/java/jme3test/collision/TestMousePick.java
index f86f956b6..9f58b7fd8 100644
--- a/jme3-examples/src/main/java/jme3test/collision/TestMousePick.java
+++ b/jme3-examples/src/main/java/jme3test/collision/TestMousePick.java
@@ -107,8 +107,9 @@ public class TestMousePick extends SimpleApplication {
/** A cube object for target practice */
protected Geometry makeCube(String name, float x, float y, float z) {
- Box box = new Box(new Vector3f(x, y, z), 1, 1, 1);
+ Box box = new Box(1, 1, 1);
Geometry cube = new Geometry(name, box);
+ cube.setLocalTranslation(x, y, z);
Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat1.setColor("Color", ColorRGBA.randomColor());
cube.setMaterial(mat1);
@@ -117,8 +118,9 @@ public class TestMousePick extends SimpleApplication {
/** A floor to show that the "shot" can go through several objects. */
protected Geometry makeFloor() {
- Box box = new Box(new Vector3f(0, -4, -5), 15, .2f, 15);
+ Box box = new Box(15, .2f, 15);
Geometry floor = new Geometry("the Floor", box);
+ floor.setLocalTranslation(0, -4, -5);
Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat1.setColor("Color", ColorRGBA.Gray);
floor.setMaterial(mat1);
diff --git a/jme3-examples/src/main/java/jme3test/effect/TestEverything.java b/jme3-examples/src/main/java/jme3test/effect/TestEverything.java
index 2aca26f5e..be05958c3 100644
--- a/jme3-examples/src/main/java/jme3test/effect/TestEverything.java
+++ b/jme3-examples/src/main/java/jme3test/effect/TestEverything.java
@@ -123,11 +123,7 @@ public class TestEverything extends SimpleApplication {
public void setupFloor(){
Material mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m");
- mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat);
- mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat);
- mat.getTextureParam("ParallaxMap").getTextureValue().setWrap(WrapMode.Repeat);
-
- Box floor = new Box(Vector3f.ZERO, 50, 1f, 50);
+ Box floor = new Box(50, 1f, 50);
TangentBinormalGenerator.generate(floor);
floor.scaleTextureCoordinates(new Vector2f(5, 5));
Geometry floorGeom = new Geometry("Floor", floor);
diff --git a/jme3-examples/src/main/java/jme3test/effect/TestSoftParticles.java b/jme3-examples/src/main/java/jme3test/effect/TestSoftParticles.java
index 3d8f96d65..71504e51a 100644
--- a/jme3-examples/src/main/java/jme3test/effect/TestSoftParticles.java
+++ b/jme3-examples/src/main/java/jme3test/effect/TestSoftParticles.java
@@ -76,7 +76,7 @@ public class TestSoftParticles extends SimpleApplication {
// -------- floor
- Box b = new Box(Vector3f.ZERO, 10, 0.1f, 10);
+ Box b = new Box(10, 0.1f, 10);
Geometry geom = new Geometry("Box", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Gray);
@@ -84,7 +84,7 @@ public class TestSoftParticles extends SimpleApplication {
geom.setMaterial(mat);
rootNode.attachChild(geom);
- Box b2 = new Box(Vector3f.ZERO, 1, 1, 1);
+ Box b2 = new Box(1, 1, 1);
Geometry geom2 = new Geometry("Box", b2);
Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat2.setColor("Color", ColorRGBA.DarkGray);
diff --git a/jme3-examples/src/main/java/jme3test/games/CubeField.java b/jme3-examples/src/main/java/jme3test/games/CubeField.java
index fdad49de6..c166b5823 100644
--- a/jme3-examples/src/main/java/jme3test/games/CubeField.java
+++ b/jme3-examples/src/main/java/jme3test/games/CubeField.java
@@ -197,9 +197,9 @@ public class CubeField extends SimpleApplication implements AnalogListener {
private Geometry createFirstCube() {
Vector3f loc = player.getLocalTranslation();
loc.addLocal(4, 0, 0);
- Box b = new Box(loc, 1, 1, 1);
-
+ Box b = new Box(1, 1, 1);
Geometry geom = new Geometry("Box", b);
+ geom.setLocalTranslation(loc);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
geom.setMaterial(mat);
@@ -216,10 +216,15 @@ public class CubeField extends SimpleApplication implements AnalogListener {
playerMesh.setMaterial(playerMaterial);
playerMesh.setName("player");
- Box floor = new Box(Vector3f.ZERO.add(playerMesh.getLocalTranslation().getX(),
- playerMesh.getLocalTranslation().getY() - 1, 0), 100, 0, 100);
+ Box floor = new Box(100, 0, 100);
+
Geometry floorMesh = new Geometry("Box", floor);
+ Vector3f translation = Vector3f.ZERO.add(playerMesh.getLocalTranslation().getX(),
+ playerMesh.getLocalTranslation().getY() - 1, 0);
+
+ floorMesh.setLocalTranslation(translation);
+
floorMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
floorMaterial.setColor("Color", ColorRGBA.LightGray);
floorMesh.setMaterial(floorMaterial);
diff --git a/jme3-examples/src/main/java/jme3test/helloworld/HelloAssets.java b/jme3-examples/src/main/java/jme3test/helloworld/HelloAssets.java
index 9a3085016..4fb4738ac 100644
--- a/jme3-examples/src/main/java/jme3test/helloworld/HelloAssets.java
+++ b/jme3-examples/src/main/java/jme3test/helloworld/HelloAssets.java
@@ -60,7 +60,7 @@ public class HelloAssets extends SimpleApplication {
rootNode.attachChild(teapot);
/** Create a wall (Box with material and texture from test-data) */
- Box box = new Box(Vector3f.ZERO, 2.5f,2.5f,1.0f);
+ Box box = new Box(2.5f, 2.5f, 1.0f);
Spatial wall = new Geometry("Box", box );
Material mat_brick = new Material( assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat_brick.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));
diff --git a/jme3-examples/src/main/java/jme3test/helloworld/HelloInput.java b/jme3-examples/src/main/java/jme3test/helloworld/HelloInput.java
index 4cf09fe6e..c01bfb31c 100644
--- a/jme3-examples/src/main/java/jme3test/helloworld/HelloInput.java
+++ b/jme3-examples/src/main/java/jme3test/helloworld/HelloInput.java
@@ -57,7 +57,7 @@ public class HelloInput extends SimpleApplication {
@Override
public void simpleInitApp() {
- Box b = new Box(Vector3f.ZERO, 1, 1, 1);
+ Box b = new Box(1, 1, 1);
player = new Geometry("Player", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
diff --git a/jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java b/jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java
index 14f220374..7e5d30a6d 100644
--- a/jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java
+++ b/jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java
@@ -127,9 +127,10 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
t.setLocalTranslation(FastMath.nextRandomFloat() * 200f, FastMath.nextRandomFloat() * 30f + 20, 30f * (i + 2f));
}
- Box b = new Box(new Vector3f(0, 10, 550), 1000, 2, 1000);
+ Box b = new Box(1000, 2, 1000);
b.scaleTextureCoordinates(new Vector2f(10, 10));
ground = new Geometry("soil", b);
+ ground.setLocalTranslation(0, 10, 550);
matGroundU = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
matGroundU.setColor("Color", ColorRGBA.Green);
diff --git a/jme3-examples/src/main/java/jme3test/light/TestPssmShadow.java b/jme3-examples/src/main/java/jme3test/light/TestPssmShadow.java
index 55d5a3f87..9f851d39c 100644
--- a/jme3-examples/src/main/java/jme3test/light/TestPssmShadow.java
+++ b/jme3-examples/src/main/java/jme3test/light/TestPssmShadow.java
@@ -113,9 +113,10 @@ public class TestPssmShadow extends SimpleApplication implements ActionListener
t.setLocalTranslation(FastMath.nextRandomFloat() * 200f, FastMath.nextRandomFloat() * 30f + 20, 30f * (i + 2f));
}
- Box b = new Box(new Vector3f(0, 10, 550), 1000, 2, 1000);
+ Box b = new Box(1000, 2, 1000);
b.scaleTextureCoordinates(new Vector2f(10, 10));
ground = new Geometry("soil", b);
+ ground.setLocalTranslation(0, 10, 550);
matGroundU = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
matGroundU.setColor("Color", ColorRGBA.Green);
diff --git a/jme3-examples/src/main/java/jme3test/light/TestShadow.java b/jme3-examples/src/main/java/jme3test/light/TestShadow.java
index db0c3768f..d3c7122fb 100644
--- a/jme3-examples/src/main/java/jme3test/light/TestShadow.java
+++ b/jme3-examples/src/main/java/jme3test/light/TestShadow.java
@@ -76,7 +76,7 @@ public class TestShadow extends SimpleApplication {
Material mat = assetManager.loadMaterial("Common/Materials/WhiteColor.j3m");
rootNode.setShadowMode(ShadowMode.Off);
- Box floor = new Box(Vector3f.ZERO, 3, 0.1f, 3);
+ Box floor = new Box(3, 0.1f, 3);
Geometry floorGeom = new Geometry("Floor", floor);
floorGeom.setMaterial(mat);
floorGeom.setLocalTranslation(0,-0.2f,0);
diff --git a/jme3-examples/src/main/java/jme3test/light/TestShadowsPerf.java b/jme3-examples/src/main/java/jme3test/light/TestShadowsPerf.java
index e9ca341b8..f267b1d41 100644
--- a/jme3-examples/src/main/java/jme3test/light/TestShadowsPerf.java
+++ b/jme3-examples/src/main/java/jme3test/light/TestShadowsPerf.java
@@ -83,7 +83,7 @@ public class TestShadowsPerf extends SimpleApplication {
mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
- Box b = new Box(Vector3f.ZERO, 800, 1, 700);
+ Box b = new Box(800, 1, 700);
b.scaleTextureCoordinates(new Vector2f(50, 50));
Geometry ground = new Geometry("ground", b);
ground.setMaterial(mat);
diff --git a/jme3-examples/src/main/java/jme3test/light/TestSpotLight.java b/jme3-examples/src/main/java/jme3test/light/TestSpotLight.java
index 7a6f35c37..0cd4512cd 100644
--- a/jme3-examples/src/main/java/jme3test/light/TestSpotLight.java
+++ b/jme3-examples/src/main/java/jme3test/light/TestSpotLight.java
@@ -100,7 +100,7 @@ public class TestSpotLight extends SimpleApplication {
// mat.setBoolean("VertexLighting", true);
- Box floor = new Box(Vector3f.ZERO, 50, 1f, 50);
+ Box floor = new Box(50, 1f, 50);
TangentBinormalGenerator.generate(floor);
floor.scaleTextureCoordinates(new Vector2f(5, 5));
Geometry floorGeom = new Geometry("Floor", floor);
diff --git a/jme3-examples/src/main/java/jme3test/light/TestSpotLightShadows.java b/jme3-examples/src/main/java/jme3test/light/TestSpotLightShadows.java
index 8df514fd3..52a5dc8c5 100644
--- a/jme3-examples/src/main/java/jme3test/light/TestSpotLightShadows.java
+++ b/jme3-examples/src/main/java/jme3test/light/TestSpotLightShadows.java
@@ -148,7 +148,7 @@ public class TestSpotLightShadows extends SimpleApplication {
// mat.setBoolean("VertexLighting", true);
- Box floor = new Box(Vector3f.ZERO, 50, 1f, 50);
+ Box floor = new Box(50, 1f, 50);
TangentBinormalGenerator.generate(floor);
floor.scaleTextureCoordinates(new Vector2f(5, 5));
Geometry floorGeom = new Geometry("Floor", floor);
diff --git a/jme3-examples/src/main/java/jme3test/material/TestMatParamOverride.java b/jme3-examples/src/main/java/jme3test/material/TestMatParamOverride.java
new file mode 100644
index 000000000..224290f25
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/material/TestMatParamOverride.java
@@ -0,0 +1,92 @@
+/*
+ * 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 jme3test.material;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.MatParamOverride;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+import com.jme3.shader.VarType;
+
+/**
+ * Test if {@link MatParamOverride}s are working correctly.
+ *
+ * @author Kirill Vainer
+ */
+public class TestMatParamOverride extends SimpleApplication {
+
+ private Box box = new Box(1, 1, 1);
+ private MatParamOverride override = new MatParamOverride(VarType.Vector4, "Color", ColorRGBA.Yellow);
+
+ public static void main(String[] args) {
+ TestMatParamOverride app = new TestMatParamOverride();
+ app.start();
+ }
+
+ private void createBox(float location, ColorRGBA color) {
+ Geometry geom = new Geometry("Box", box);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setColor("Color", color);
+ geom.setMaterial(mat);
+ geom.move(location, 0, 0);
+ rootNode.attachChild(geom);
+ }
+
+ @Override
+ public void simpleInitApp() {
+ inputManager.setCursorVisible(true);
+
+ createBox(-3, ColorRGBA.Red);
+ createBox(0, ColorRGBA.Green);
+ createBox(3, ColorRGBA.Blue);
+
+ inputManager.addMapping("override", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("override") && isPressed) {
+ if (!rootNode.getLocalMatParamOverrides().isEmpty()) {
+ rootNode.clearMatParamOverrides();
+ } else {
+ rootNode.addMatParamOverride(override);
+ }
+ System.out.println(rootNode.getLocalMatParamOverrides());
+ }
+ }
+ }, "override");
+ }
+}
diff --git a/jme3-examples/src/main/java/jme3test/material/TestParallax.java b/jme3-examples/src/main/java/jme3test/material/TestParallax.java
index f5af57f1f..cf5263ed2 100644
--- a/jme3-examples/src/main/java/jme3test/material/TestParallax.java
+++ b/jme3-examples/src/main/java/jme3test/material/TestParallax.java
@@ -71,8 +71,7 @@ public class TestParallax extends SimpleApplication {
Material mat;
public void setupFloor() {
- mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall2.j3m");
- //mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m");
+ mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m");
Node floorGeom = new Node("floorGeom");
Quad q = new Quad(100, 100);
diff --git a/jme3-examples/src/main/java/jme3test/material/TestShaderNodes.java b/jme3-examples/src/main/java/jme3test/material/TestShaderNodes.java
index db8a21c97..a580f54ed 100644
--- a/jme3-examples/src/main/java/jme3test/material/TestShaderNodes.java
+++ b/jme3-examples/src/main/java/jme3test/material/TestShaderNodes.java
@@ -3,6 +3,7 @@ package jme3test.material;
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.material.Technique;
+import com.jme3.material.TechniqueDef;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
@@ -27,12 +28,12 @@ public class TestShaderNodes extends SimpleApplication {
Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg");
Material mat = new Material(assetManager, "Common/MatDefs/Misc/UnshadedNodes.j3md");
- mat.selectTechnique("Default", renderManager);
+ mat.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager);
Technique t = mat.getActiveTechnique();
- for (Shader.ShaderSource shaderSource : t.getShader().getSources()) {
- System.out.println(shaderSource.getSource());
- }
+// for (Shader.ShaderSource shaderSource : t.getShader().getSources()) {
+// System.out.println(shaderSource.getSource());
+// }
mat.setColor("Color", ColorRGBA.Yellow);
diff --git a/jme3-examples/src/main/java/jme3test/model/shape/TestBillboard.java b/jme3-examples/src/main/java/jme3test/model/shape/TestBillboard.java
index ba7acb1f7..8fa8a66f1 100644
--- a/jme3-examples/src/main/java/jme3test/model/shape/TestBillboard.java
+++ b/jme3-examples/src/main/java/jme3test/model/shape/TestBillboard.java
@@ -64,8 +64,9 @@ public class TestBillboard extends SimpleApplication {
g3.setMaterial(mat2);
g3.setLocalTranslation(.5f, .5f, .01f);
- Box b = new Box(new Vector3f(0, 0, 3), .25f, .5f, .25f);
+ Box b = new Box(.25f, .5f, .25f);
Geometry g2 = new Geometry("Box", b);
+ g2.setLocalTranslation(0, 0, 3);
g2.setMaterial(mat);
Node bb = new Node("billboard");
diff --git a/jme3-examples/src/main/java/jme3test/model/shape/TestBox.java b/jme3-examples/src/main/java/jme3test/model/shape/TestBox.java
index 19d26b5ac..0e5e86aef 100644
--- a/jme3-examples/src/main/java/jme3test/model/shape/TestBox.java
+++ b/jme3-examples/src/main/java/jme3test/model/shape/TestBox.java
@@ -34,7 +34,6 @@ package jme3test.model.shape;
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
-import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
diff --git a/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyGui.java b/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyGui.java
index fe9171c92..3d2e67b5f 100644
--- a/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyGui.java
+++ b/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyGui.java
@@ -54,7 +54,7 @@ public class TestNiftyGui extends SimpleApplication implements ScreenController
@Override
public void simpleInitApp() {
- Box b = new Box(Vector3f.ZERO, 1, 1, 1);
+ Box b = new Box(1, 1, 1);
Geometry geom = new Geometry("Box", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
diff --git a/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyToMesh.java b/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyToMesh.java
index ef82f263d..ce3832c73 100644
--- a/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyToMesh.java
+++ b/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyToMesh.java
@@ -79,7 +79,7 @@ public class TestNiftyToMesh extends SimpleApplication{
niftyView.setClearFlags(true, true, true);
niftyView.setOutputFrameBuffer(fb);
- Box b = new Box(Vector3f.ZERO, 1, 1, 1);
+ Box b = new Box(1, 1, 1);
Geometry geom = new Geometry("Box", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", tex);
diff --git a/jme3-examples/src/main/java/jme3test/post/TestBloom.java b/jme3-examples/src/main/java/jme3test/post/TestBloom.java
index b73d234d7..1a394bf36 100644
--- a/jme3-examples/src/main/java/jme3test/post/TestBloom.java
+++ b/jme3-examples/src/main/java/jme3test/post/TestBloom.java
@@ -102,7 +102,8 @@ public class TestBloom extends SimpleApplication {
- Geometry soil=new Geometry("soil", new Box(new Vector3f(0, -13, 550), 800, 10, 700));
+ Geometry soil = new Geometry("soil", new Box(800, 10, 700));
+ soil.setLocalTranslation(0, -13, 550);
soil.setMaterial(matSoil);
soil.setShadowMode(ShadowMode.CastAndReceive);
rootNode.attachChild(soil);
diff --git a/jme3-examples/src/main/java/jme3test/post/TestCrossHatch.java b/jme3-examples/src/main/java/jme3test/post/TestCrossHatch.java
index 2164ec229..ff3ef081c 100644
--- a/jme3-examples/src/main/java/jme3test/post/TestCrossHatch.java
+++ b/jme3-examples/src/main/java/jme3test/post/TestCrossHatch.java
@@ -102,7 +102,8 @@ public class TestCrossHatch extends SimpleApplication {
- Geometry soil=new Geometry("soil", new Box(new Vector3f(0, -13, 550), 800, 10, 700));
+ Geometry soil = new Geometry("soil", new Box(800, 10, 700));
+ soil.setLocalTranslation(0, -13, 550);
soil.setMaterial(matSoil);
soil.setShadowMode(ShadowMode.CastAndReceive);
rootNode.attachChild(soil);
diff --git a/jme3-examples/src/main/java/jme3test/post/TestPostFilters.java b/jme3-examples/src/main/java/jme3test/post/TestPostFilters.java
index 4ad419668..3ab2ae295 100644
--- a/jme3-examples/src/main/java/jme3test/post/TestPostFilters.java
+++ b/jme3-examples/src/main/java/jme3test/post/TestPostFilters.java
@@ -107,10 +107,7 @@ public class TestPostFilters extends SimpleApplication implements ActionListener
public void setupFloor() {
Material mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m");
- mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat);
- mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat);
- mat.getTextureParam("ParallaxMap").getTextureValue().setWrap(WrapMode.Repeat);
- Box floor = new Box(Vector3f.ZERO, 50, 1f, 50);
+ Box floor = new Box(50, 1f, 50);
TangentBinormalGenerator.generate(floor);
floor.scaleTextureCoordinates(new Vector2f(5, 5));
Geometry floorGeom = new Geometry("Floor", floor);
diff --git a/jme3-examples/src/main/java/jme3test/post/TestPosterization.java b/jme3-examples/src/main/java/jme3test/post/TestPosterization.java
index 4200ad463..ff8cf7ee8 100644
--- a/jme3-examples/src/main/java/jme3test/post/TestPosterization.java
+++ b/jme3-examples/src/main/java/jme3test/post/TestPosterization.java
@@ -102,7 +102,8 @@ public class TestPosterization extends SimpleApplication {
- Geometry soil=new Geometry("soil", new Box(new Vector3f(0, -13, 550), 800, 10, 700));
+ Geometry soil = new Geometry("soil", new Box(800, 10, 700));
+ soil.setLocalTranslation(0, -13, 550);
soil.setMaterial(matSoil);
soil.setShadowMode(ShadowMode.CastAndReceive);
rootNode.attachChild(soil);
diff --git a/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java b/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java
index ad0172511..17b22d167 100644
--- a/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java
+++ b/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java
@@ -116,7 +116,7 @@ public class TestRenderToMemory extends SimpleApplication implements SceneProces
frames ++;
t = t2;
- if (total > 1000){
+ if (total > timer.getResolution()) {
fps = frames;
total = 0;
frames = 0;
@@ -202,7 +202,7 @@ public class TestRenderToMemory extends SimpleApplication implements SceneProces
offView.setOutputFrameBuffer(offBuffer);
// setup framebuffer's scene
- Box boxMesh = new Box(Vector3f.ZERO, 1,1,1);
+ Box boxMesh = new Box(1, 1, 1);
Material material = assetManager.loadMaterial("Interface/Logo/Logo.j3m");
offBox = new Geometry("box", boxMesh);
offBox.setMaterial(material);
diff --git a/jme3-examples/src/main/java/jme3test/post/TestRenderToTexture.java b/jme3-examples/src/main/java/jme3test/post/TestRenderToTexture.java
index ba872831a..037c959d3 100644
--- a/jme3-examples/src/main/java/jme3test/post/TestRenderToTexture.java
+++ b/jme3-examples/src/main/java/jme3test/post/TestRenderToTexture.java
@@ -93,7 +93,7 @@ public class TestRenderToTexture extends SimpleApplication implements ActionList
offView.setOutputFrameBuffer(offBuffer);
// setup framebuffer's scene
- Box boxMesh = new Box(Vector3f.ZERO, 1,1,1);
+ Box boxMesh = new Box(1, 1, 1);
Material material = assetManager.loadMaterial("Interface/Logo/Logo.j3m");
offBox = new Geometry("box", boxMesh);
offBox.setMaterial(material);
@@ -110,7 +110,7 @@ public class TestRenderToTexture extends SimpleApplication implements ActionList
cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
//setup main scene
- Geometry quad = new Geometry("box", new Box(Vector3f.ZERO, 1,1,1));
+ Geometry quad = new Geometry("box", new Box(1, 1, 1));
Texture offTex = setupOffscreenView();
diff --git a/jme3-examples/src/main/java/jme3test/renderer/TestBlendEquations.java b/jme3-examples/src/main/java/jme3test/renderer/TestBlendEquations.java
new file mode 100644
index 000000000..9335912b6
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderer/TestBlendEquations.java
@@ -0,0 +1,110 @@
+/*
+ * 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 jme3test.renderer;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.material.RenderState;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Quad;
+
+public class TestBlendEquations extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestBlendEquations app = new TestBlendEquations();
+ app.start();
+ }
+
+ public void simpleInitApp() {
+ Geometry teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
+ teaGeom.scale(6);
+ teaGeom.getMaterial().getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.Add);
+ teaGeom.move(0, -2f, 0);
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setColor(ColorRGBA.Red);
+ dl.setDirection(Vector3f.UNIT_XYZ.negate());
+
+ rootNode.addLight(dl);
+ rootNode.attachChild(teaGeom);
+
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setColor("Color", new ColorRGBA(0.5f, 0f, 1f, 0.3f));
+ mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Color);
+ mat.getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.Subtract);
+
+ Geometry geo = new Geometry("BottomLeft", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2));
+ geo.setMaterial(mat);
+ geo.setQueueBucket(RenderQueue.Bucket.Gui);
+ geo.setLocalTranslation(0, 0, 1);
+
+ guiNode.attachChild(geo);
+
+ Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ m.getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.ReverseSubtract);
+ m.setColor("Color", new ColorRGBA(0.0f, 1f, 1.f, 1f));
+ m.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.AlphaAdditive);
+
+ geo = new Geometry("BottomRight", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2));
+ geo.setMaterial(m);
+ geo.setQueueBucket(RenderQueue.Bucket.Gui);
+ geo.setLocalTranslation(guiViewPort.getCamera().getWidth() / 2, 0, 1);
+
+ guiNode.attachChild(geo);
+
+ m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ m.getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.Min);
+ m.setColor("Color", new ColorRGBA(0.3f, 0f, 0.1f, 0.3f));
+ m.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Additive);
+
+ geo = new Geometry("TopRight", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2));
+ geo.setMaterial(m);
+ geo.setQueueBucket(RenderQueue.Bucket.Gui);
+ geo.setLocalTranslation(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2, 1);
+
+ guiNode.attachChild(geo);
+
+ geo = new Geometry("OverTeaPot", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2));
+ geo.setMaterial(mat);
+ geo.setQueueBucket(RenderQueue.Bucket.Transparent);
+ geo.setLocalTranslation(0, -100, 5);
+
+ rootNode.attachChild(geo);
+
+ }
+
+
+}
diff --git a/jme3-examples/src/main/java/jme3test/texture/TestAnisotropicFilter.java b/jme3-examples/src/main/java/jme3test/texture/TestAnisotropicFilter.java
new file mode 100755
index 000000000..c8633f596
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/texture/TestAnisotropicFilter.java
@@ -0,0 +1,116 @@
+package jme3test.texture;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.app.state.ScreenshotAppState;
+import com.jme3.asset.AssetManager;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.Limits;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Quad;
+import com.jme3.texture.Image;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture2D;
+import com.jme3.texture.image.ColorSpace;
+import com.jme3.texture.image.ImageRaster;
+import com.jme3.util.BufferUtils;
+
+public class TestAnisotropicFilter extends SimpleApplication implements ActionListener {
+
+ private int globalAniso = 1;
+ private int maxAniso = 1;
+
+ @Override
+ public void simpleInitApp() {
+ maxAniso = renderer.getLimits().get(Limits.TextureAnisotropy);
+
+ flyCam.setDragToRotate(true);
+ flyCam.setMoveSpeed(100);
+ cam.setLocation(new Vector3f(197.02617f, 4.6769195f, -194.89545f));
+ cam.setRotation(new Quaternion(0.07921988f, 0.8992258f, -0.18292196f, 0.38943136f));
+ Quad q = new Quad(1000, 1000);
+ q.scaleTextureCoordinates(new Vector2f(1000, 1000));
+ Geometry geom = new Geometry("quad", q);
+ geom.rotate(-FastMath.HALF_PI, 0, 0);
+ geom.setMaterial(createCheckerBoardMaterial(assetManager));
+ rootNode.attachChild(geom);
+
+ inputManager.addMapping("higher", new KeyTrigger(KeyInput.KEY_1));
+ inputManager.addMapping("lower", new KeyTrigger(KeyInput.KEY_2));
+ inputManager.addListener(this, "higher");
+ inputManager.addListener(this, "lower");
+ }
+
+ private static Material createCheckerBoardMaterial(AssetManager assetManager) {
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ Texture tex = createCheckerBoardTexture(); // assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.dds");
+ tex.setMagFilter(Texture.MagFilter.Bilinear);
+ tex.setMinFilter(Texture.MinFilter.Trilinear);
+ tex.setWrap(Texture.WrapMode.Repeat);
+ mat.setTexture("ColorMap", tex);
+ return mat;
+ }
+
+ private static Texture2D createCheckerBoardTexture() {
+ Image image = new Image(Format.RGBA8, 1024, 1024, BufferUtils.createByteBuffer(1024 * 1024 * 4), ColorSpace.sRGB);
+
+ ImageRaster raster = ImageRaster.create(image);
+ for (int y = 0; y < 1024; y++) {
+ for (int x = 0; x < 1024; x++) {
+ if (y < 512) {
+ if (x < 512) {
+ raster.setPixel(x, y, ColorRGBA.Black);
+ } else {
+ raster.setPixel(x, y, ColorRGBA.White);
+ }
+ } else {
+ if (x < 512) {
+ raster.setPixel(x, y, ColorRGBA.White);
+ } else {
+ raster.setPixel(x, y, ColorRGBA.Black);
+ }
+ }
+ }
+ }
+
+ return new Texture2D(image);
+ }
+
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (isPressed) {
+ return;
+ }
+ switch (name) {
+ case "higher":
+ globalAniso++;
+ if (globalAniso > 32) {
+ globalAniso = 32;
+ }
+ renderer.setDefaultAnisotropicFilter(globalAniso);
+ System.out.format("Global Aniso: %d / %d\r\n", globalAniso, maxAniso);
+ break;
+ case "lower":
+ globalAniso--;
+ if (globalAniso < 1) {
+ globalAniso = 1;
+ }
+ renderer.setDefaultAnisotropicFilter(globalAniso);
+ System.out.format("Global Aniso: %d / %d\r\n", globalAniso, maxAniso);
+ break;
+ }
+ }
+
+ public static void main(String[] args) {
+ TestAnisotropicFilter app = new TestAnisotropicFilter();
+ app.start();
+ }
+}
diff --git a/jme3-examples/src/main/java/jme3test/water/TestPostWater.java b/jme3-examples/src/main/java/jme3test/water/TestPostWater.java
index a03aeb393..a4d557f78 100644
--- a/jme3-examples/src/main/java/jme3test/water/TestPostWater.java
+++ b/jme3-examples/src/main/java/jme3test/water/TestPostWater.java
@@ -194,7 +194,7 @@ public class TestPostWater extends SimpleApplication {
private void createBox() {
//creating a transluscent box
- box = new Geometry("box", new Box(new Vector3f(0, 0, 0), 50, 50, 50));
+ box = new Geometry("box", new Box(50, 50, 50));
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", new ColorRGBA(1.0f, 0, 0, 0.3f));
mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
diff --git a/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java b/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java
index a9398f159..958163596 100644
--- a/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java
+++ b/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java
@@ -78,6 +78,11 @@ public class IosGL implements GL, GLExt, GLFbo {
checkLimit(buffer);
return buffer.limit() / elementSize;
}
+
+ @Override
+ public void glBlendEquationSeparate(int colorMode, int alphaMode) {
+ JmeIosGLES.glBlendEquationSeparate(colorMode, alphaMode);
+ }
private int toArray(IntBuffer buffer) {
int remain = buffer.remaining();
diff --git a/jme3-ios/src/main/java/com/jme3/renderer/ios/JmeIosGLES.java b/jme3-ios/src/main/java/com/jme3/renderer/ios/JmeIosGLES.java
index 0811dc422..b8ec75a77 100644
--- a/jme3-ios/src/main/java/com/jme3/renderer/ios/JmeIosGLES.java
+++ b/jme3-ios/src/main/java/com/jme3/renderer/ios/JmeIosGLES.java
@@ -142,6 +142,7 @@ public class JmeIosGLES {
public static native void glBindRenderbuffer(int target, int renderbuffer);
public static native void glBindTexture(int target, int texture);
// public static native void glBindVertexArray // TODO: Investigate this
+ public static native void glBlendEquationSeparate(int colorMode, int alphaMode);
public static native void glBlendFunc(int sfactor, int dfactor);
public static native void glBufferData(int target, int size, Buffer data, int usage);
public static native void glBufferData2(int target, int size, byte[] data, int offset, int usage);
diff --git a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java
index 2ca2fb266..8b222d751 100644
--- a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java
+++ b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java
@@ -78,6 +78,11 @@ public class JoglGL implements GL, GL2, GL3, GL4 {
GLContext.getCurrentGL().glBindTexture(param1, param2);
}
+ @Override
+ public void glBlendEquationSeparate(int colorMode, int alphaMode){
+ GLContext.getCurrentGL().glBlendEquationSeparate(colorMode, alphaMode);
+ }
+
@Override
public void glBlendFunc(int param1, int param2) {
GLContext.getCurrentGL().glBlendFunc(param1, param2);
diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglAbstractDisplay.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglAbstractDisplay.java
index 3b468f1aa..c4f38f970 100644
--- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglAbstractDisplay.java
+++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglAbstractDisplay.java
@@ -77,8 +77,6 @@ public abstract class JoglAbstractDisplay extends JoglContext implements GLEvent
protected boolean wasAnimating = false;
protected void initGLCanvas() {
- loadNatives();
-
device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
GLCapabilities caps;
diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java
index 3ed543bc9..24a647ef6 100644
--- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java
+++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java
@@ -53,8 +53,6 @@ import com.jme3.renderer.opengl.GLTracer;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeContext;
import com.jme3.system.NanoTimer;
-import com.jme3.system.NativeLibraryLoader;
-import com.jme3.system.NullRenderer;
import com.jme3.system.SystemListener;
import com.jme3.system.Timer;
@@ -86,13 +84,6 @@ public abstract class JoglContext implements JmeContext {
protected MouseInput mouseInput;
protected JoyInput joyInput;
- public void loadNatives() {
- // Not sure if need to load OpenAL here ...
- if (NativeLibraryLoader.isUsingNativeBullet()) {
- NativeLibraryLoader.loadNativeLibrary("bulletjme", true);
- }
- }
-
@Override
public void setSystemListener(SystemListener listener){
this.listener = listener;
diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtAbstractDisplay.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtAbstractDisplay.java
index 9c7a49d17..48f191cb3 100644
--- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtAbstractDisplay.java
+++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtAbstractDisplay.java
@@ -73,7 +73,6 @@ public abstract class JoglNewtAbstractDisplay extends JoglContext implements GLE
protected boolean wasAnimating = false;
protected void initGLCanvas() {
- loadNatives();
GLCapabilities caps;
if (settings.getRenderer().equals(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE)) {
caps = new GLCapabilities(GLProfile.getMaxProgrammable(true));
diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java
index 56aa2d53f..54fa3b552 100644
--- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java
+++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java
@@ -123,8 +123,7 @@ public class JoglOffscreenBuffer extends JoglContext implements Runnable {
}
@Override
- public void run(){
- loadNatives();
+ public void run() {
logger.log(Level.FINE, "Using JOGL {0}", JoglVersion.getInstance().getImplementationVersion());
initInThread();
while (!needClose.get()){
diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java
index 6f640042f..abc419c41 100644
--- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java
+++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java
@@ -50,6 +50,10 @@ public final class LwjglGL implements GL, GL2, GL3, GL4 {
GL11.glBindTexture(param1, param2);
}
+ public void glBlendEquationSeparate(int colorMode, int alphaMode){
+ GL20.glBlendEquationSeparate(colorMode,alphaMode);
+ }
+
public void glBlendFunc(int param1, int param2) {
GL11.glBlendFunc(param1, param2);
}
diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java
index 3f1139886..be3014da5 100644
--- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java
+++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java
@@ -29,6 +29,7 @@
* 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.system.lwjgl;
import com.jme3.input.lwjgl.JInputJoyInput;
@@ -69,7 +70,6 @@ public abstract class LwjglContext implements JmeContext {
private static final Logger logger = Logger.getLogger(LwjglContext.class.getName());
protected static final String THREAD_NAME = "jME3 Main";
-
protected AtomicBoolean created = new AtomicBoolean(false);
protected AtomicBoolean renderable = new AtomicBoolean(false);
protected final Object createdLock = new Object();
@@ -113,7 +113,6 @@ public abstract class LwjglContext implements JmeContext {
return null;
}
}
-
protected int determineMaxSamples(int requestedSamples) {
try {
// If we already have a valid context, determine samples using current
@@ -131,13 +130,11 @@ public abstract class LwjglContext implements JmeContext {
} catch (LWJGLException ex) {
listener.handleError("Failed to check if display is current", ex);
}
-
if ((Pbuffer.getCapabilities() & Pbuffer.PBUFFER_SUPPORTED) == 0) {
// No pbuffer, assume everything is supported.
return Integer.MAX_VALUE;
} else {
Pbuffer pb = null;
-
// OpenGL2 method: Create pbuffer and query samples
// from GL_ARB_framebuffer_object or GL_EXT_framebuffer_multisample.
try {
@@ -162,7 +159,6 @@ public abstract class LwjglContext implements JmeContext {
}
}
}
-
protected void loadNatives() {
if (JmeSystem.isLowPermissions()) {
return;
@@ -174,12 +170,8 @@ public abstract class LwjglContext implements JmeContext {
NativeLibraryLoader.loadNativeLibrary("jinput", true);
NativeLibraryLoader.loadNativeLibrary("jinput-dx8", true);
}
- if (NativeLibraryLoader.isUsingNativeBullet()) {
- NativeLibraryLoader.loadNativeLibrary("bulletjme", true);
- }
NativeLibraryLoader.loadNativeLibrary("lwjgl", true);
}
-
protected int getNumSamplesToUse() {
int samples = 0;
if (settings.getSamples() > 1) {
@@ -190,7 +182,6 @@ public abstract class LwjglContext implements JmeContext {
"Couldn''t satisfy antialiasing samples requirement: x{0}. "
+ "Video hardware only supports: x{1}",
new Object[]{samples, supportedSamples});
-
samples = supportedSamples;
}
}
@@ -202,48 +193,43 @@ public abstract class LwjglContext implements JmeContext {
throw new RendererException("OpenGL 2.0 or higher is "
+ "required for jMonkeyEngine");
}
-
+
if (settings.getRenderer().equals(AppSettings.LWJGL_OPENGL2)
|| settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)) {
GL gl = new LwjglGL();
GLExt glext = new LwjglGLExt();
GLFbo glfbo;
-
+
if (GLContext.getCapabilities().OpenGL30) {
glfbo = new LwjglGLFboGL3();
} else {
glfbo = new LwjglGLFboEXT();
}
-
+
if (settings.getBoolean("GraphicsDebug")) {
gl = new GLDebugDesktop(gl, glext, glfbo);
glext = (GLExt) gl;
glfbo = (GLFbo) gl;
}
-
if (settings.getBoolean("GraphicsTiming")) {
GLTimingState timingState = new GLTimingState();
gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class);
glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class);
glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class);
}
-
if (settings.getBoolean("GraphicsTrace")) {
gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class);
glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class);
glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class);
}
-
renderer = new GLRenderer(gl, glext, glfbo);
renderer.initialize();
} else {
throw new UnsupportedOperationException("Unsupported renderer: " + settings.getRenderer());
}
-
if (GLContext.getCapabilities().GL_ARB_debug_output && settings.getBoolean("GraphicsDebug")) {
ARBDebugOutput.glDebugMessageCallbackARB(new ARBDebugOutputCallback(new LwjglGLDebugOutputHandler()));
}
-
renderer.setMainFrameBufferSrgb(settings.isGammaCorrection());
renderer.setLinearizeSrgbImages(settings.isGammaCorrection());
@@ -270,15 +256,12 @@ public abstract class LwjglContext implements JmeContext {
createdLock.notifyAll();
}
}
-
public void internalCreate() {
timer = new LwjglTimer();
-
synchronized (createdLock) {
created.set(true);
createdLock.notifyAll();
}
-
if (renderable.get()) {
initContextFirstTime();
} else {
@@ -308,7 +291,6 @@ public abstract class LwjglContext implements JmeContext {
public boolean isCreated() {
return created.get();
}
-
public boolean isRenderable() {
return renderable.get();
}
diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java
index 25de6b148..10358c009 100644
--- a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java
+++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java
@@ -79,6 +79,10 @@ public class LwjglGL implements GL, GL2, GL3, GL4 {
GL11.glBindTexture(param1, param2);
}
+ public void glBlendEquationSeparate(int colorMode, int alphaMode){
+ GL20.glBlendEquationSeparate(colorMode,alphaMode);
+ }
+
public void glBlendFunc(int param1, int param2) {
GL11.glBlendFunc(param1, param2);
}
diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java
index 0fe8a7b23..20532df36 100644
--- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java
+++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java
@@ -116,17 +116,6 @@ public abstract class LwjglContext implements JmeContext {
return samples;
}
- protected void loadNatives() {
- if (JmeSystem.isLowPermissions()) {
- return;
- }
-
- if (NativeLibraryLoader.isUsingNativeBullet()) {
- NativeLibraryLoader.loadNativeLibrary("bulletjme", true);
- }
- }
-
-
protected void initContextFirstTime() {
final GLCapabilities capabilities = createCapabilities(settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3));
diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java
index aaa24ce42..cac8ecdd1 100644
--- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java
+++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java
@@ -315,8 +315,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
});
}
- loadNatives();
-
timer = new NanoTimer();
// For canvas, this will create a pbuffer,
diff --git a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/SceneLoader.java b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/SceneLoader.java
index 491301c22..87e13abed 100644
--- a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/SceneLoader.java
+++ b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/SceneLoader.java
@@ -803,9 +803,7 @@ public class SceneLoader implements AssetLoader {
m.setColor("Diffuse", new ColorRGBA(data.diffuseColor.x, data.diffuseColor.y, data.diffuseColor.z, 1));
m.setColor("Specular", new ColorRGBA(data.specularColor.x, data.specularColor.y, data.specularColor.z, 1));
m.setFloat("Shininess", data.shininessExponent);
- m.setBoolean("UseMaterialColors", true);
- m.getAdditionalRenderState().setAlphaTest(true);
- m.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
+ m.setBoolean("UseMaterialColors", true);
return m;
}
diff --git a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/obj/FbxObjectFactory.java b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/obj/FbxObjectFactory.java
index ec8c1fd67..111750df1 100644
--- a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/obj/FbxObjectFactory.java
+++ b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/obj/FbxObjectFactory.java
@@ -74,6 +74,12 @@ public final class FbxObjectFactory {
subclassName.equals("FKEffector")) {
// jME3 does not support IK.
return FbxNullAttribute.class;
+ } else if (subclassName.equals("Light")) {
+ // TODO: support lights
+ return FbxNullAttribute.class;
+ } else if (subclassName.equals("Camera")) {
+ // TODO: support cameras
+ return FbxNullAttribute.class;
} else {
// NodeAttribute - Unknown
logger.log(Level.WARNING, "Unknown object subclass: {0}. Ignoring.", subclassName);
diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/GeoMap.java b/jme3-terrain/src/main/java/com/jme3/terrain/GeoMap.java
index 21b222023..efa823c66 100644
--- a/jme3-terrain/src/main/java/com/jme3/terrain/GeoMap.java
+++ b/jme3-terrain/src/main/java/com/jme3/terrain/GeoMap.java
@@ -51,16 +51,7 @@ public class GeoMap implements Savable {
protected int width, height, maxval;
public GeoMap() {}
-
- @Deprecated
- public GeoMap(FloatBuffer heightData, int width, int height, int maxval){
- hdata = new float[heightData.limit()];
- heightData.get(hdata);
- this.width = width;
- this.height = height;
- this.maxval = maxval;
- }
-
+
public GeoMap(float[] heightData, int width, int height, int maxval){
this.hdata = heightData;
this.width = width;
@@ -68,13 +59,6 @@ public class GeoMap implements Savable {
this.maxval = maxval;
}
- @Deprecated
- public FloatBuffer getHeightData(){
- if (!isLoaded())
- return null;
- return BufferUtils.createFloatBuffer(hdata);
- }
-
public float[] getHeightArray(){
if (!isLoaded())
return null;
diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/LODGeomap.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/LODGeomap.java
index fec90d811..286c570d9 100644
--- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/LODGeomap.java
+++ b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/LODGeomap.java
@@ -69,11 +69,6 @@ public class LODGeomap extends GeoMap {
public LODGeomap() {
}
-
- @Deprecated
- public LODGeomap(int size, FloatBuffer heightMap) {
- super(heightMap, size, size, 1);
- }
public LODGeomap(int size, float[] heightMap) {
super(heightMap, size, size, 1);
diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainGrid.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainGrid.java
index 50e1f9f73..d232be924 100644
--- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainGrid.java
+++ b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainGrid.java
@@ -43,7 +43,6 @@ import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.UpdateControl;
import com.jme3.terrain.Terrain;
-import com.jme3.terrain.heightmap.HeightMap;
import com.jme3.terrain.heightmap.HeightMapGrid;
import java.io.IOException;
import java.util.HashSet;
@@ -114,7 +113,6 @@ public class TerrainGrid extends TerrainQuad {
protected Vector3f currentCamCell = Vector3f.ZERO;
protected int quarterSize; // half of quadSize
protected int quadSize;
- protected HeightMapGrid heightMapGrid;
private TerrainGridTileLoader gridTileLoader;
protected Vector3f[] quadIndex;
protected Set listeners = new HashSet();
@@ -150,13 +148,7 @@ public class TerrainGrid extends TerrainQuad {
final Vector3f quadCell = location.add(quadIndex[quadIdx]);
TerrainQuad q = cache.get(quadCell);
if (q == null) {
- if (heightMapGrid != null) {
- // create the new Quad since it doesn't exist
- HeightMap heightMapAt = heightMapGrid.getHeightMapAt(quadCell);
- q = new TerrainQuad(getName() + "Quad" + quadCell, patchSize, quadSize, heightMapAt == null ? null : heightMapAt.getHeightMap());
- q.setMaterial(material.clone());
- log.log(Level.FINE, "Loaded TerrainQuad {0} from HeightMapGrid", q.getName());
- } else if (gridTileLoader != null) {
+ if (gridTileLoader != null) {
q = gridTileLoader.getTerrainQuadAt(quadCell);
// only clone the material to the quad if it doesn't have a material of its own
if(q.getMaterial()==null) q.setMaterial(material.clone());
diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainPatch.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainPatch.java
index 4641f4de6..44ad5cb30 100644
--- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainPatch.java
+++ b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainPatch.java
@@ -218,11 +218,6 @@ public class TerrainPatch extends Geometry {
return lodEntropy;
}
- @Deprecated
- public FloatBuffer getHeightmap() {
- return BufferUtils.createFloatBuffer(geomap.getHeightArray());
- }
-
public float[] getHeightMap() {
return geomap.getHeightArray();
}
diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainQuad.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainQuad.java
index e21b89155..679afcb70 100644
--- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainQuad.java
+++ b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainQuad.java
@@ -161,21 +161,6 @@ public class TerrainQuad extends Node implements Terrain {
addControl(new NormalRecalcControl(this));
}
- /**
- *
- * @param name the name of the scene element. This is required for
- * identification and comparison purposes.
- * @param patchSize size of the individual patches
- * @param quadSize
- * @param totalSize the size of this entire terrain tree (on one side)
- * @param heightMap The height map to generate the terrain from (a flat
- * height map will be generated if this is null)
- */
- @Deprecated
- public TerrainQuad(String name, int patchSize, int quadSize, int totalSize, float[] heightMap) {
- this(name, patchSize, totalSize, quadSize, Vector3f.UNIT_XYZ, heightMap);
- }
-
/**
*
* @param name the name of the scene element. This is required for
diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodCalculatorFactory.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodCalculatorFactory.java
deleted file mode 100644
index bfbd24a11..000000000
--- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodCalculatorFactory.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2009-2012 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.terrain.geomipmap.lodcalc;
-
-import com.jme3.export.Savable;
-import com.jme3.terrain.geomipmap.TerrainPatch;
-
-/**
- * Creates LOD Calculator objects for the terrain patches.
- *
- * @author Brent Owens
- * @deprecated phasing this out
- */
-public interface LodCalculatorFactory extends Savable, Cloneable {
-
- public LodCalculator createCalculator();
- public LodCalculator createCalculator(TerrainPatch terrainPatch);
-
- public LodCalculatorFactory clone();
-}
diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodDistanceCalculatorFactory.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodDistanceCalculatorFactory.java
deleted file mode 100644
index ab6e0037e..000000000
--- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodDistanceCalculatorFactory.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2009-2012 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.terrain.geomipmap.lodcalc;
-
-import com.jme3.export.InputCapsule;
-import com.jme3.export.JmeExporter;
-import com.jme3.export.JmeImporter;
-import com.jme3.export.OutputCapsule;
-import com.jme3.terrain.geomipmap.TerrainPatch;
-import java.io.IOException;
-
-/**
- *
- * @author bowens
- * @deprecated phasing out
- */
-public class LodDistanceCalculatorFactory implements LodCalculatorFactory {
-
- private float lodThresholdSize = 2.7f;
- private LodThreshold lodThreshold = null;
-
-
- public LodDistanceCalculatorFactory() {
- }
-
- public LodDistanceCalculatorFactory(LodThreshold lodThreshold) {
- this.lodThreshold = lodThreshold;
- }
-
- public LodCalculator createCalculator() {
- return new DistanceLodCalculator();
- }
-
- public LodCalculator createCalculator(TerrainPatch terrainPatch) {
- return new DistanceLodCalculator();
- }
-
- public void write(JmeExporter ex) throws IOException {
- OutputCapsule c = ex.getCapsule(this);
- c.write(lodThreshold, "lodThreshold", null);
- c.write(lodThresholdSize, "lodThresholdSize", 2);
- }
-
- public void read(JmeImporter im) throws IOException {
- InputCapsule c = im.getCapsule(this);
- lodThresholdSize = c.readFloat("lodThresholdSize", 2);
- lodThreshold = (LodThreshold) c.readSavable("lodThreshold", null);
- }
-
- @Override
- public LodDistanceCalculatorFactory clone() {
- LodDistanceCalculatorFactory clone = new LodDistanceCalculatorFactory();
- clone.lodThreshold = lodThreshold.clone();
- clone.lodThresholdSize = lodThresholdSize;
- return clone;
- }
-
-}
diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodPerspectiveCalculatorFactory.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodPerspectiveCalculatorFactory.java
deleted file mode 100644
index cb4a7d41e..000000000
--- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodPerspectiveCalculatorFactory.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2009-2012 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.terrain.geomipmap.lodcalc;
-
-import com.jme3.export.JmeExporter;
-import com.jme3.export.JmeImporter;
-import com.jme3.renderer.Camera;
-import com.jme3.terrain.geomipmap.TerrainPatch;
-import java.io.IOException;
-
-/**
- * TODO: Make it work with multiple cameras
- * TODO: Fix the cracks when the lod differences are greater than 1
- * for two adjacent blocks.
- * @deprecated phasing out
- */
-public class LodPerspectiveCalculatorFactory implements LodCalculatorFactory {
-
- private Camera cam;
- private float pixelError;
-
- public LodPerspectiveCalculatorFactory(Camera cam, float pixelError){
- this.cam = cam;
- this.pixelError = pixelError;
- }
-
- public LodCalculator createCalculator() {
- return new PerspectiveLodCalculator(cam, pixelError);
- }
-
- public LodCalculator createCalculator(TerrainPatch terrainPatch) {
- PerspectiveLodCalculator p = new PerspectiveLodCalculator(cam, pixelError);
- return p;
- }
-
- public void write(JmeExporter ex) throws IOException {
- }
-
- public void read(JmeImporter im) throws IOException {
- }
-
- @Override
- public LodCalculatorFactory clone() {
- try {
- return (LodCalculatorFactory) super.clone();
- } catch (CloneNotSupportedException ex) {
- throw new AssertionError();
- }
- }
-
-}
diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMap.java b/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMap.java
index d4e9b22c8..0373c80eb 100644
--- a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMap.java
+++ b/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMap.java
@@ -44,7 +44,7 @@ import com.jme3.texture.image.ImageRaster;
* @author Mike Kienenberger
* @version $id$
*/
-public class ImageBasedHeightMap extends AbstractHeightMap implements ImageHeightmap {
+public class ImageBasedHeightMap extends AbstractHeightMap {
protected Image colorImage;
diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMapGrid.java b/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMapGrid.java
deleted file mode 100644
index f0d841c22..000000000
--- a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMapGrid.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 2009-2012 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.terrain.heightmap;
-
-import com.jme3.asset.AssetManager;
-import com.jme3.asset.AssetNotFoundException;
-import com.jme3.asset.TextureKey;
-import com.jme3.math.Vector3f;
-import com.jme3.texture.Texture;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Loads Terrain grid tiles with image heightmaps.
- * By default it expects a 16-bit grayscale image as the heightmap, but
- * you can also call setImageType(BufferedImage.TYPE_) to set it to be a different
- * image type. If you do this, you must also set a custom ImageHeightmap that will
- * understand and be able to parse the image. By default if you pass in an image of type
- * BufferedImage.TYPE_3BYTE_BGR, it will use the ImageBasedHeightMap for you.
- *
- * @author Anthyon, Brent Owens
- */
-@Deprecated
-/**
- * @Deprecated in favor of ImageTileLoader
- */
-public class ImageBasedHeightMapGrid implements HeightMapGrid {
-
- private static final Logger logger = Logger.getLogger(ImageBasedHeightMapGrid.class.getName());
- private final AssetManager assetManager;
- private final Namer namer;
- private int size;
-
-
- public ImageBasedHeightMapGrid(final String textureBase, final String textureExt, AssetManager assetManager) {
- this(assetManager, new Namer() {
-
- public String getName(int x, int y) {
- return textureBase + "_" + x + "_" + y + "." + textureExt;
- }
- });
- }
-
- public ImageBasedHeightMapGrid(AssetManager assetManager, Namer namer) {
- this.assetManager = assetManager;
- this.namer = namer;
- }
-
- public HeightMap getHeightMapAt(Vector3f location) {
- // HEIGHTMAP image (for the terrain heightmap)
- int x = (int) location.x;
- int z = (int) location.z;
-
- AbstractHeightMap heightmap = null;
- //BufferedImage im = null;
-
- try {
- String name = namer.getName(x, z);
- logger.log(Level.FINE, "Loading heightmap from file: {0}", name);
- final Texture texture = assetManager.loadTexture(new TextureKey(name));
-
- // CREATE HEIGHTMAP
- heightmap = new ImageBasedHeightMap(texture.getImage());
-
- heightmap.setHeightScale(1);
- heightmap.load();
-
- } catch (AssetNotFoundException e) {
- logger.log(Level.SEVERE, "Asset Not found! ", e);
- }
- return heightmap;
- }
-
- public void setSize(int size) {
- this.size = size - 1;
- }
-}
diff --git a/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall.j3m b/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall.j3m
index 41af10431..c35ab04c4 100644
--- a/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall.j3m
+++ b/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall.j3m
@@ -1,7 +1,8 @@
Material Pong Rock : Common/MatDefs/Light/Lighting.j3md {
MaterialParameters {
- Shininess: 2.0
- DiffuseMap : Repeat Textures/Terrain/BrickWall/BrickWall.jpg
- ParallaxMap : Repeat Textures/Terrain/BrickWall/BrickWall_height.jpg
+ Shininess : 2.0
+ DiffuseMap : Repeat Textures/Terrain/BrickWall/BrickWall.dds
+ NormalMap : Repeat Textures/Terrain/BrickWall/BrickWall_normal_parallax.dds
+ PackedNormalParallax : true
}
}
\ No newline at end of file
diff --git a/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall2.j3m b/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall2.j3m
deleted file mode 100644
index 8f90a9454..000000000
--- a/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall2.j3m
+++ /dev/null
@@ -1,8 +0,0 @@
-Material Pong Rock : Common/MatDefs/Light/Lighting.j3md {
- MaterialParameters {
- Shininess: 2.0
- DiffuseMap : Repeat Textures/Terrain/BrickWall/BrickWall.jpg
- NormalMap : Repeat Textures/Terrain/BrickWall/BrickWall_normal_parallax.dds
- PackedNormalParallax: true
- }
-}
\ No newline at end of file