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 */ TechniqueDef(String name)123 public TechniqueDef(String name){ 124 this.name = name == null ? "Default" : name; 125 } 126 127 /** 128 * Serialization only. Do not use. 129 */ TechniqueDef()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 */ getName()139 public String getName(){ 140 return name; 141 } 142 143 /** 144 * Returns the light mode. 145 * @return the light mode. 146 * @see LightMode 147 */ getLightMode()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 */ setLightMode(LightMode lightMode)159 public void setLightMode(LightMode lightMode) { 160 this.lightMode = lightMode; 161 } 162 163 /** 164 * Returns the shadow mode. 165 * @return the shadow mode. 166 */ getShadowMode()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 */ setShadowMode(ShadowMode shadowMode)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 */ getRenderState()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 */ setRenderState(RenderState renderState)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 */ isUsingShaders()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 */ getRequiredCaps()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 */ setShaderFile(String vertexShader, String fragmentShader, String shaderLanguage)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 */ getShaderParamDefine(String paramName)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 */ addShaderParamDefine(String paramName, String defineName)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 */ getShaderPresetDefines()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 */ addShaderPresetDefine(String defineName, VarType type, Object value)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 */ getFragmentShaderName()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 */ getVertexShaderName()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 */ getShaderLanguage()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 */ addWorldParam(String name)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 */ getWorldBindings()362 public List<UniformBinding> getWorldBindings() { 363 return worldBinds; 364 } 365 write(JmeExporter ex)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 read(JmeImporter im)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