/* * 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. *

* 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. *

* 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. *

* The specific details of rendering the lighting is up to the * renderer implementation. */ FixedPipeline, } public enum ShadowMode { Disable, InPass, PostPass, } private EnumSet 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 defineParams; private ArrayList worldBinds; /** * Creates a new technique definition. *

* Used internally by the J3M/J3MD loader. * * @param name The name of the technique, should be set to null * 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 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. *

* 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(); 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. *

* 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(); } 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 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 export is available // oc.write(defineParams, "defineParams", null); // TODO: Finish this when List 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); } }