Home | History | Annotate | Download | only in material
      1 /*
      2  * Copyright (c) 2009-2010 jMonkeyEngine
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 package com.jme3.material;
     34 
     35 import com.jme3.export.*;
     36 import com.jme3.renderer.Caps;
     37 import com.jme3.renderer.Renderer;
     38 import com.jme3.shader.DefineList;
     39 import com.jme3.shader.UniformBinding;
     40 import com.jme3.shader.VarType;
     41 import java.io.IOException;
     42 import java.util.ArrayList;
     43 import java.util.EnumSet;
     44 import java.util.HashMap;
     45 import java.util.List;
     46 
     47 /**
     48  * Describes a technique definition.
     49  *
     50  * @author Kirill Vainer
     51  */
     52 public class TechniqueDef implements Savable {
     53 
     54     /**
     55      * Describes light rendering mode.
     56      */
     57     public enum LightMode {
     58         /**
     59          * Disable light-based rendering
     60          */
     61         Disable,
     62 
     63         /**
     64          * Enable light rendering by using a single pass.
     65          * <p>
     66          * An array of light positions and light colors is passed to the shader
     67          * containing the world light list for the geometry being rendered.
     68          */
     69         SinglePass,
     70 
     71         /**
     72          * Enable light rendering by using multi-pass rendering.
     73          * <p>
     74          * The geometry will be rendered once for each light. Each time the
     75          * light position and light color uniforms are updated to contain
     76          * the values for the current light. The ambient light color uniform
     77          * is only set to the ambient light color on the first pass, future
     78          * passes have it set to black.
     79          */
     80         MultiPass,
     81 
     82         /**
     83          * Enable light rendering by using the
     84          * {@link Renderer#setLighting(com.jme3.light.LightList) renderer's setLighting}
     85          * method.
     86          * <p>
     87          * The specific details of rendering the lighting is up to the
     88          * renderer implementation.
     89          */
     90         FixedPipeline,
     91     }
     92 
     93     public enum ShadowMode {
     94         Disable,
     95         InPass,
     96         PostPass,
     97     }
     98 
     99     private EnumSet<Caps> requiredCaps = EnumSet.noneOf(Caps.class);
    100     private String name;
    101 
    102     private String vertName;
    103     private String fragName;
    104     private String shaderLang;
    105     private DefineList presetDefines;
    106     private boolean usesShaders;
    107 
    108     private RenderState renderState;
    109     private LightMode lightMode   = LightMode.Disable;
    110     private ShadowMode shadowMode = ShadowMode.Disable;
    111 
    112     private HashMap<String, String> defineParams;
    113     private ArrayList<UniformBinding> worldBinds;
    114 
    115     /**
    116      * Creates a new technique definition.
    117      * <p>
    118      * Used internally by the J3M/J3MD loader.
    119      *
    120      * @param name The name of the technique, should be set to <code>null</code>
    121      * for default techniques.
    122      */
    123     public TechniqueDef(String name){
    124         this.name = name == null ? "Default" : name;
    125     }
    126 
    127     /**
    128      * Serialization only. Do not use.
    129      */
    130     public TechniqueDef(){
    131     }
    132 
    133     /**
    134      * Returns the name of this technique as specified in the J3MD file.
    135      * Default techniques have the name "Default".
    136      *
    137      * @return the name of this technique
    138      */
    139     public String getName(){
    140         return name;
    141     }
    142 
    143     /**
    144      * Returns the light mode.
    145      * @return the light mode.
    146      * @see LightMode
    147      */
    148     public LightMode getLightMode() {
    149         return lightMode;
    150     }
    151 
    152     /**
    153      * Set the light mode
    154      *
    155      * @param lightMode the light mode
    156      *
    157      * @see LightMode
    158      */
    159     public void setLightMode(LightMode lightMode) {
    160         this.lightMode = lightMode;
    161     }
    162 
    163     /**
    164      * Returns the shadow mode.
    165      * @return the shadow mode.
    166      */
    167     public ShadowMode getShadowMode() {
    168         return shadowMode;
    169     }
    170 
    171     /**
    172      * Set the shadow mode.
    173      *
    174      * @param shadowMode the shadow mode.
    175      *
    176      * @see ShadowMode
    177      */
    178     public void setShadowMode(ShadowMode shadowMode) {
    179         this.shadowMode = shadowMode;
    180     }
    181 
    182     /**
    183      * Returns the render state that this technique is using
    184      * @return the render state that this technique is using
    185      * @see #setRenderState(com.jme3.material.RenderState)
    186      */
    187     public RenderState getRenderState() {
    188         return renderState;
    189     }
    190 
    191     /**
    192      * Sets the render state that this technique is using.
    193      *
    194      * @param renderState the render state that this technique is using.
    195      *
    196      * @see RenderState
    197      */
    198     public void setRenderState(RenderState renderState) {
    199         this.renderState = renderState;
    200     }
    201 
    202     /**
    203      * Returns true if this technique uses shaders, false otherwise.
    204      *
    205      * @return true if this technique uses shaders, false otherwise.
    206      *
    207      * @see #setShaderFile(java.lang.String, java.lang.String, java.lang.String)
    208      */
    209     public boolean isUsingShaders(){
    210         return usesShaders;
    211     }
    212 
    213     /**
    214      * Gets the {@link Caps renderer capabilities} that are required
    215      * by this technique.
    216      *
    217      * @return the required renderer capabilities
    218      */
    219     public EnumSet<Caps> getRequiredCaps() {
    220         return requiredCaps;
    221     }
    222 
    223     /**
    224      * Sets the shaders that this technique definition will use.
    225      *
    226      * @param vertexShader The name of the vertex shader
    227      * @param fragmentShader The name of the fragment shader
    228      * @param shaderLanguage The shader language
    229      */
    230     public void setShaderFile(String vertexShader, String fragmentShader, String shaderLanguage){
    231         this.vertName = vertexShader;
    232         this.fragName = fragmentShader;
    233         this.shaderLang = shaderLanguage;
    234 
    235         Caps langCap = Caps.valueOf(shaderLanguage);
    236         requiredCaps.add(langCap);
    237 
    238         usesShaders = true;
    239     }
    240 
    241     /**
    242      * Returns the define name which the given material parameter influences.
    243      *
    244      * @param paramName The parameter name to look up
    245      * @return The define name
    246      *
    247      * @see #addShaderParamDefine(java.lang.String, java.lang.String)
    248      */
    249     public String getShaderParamDefine(String paramName){
    250         if (defineParams == null)
    251             return null;
    252 
    253         return defineParams.get(paramName);
    254     }
    255 
    256     /**
    257      * Adds a define linked to a material parameter.
    258      * <p>
    259      * Any time the material parameter on the parent material is altered,
    260      * the appropriate define on the technique will be modified as well.
    261      * See the method
    262      * {@link DefineList#set(java.lang.String, com.jme3.shader.VarType, java.lang.Object) }
    263      * on the exact details of how the material parameter changes the define.
    264      *
    265      * @param paramName The name of the material parameter to link to.
    266      * @param defineName The name of the define parameter, e.g. USE_LIGHTING
    267      */
    268     public void addShaderParamDefine(String paramName, String defineName){
    269         if (defineParams == null)
    270             defineParams = new HashMap<String, String>();
    271 
    272         defineParams.put(paramName, defineName);
    273     }
    274 
    275     /**
    276      * Returns the {@link DefineList} for the preset defines.
    277      *
    278      * @return the {@link DefineList} for the preset defines.
    279      *
    280      * @see #addShaderPresetDefine(java.lang.String, com.jme3.shader.VarType, java.lang.Object)
    281      */
    282     public DefineList getShaderPresetDefines() {
    283         return presetDefines;
    284     }
    285 
    286     /**
    287      * Adds a preset define.
    288      * <p>
    289      * Preset defines do not depend upon any parameters to be activated,
    290      * they are always passed to the shader as long as this technique is used.
    291      *
    292      * @param defineName The name of the define parameter, e.g. USE_LIGHTING
    293      * @param type The type of the define. See
    294      * {@link DefineList#set(java.lang.String, com.jme3.shader.VarType, java.lang.Object) }
    295      * to see why it matters.
    296      *
    297      * @param value The value of the define
    298      */
    299     public void addShaderPresetDefine(String defineName, VarType type, Object value){
    300         if (presetDefines == null)
    301             presetDefines = new DefineList();
    302 
    303         presetDefines.set(defineName, type, value);
    304     }
    305 
    306     /**
    307      * Returns the name of the fragment shader used by the technique, or null
    308      * if no fragment shader is specified.
    309      *
    310      * @return the name of the fragment shader to be used.
    311      */
    312     public String getFragmentShaderName() {
    313         return fragName;
    314     }
    315 
    316 
    317     /**
    318      * Returns the name of the vertex shader used by the technique, or null
    319      * if no vertex shader is specified.
    320      *
    321      * @return the name of the vertex shader to be used.
    322      */
    323     public String getVertexShaderName() {
    324         return vertName;
    325     }
    326 
    327     /**
    328      * Returns the shader language of the shaders used in this technique.
    329      *
    330      * @return the shader language of the shaders used in this technique.
    331      */
    332     public String getShaderLanguage() {
    333         return shaderLang;
    334     }
    335 
    336     /**
    337      * Adds a new world parameter by the given name.
    338      *
    339      * @param name The world parameter to add.
    340      * @return True if the world parameter name was found and added
    341      * to the list of world parameters, false otherwise.
    342      */
    343     public boolean addWorldParam(String name) {
    344         if (worldBinds == null){
    345             worldBinds = new ArrayList<UniformBinding>();
    346         }
    347 
    348         try {
    349             worldBinds.add( UniformBinding.valueOf(name) );
    350             return true;
    351         } catch (IllegalArgumentException ex){
    352             return false;
    353         }
    354     }
    355 
    356     /**
    357      * Returns a list of world parameters that are used by this
    358      * technique definition.
    359      *
    360      * @return The list of world parameters
    361      */
    362     public List<UniformBinding> getWorldBindings() {
    363         return worldBinds;
    364     }
    365 
    366     public void write(JmeExporter ex) throws IOException{
    367         OutputCapsule oc = ex.getCapsule(this);
    368         oc.write(name, "name", null);
    369         oc.write(vertName, "vertName", null);
    370         oc.write(fragName, "fragName", null);
    371         oc.write(shaderLang, "shaderLang", null);
    372         oc.write(presetDefines, "presetDefines", null);
    373         oc.write(lightMode, "lightMode", LightMode.Disable);
    374         oc.write(shadowMode, "shadowMode", ShadowMode.Disable);
    375         oc.write(renderState, "renderState", null);
    376         oc.write(usesShaders, "usesShaders", false);
    377         // TODO: Finish this when Map<String, String> export is available
    378 //        oc.write(defineParams, "defineParams", null);
    379         // TODO: Finish this when List<Enum> export is available
    380 //        oc.write(worldBinds, "worldBinds", null);
    381     }
    382 
    383     public void read(JmeImporter im) throws IOException{
    384         InputCapsule ic = im.getCapsule(this);
    385         name = ic.readString("name", null);
    386         vertName = ic.readString("vertName", null);
    387         fragName = ic.readString("fragName", null);
    388         shaderLang = ic.readString("shaderLang", null);
    389         presetDefines = (DefineList) ic.readSavable("presetDefines", null);
    390         lightMode = ic.readEnum("lightMode", LightMode.class, LightMode.Disable);
    391         shadowMode = ic.readEnum("shadowMode", ShadowMode.class, ShadowMode.Disable);
    392         renderState = (RenderState) ic.readSavable("renderState", null);
    393         usesShaders = ic.readBoolean("usesShaders", false);
    394     }
    395 
    396 }
    397