blob: aaeb34004882e9759d64db2c289bed834295b1cd [file] [log] [blame]
/*
* Copyright (c) 2009-2010 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.export.*;
import com.jme3.renderer.Caps;
import com.jme3.renderer.Renderer;
import com.jme3.shader.DefineList;
import com.jme3.shader.UniformBinding;
import com.jme3.shader.VarType;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
/**
* Describes a technique definition.
*
* @author Kirill Vainer
*/
public class TechniqueDef implements Savable {
/**
* Describes light rendering mode.
*/
public enum LightMode {
/**
* Disable light-based rendering
*/
Disable,
/**
* Enable light rendering by using a single pass.
* <p>
* An array of light positions and light colors is passed to the shader
* containing the world light list for the geometry being rendered.
*/
SinglePass,
/**
* Enable light rendering by using multi-pass rendering.
* <p>
* The geometry will be rendered once for each light. Each time the
* light position and light color uniforms are updated to contain
* the values for the current light. The ambient light color uniform
* is only set to the ambient light color on the first pass, future
* passes have it set to black.
*/
MultiPass,
/**
* Enable light rendering by using the
* {@link Renderer#setLighting(com.jme3.light.LightList) renderer's setLighting}
* method.
* <p>
* The specific details of rendering the lighting is up to the
* renderer implementation.
*/
FixedPipeline,
}
public enum ShadowMode {
Disable,
InPass,
PostPass,
}
private EnumSet<Caps> requiredCaps = EnumSet.noneOf(Caps.class);
private String name;
private String vertName;
private String fragName;
private String shaderLang;
private DefineList presetDefines;
private boolean usesShaders;
private RenderState renderState;
private LightMode lightMode = LightMode.Disable;
private ShadowMode shadowMode = ShadowMode.Disable;
private HashMap<String, String> defineParams;
private ArrayList<UniformBinding> worldBinds;
/**
* Creates a new technique definition.
* <p>
* Used internally by the J3M/J3MD loader.
*
* @param name The name of the technique, should be set to <code>null</code>
* for default techniques.
*/
public TechniqueDef(String name){
this.name = name == null ? "Default" : name;
}
/**
* Serialization only. Do not use.
*/
public TechniqueDef(){
}
/**
* Returns the name of this technique as specified in the J3MD file.
* Default techniques have the name "Default".
*
* @return the name of this technique
*/
public String getName(){
return name;
}
/**
* Returns the light mode.
* @return the light mode.
* @see LightMode
*/
public LightMode getLightMode() {
return lightMode;
}
/**
* Set the light mode
*
* @param lightMode the light mode
*
* @see LightMode
*/
public void setLightMode(LightMode lightMode) {
this.lightMode = lightMode;
}
/**
* Returns the shadow mode.
* @return the shadow mode.
*/
public ShadowMode getShadowMode() {
return shadowMode;
}
/**
* Set the shadow mode.
*
* @param shadowMode the shadow mode.
*
* @see ShadowMode
*/
public void setShadowMode(ShadowMode shadowMode) {
this.shadowMode = shadowMode;
}
/**
* Returns the render state that this technique is using
* @return the render state that this technique is using
* @see #setRenderState(com.jme3.material.RenderState)
*/
public RenderState getRenderState() {
return renderState;
}
/**
* Sets the render state that this technique is using.
*
* @param renderState the render state that this technique is using.
*
* @see RenderState
*/
public void setRenderState(RenderState renderState) {
this.renderState = renderState;
}
/**
* Returns true if this technique uses shaders, false otherwise.
*
* @return true if this technique uses shaders, false otherwise.
*
* @see #setShaderFile(java.lang.String, java.lang.String, java.lang.String)
*/
public boolean isUsingShaders(){
return usesShaders;
}
/**
* Gets the {@link Caps renderer capabilities} that are required
* by this technique.
*
* @return the required renderer capabilities
*/
public EnumSet<Caps> getRequiredCaps() {
return requiredCaps;
}
/**
* Sets the shaders that this technique definition will use.
*
* @param vertexShader The name of the vertex shader
* @param fragmentShader The name of the fragment shader
* @param shaderLanguage The shader language
*/
public void setShaderFile(String vertexShader, String fragmentShader, String shaderLanguage){
this.vertName = vertexShader;
this.fragName = fragmentShader;
this.shaderLang = shaderLanguage;
Caps langCap = Caps.valueOf(shaderLanguage);
requiredCaps.add(langCap);
usesShaders = true;
}
/**
* Returns the define name which the given material parameter influences.
*
* @param paramName The parameter name to look up
* @return The define name
*
* @see #addShaderParamDefine(java.lang.String, java.lang.String)
*/
public String getShaderParamDefine(String paramName){
if (defineParams == null)
return null;
return defineParams.get(paramName);
}
/**
* Adds a define linked to a material parameter.
* <p>
* 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.
*
* @param paramName The name 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<String, String>();
defineParams.put(paramName, defineName);
}
/**
* Returns the {@link DefineList} for the preset defines.
*
* @return the {@link DefineList} for the preset defines.
*
* @see #addShaderPresetDefine(java.lang.String, com.jme3.shader.VarType, java.lang.Object)
*/
public DefineList getShaderPresetDefines() {
return presetDefines;
}
/**
* Adds a preset define.
* <p>
* 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.
*
* @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.
*
* @param value The value of the define
*/
public void addShaderPresetDefine(String defineName, VarType type, Object value){
if (presetDefines == null)
presetDefines = new DefineList();
presetDefines.set(defineName, type, value);
}
/**
* Returns the name of the fragment shader used by the technique, or null
* if no fragment shader is specified.
*
* @return the name of the fragment shader to be used.
*/
public String getFragmentShaderName() {
return fragName;
}
/**
* Returns the name of the vertex shader used by the technique, or null
* if no vertex shader is specified.
*
* @return the name of the vertex shader to be used.
*/
public String getVertexShaderName() {
return vertName;
}
/**
* Returns the shader language of the shaders used in this technique.
*
* @return the shader language of the shaders used in this technique.
*/
public String getShaderLanguage() {
return shaderLang;
}
/**
* Adds a new world parameter by the given name.
*
* @param name The world parameter to add.
* @return True if the world parameter name was found and added
* to the list of world parameters, false otherwise.
*/
public boolean addWorldParam(String name) {
if (worldBinds == null){
worldBinds = new ArrayList<UniformBinding>();
}
try {
worldBinds.add( UniformBinding.valueOf(name) );
return true;
} catch (IllegalArgumentException ex){
return false;
}
}
/**
* Returns a list of world parameters that are used by this
* technique definition.
*
* @return The list of world parameters
*/
public List<UniformBinding> getWorldBindings() {
return worldBinds;
}
public void write(JmeExporter ex) throws IOException{
OutputCapsule oc = ex.getCapsule(this);
oc.write(name, "name", null);
oc.write(vertName, "vertName", null);
oc.write(fragName, "fragName", null);
oc.write(shaderLang, "shaderLang", null);
oc.write(presetDefines, "presetDefines", null);
oc.write(lightMode, "lightMode", LightMode.Disable);
oc.write(shadowMode, "shadowMode", ShadowMode.Disable);
oc.write(renderState, "renderState", null);
oc.write(usesShaders, "usesShaders", false);
// TODO: Finish this when Map<String, String> export is available
// oc.write(defineParams, "defineParams", null);
// TODO: Finish this when List<Enum> export is available
// oc.write(worldBinds, "worldBinds", null);
}
public void read(JmeImporter im) throws IOException{
InputCapsule ic = im.getCapsule(this);
name = ic.readString("name", null);
vertName = ic.readString("vertName", null);
fragName = ic.readString("fragName", null);
shaderLang = ic.readString("shaderLang", null);
presetDefines = (DefineList) ic.readSavable("presetDefines", null);
lightMode = ic.readEnum("lightMode", LightMode.class, LightMode.Disable);
shadowMode = ic.readEnum("shadowMode", ShadowMode.class, ShadowMode.Disable);
renderState = (RenderState) ic.readSavable("renderState", null);
usesShaders = ic.readBoolean("usesShaders", false);
}
}