From 1ad8ff154c24b256bdd430963027bdb09c100f9a Mon Sep 17 00:00:00 2001 From: michael Date: Mon, 23 Feb 2015 22:39:46 +0100 Subject: [PATCH] Fixed uploading of all shader stages --- .../com/jme3/asset/DesktopAssetManager.java | 61 ++-- .../asset/cache/WeakRefCloneAssetCache.java | 84 +++--- .../com/jme3/renderer/opengl/GLRenderer.java | 204 ++++++------- .../main/java/com/jme3/shader/ShaderKey.java | 13 + .../com/jme3/material/plugins/J3MLoader.java | 278 +++++++++--------- .../resources/Materials/Geom/SimpleGeom.frag | 3 + .../resources/Materials/Geom/SimpleGeom.geom | 19 ++ .../resources/Materials/Geom/SimpleGeom.j3m | 4 + .../resources/Materials/Geom/SimpleGeom.j3md | 17 ++ .../resources/Materials/Geom/SimpleGeom.vert | 5 + 10 files changed, 374 insertions(+), 314 deletions(-) create mode 100644 jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.frag create mode 100644 jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.geom create mode 100644 jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.j3m create mode 100644 jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.j3md create mode 100644 jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.vert diff --git a/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java b/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java index bf0d145d8..109ebed36 100644 --- a/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java +++ b/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java @@ -68,12 +68,12 @@ public class DesktopAssetManager implements AssetManager { private static final Logger logger = Logger.getLogger(AssetManager.class.getName()); private ShaderGenerator shaderGenerator; - + private final ImplHandler handler = new ImplHandler(this); - private CopyOnWriteArrayList eventListeners = + private CopyOnWriteArrayList eventListeners = new CopyOnWriteArrayList(); - + private List classLoaders = Collections.synchronizedList(new ArrayList()); @@ -89,7 +89,7 @@ public class DesktopAssetManager implements AssetManager { public DesktopAssetManager(URL configFile){ if (configFile != null){ loadConfigFile(configFile); - } + } logger.fine("DesktopAssetManager created."); } @@ -109,11 +109,11 @@ public class DesktopAssetManager implements AssetManager { } } } - + public void addClassLoader(ClassLoader loader) { classLoaders.add(loader); } - + public void removeClassLoader(ClassLoader loader) { classLoaders.remove(loader); } @@ -121,7 +121,7 @@ public class DesktopAssetManager implements AssetManager { public List getClassLoaders(){ return Collections.unmodifiableList(classLoaders); } - + public void addAssetEventListener(AssetEventListener listener) { eventListeners.add(listener); } @@ -133,7 +133,7 @@ public class DesktopAssetManager implements AssetManager { public void clearAssetEventListeners() { eventListeners.clear(); } - + public void setAssetEventListener(AssetEventListener listener){ eventListeners.clear(); eventListeners.add(listener); @@ -160,7 +160,7 @@ public class DesktopAssetManager implements AssetManager { registerLoader(clazz, extensions); } } - + public void unregisterLoader(Class loaderClass) { handler.removeLoader(loaderClass); if (logger.isLoggable(Level.FINER)){ @@ -190,7 +190,7 @@ public class DesktopAssetManager implements AssetManager { registerLocator(rootPath, clazz); } } - + public void unregisterLocator(String rootPath, Class clazz){ handler.removeLocator(clazz, rootPath); if (logger.isLoggable(Level.FINER)){ @@ -198,7 +198,7 @@ public class DesktopAssetManager implements AssetManager { clazz.getSimpleName()); } } - + public AssetInfo locateAsset(AssetKey key){ AssetInfo info = handler.tryLocate(key); if (info == null){ @@ -206,7 +206,7 @@ public class DesktopAssetManager implements AssetManager { } return info; } - + public T getFromCache(AssetKey key) { AssetCache cache = handler.getCache(key.getCacheType()); if (cache != null) { @@ -220,7 +220,7 @@ public class DesktopAssetManager implements AssetManager { throw new IllegalArgumentException("Key " + key + " specifies no cache."); } } - + public void addToCache(AssetKey key, T asset) { AssetCache cache = handler.getCache(key.getCacheType()); if (cache != null) { @@ -230,7 +230,7 @@ public class DesktopAssetManager implements AssetManager { throw new IllegalArgumentException("Key " + key + " specifies no cache."); } } - + public boolean deleteFromCache(AssetKey key) { AssetCache cache = handler.getCache(key.getCacheType()); if (cache != null) { @@ -239,7 +239,7 @@ public class DesktopAssetManager implements AssetManager { throw new IllegalArgumentException("Key " + key + " specifies no cache."); } } - + public void clearCache(){ handler.clearCache(); if (logger.isLoggable(Level.FINER)){ @@ -257,14 +257,14 @@ public class DesktopAssetManager implements AssetManager { public T loadAsset(AssetKey key){ if (key == null) throw new IllegalArgumentException("key cannot be null"); - + for (AssetEventListener listener : eventListeners){ listener.assetRequested(key); } - + AssetCache cache = handler.getCache(key.getCacheType()); AssetProcessor proc = handler.getProcessor(key.getProcessorType()); - + Object obj = cache != null ? cache.getFromCache(key) : null; if (obj == null){ // Asset not in cache, load it from file system. @@ -298,17 +298,17 @@ public class DesktopAssetManager implements AssetManager { logger.log(Level.FINER, "Loaded {0} with {1}", new Object[]{key, loader.getClass().getSimpleName()}); } - + if (proc != null){ // do processing on asset before caching obj = proc.postProcess(key, obj); } - + if (cache != null){ // At this point, obj should be of type T cache.addToCache(key, (T) obj); } - + for (AssetEventListener listener : eventListeners){ listener.assetLoaded(key); } @@ -334,7 +334,7 @@ public class DesktopAssetManager implements AssetManager { } } } - + return clone; } @@ -342,7 +342,7 @@ public class DesktopAssetManager implements AssetManager { return loadAsset(new AssetKey(name)); } - public Texture loadTexture(TextureKey key){ + public Texture loadTexture(TextureKey key){ return (Texture) loadAsset(key); } @@ -393,6 +393,7 @@ public class DesktopAssetManager implements AssetManager { public Shader loadShader(ShaderKey key){ // cache abuse in method // that doesn't use loaders/locators + System.out.println(); AssetCache cache = handler.getCache(SimpleAssetCache.class); Shader shader = (Shader) cache.getFromCache(key); if (shader == null){ @@ -402,17 +403,11 @@ public class DesktopAssetManager implements AssetManager { } shader = shaderGenerator.generateShader(); } else { - - String vertName = key.getVertName(); - String fragName = key.getFragName(); - - String vertSource = (String) loadAsset(new AssetKey(vertName)); - String fragSource = (String) loadAsset(new AssetKey(fragName)); - shader = new Shader(); shader.initialize(); - shader.addSource(Shader.ShaderType.Vertex, vertName, vertSource, key.getDefines().getCompiled(), key.getVertexShaderLanguage()); - shader.addSource(Shader.ShaderType.Fragment, fragName, fragSource, key.getDefines().getCompiled(), key.getFragmentShaderLanguage()); + for (Shader.ShaderType shaderType : key.getUsedShaderPrograms()) { + shader.addSource(shaderType,key.getShaderProgramName(shaderType),(String) loadAsset(new AssetKey(key.getShaderProgramName(shaderType))),key.getDefines().getCompiled(),key.getShaderProgramLanguage(shaderType)); + } } cache.addToCache(key, shader); @@ -443,5 +438,5 @@ public class DesktopAssetManager implements AssetManager { this.shaderGenerator = shaderGenerator; } - + } diff --git a/jme3-core/src/main/java/com/jme3/asset/cache/WeakRefCloneAssetCache.java b/jme3-core/src/main/java/com/jme3/asset/cache/WeakRefCloneAssetCache.java index 46ddfd199..15c453dcc 100644 --- a/jme3-core/src/main/java/com/jme3/asset/cache/WeakRefCloneAssetCache.java +++ b/jme3-core/src/main/java/com/jme3/asset/cache/WeakRefCloneAssetCache.java @@ -33,6 +33,7 @@ package com.jme3.asset.cache; import com.jme3.asset.AssetKey; import com.jme3.asset.CloneableSmartAsset; + import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; @@ -45,43 +46,43 @@ import java.util.logging.Logger; * caches cloneable assets in a weak-key * cache, allowing them to be collected when memory is low. * The cache stores weak references to the asset keys, so that - * when all clones of the original asset are collected, will cause the + * when all clones of the original asset are collected, will cause the * asset to be automatically removed from the cache. - * -* @author Kirill Vainer + * + * @author Kirill Vainer */ public class WeakRefCloneAssetCache implements AssetCache { private static final Logger logger = Logger.getLogger(WeakRefAssetCache.class.getName()); - + private final ReferenceQueue refQueue = new ReferenceQueue(); - + /** - * Maps cloned key to AssetRef which has a weak ref to the original + * Maps cloned key to AssetRef which has a weak ref to the original * key and a strong ref to the original asset. */ - private final ConcurrentHashMap smartCache + private final ConcurrentHashMap smartCache = new ConcurrentHashMap(); - + /** * Stored in the ReferenceQueue to find out when originalKey is collected * by GC. Once collected, the clonedKey is used to remove the asset * from the cache. */ private static final class KeyRef extends PhantomReference { - + AssetKey clonedKey; - + public KeyRef(AssetKey originalKey, ReferenceQueue refQueue) { super(originalKey, refQueue); clonedKey = originalKey.clone(); } } - + /** * Stores the original key and original asset. * The asset info contains a cloneable asset (e.g. the original, from - * which all clones are made). Also a weak reference to the + * which all clones are made). Also a weak reference to the * original key which is used when the clones are produced. */ private static final class AssetRef extends WeakReference { @@ -94,24 +95,24 @@ public class WeakRefCloneAssetCache implements AssetCache { } } - private final ThreadLocal> assetLoadStack + private final ThreadLocal> assetLoadStack = new ThreadLocal>() { @Override protected ArrayList initialValue() { return new ArrayList(); } }; - - private void removeCollectedAssets(){ + + private void removeCollectedAssets() { int removedAssets = 0; - for (KeyRef ref; (ref = (KeyRef)refQueue.poll()) != null;){ + for (KeyRef ref; (ref = (KeyRef) refQueue.poll()) != null; ) { // (Cannot use ref.get() since it was just collected by GC!) AssetKey key = ref.clonedKey; - + // Asset was collected, note that at this point the asset cache // might not even have this asset anymore, it is OK. - if (smartCache.remove(key) != null){ - removedAssets ++; + if (smartCache.remove(key) != null) { + removedAssets++; //System.out.println("WeakRefAssetCache: The asset " + ref.assetKey + " was purged from the cache"); } } @@ -119,25 +120,24 @@ public class WeakRefCloneAssetCache implements AssetCache { logger.log(Level.FINE, "WeakRefAssetCache: {0} assets were purged from the cache.", removedAssets); } } - + public void addToCache(AssetKey originalKey, T obj) { // Make room for new asset removeCollectedAssets(); - CloneableSmartAsset asset = (CloneableSmartAsset) obj; - + // No circular references, since the original asset is // strongly referenced, we don't want the key strongly referenced. - asset.setKey(null); - + asset.setKey(null); + // Start tracking the collection of originalKey // (this adds the KeyRef to the ReferenceQueue) KeyRef ref = new KeyRef(originalKey, refQueue); - + // Place the asset in the cache, but use a clone of // the original key. smartCache.put(ref.clonedKey, new AssetRef(asset, originalKey)); - + // Push the original key used to load the asset // so that it can be set on the clone later ArrayList loadStack = assetLoadStack.get(); @@ -146,9 +146,9 @@ public class WeakRefCloneAssetCache implements AssetCache { public void registerAssetClone(AssetKey key, T clone) { ArrayList loadStack = assetLoadStack.get(); - ((CloneableSmartAsset)clone).setKey(loadStack.remove(loadStack.size() - 1)); + ((CloneableSmartAsset) clone).setKey(loadStack.remove(loadStack.size() - 1)); } - + public void notifyNoAssetClone() { ArrayList loadStack = assetLoadStack.get(); loadStack.remove(loadStack.size() - 1); @@ -156,10 +156,10 @@ public class WeakRefCloneAssetCache implements AssetCache { public T getFromCache(AssetKey key) { AssetRef smartInfo; - synchronized (smartCache){ + synchronized (smartCache) { smartInfo = smartCache.get(key); } - + if (smartInfo == null) { return null; } else { @@ -167,40 +167,40 @@ public class WeakRefCloneAssetCache implements AssetCache { // can check this and determine that the asset clone // belongs to the asset retrieved here. AssetKey keyForTheClone = smartInfo.get(); - if (keyForTheClone == null){ + if (keyForTheClone == null) { // The asset was JUST collected by GC // (between here and smartCache.get) return null; } - + // Prevent original key from getting collected // while an asset is loaded for it. ArrayList loadStack = assetLoadStack.get(); loadStack.add(keyForTheClone); - + return (T) smartInfo.asset; } } public boolean deleteFromCache(AssetKey key) { ArrayList loadStack = assetLoadStack.get(); - - if (!loadStack.isEmpty()){ + + if (!loadStack.isEmpty()) { throw new UnsupportedOperationException("Cache cannot be modified" - + "while assets are being loaded"); + + "while assets are being loaded"); } - + return smartCache.remove(key) != null; } - + public void clearCache() { ArrayList loadStack = assetLoadStack.get(); - - if (!loadStack.isEmpty()){ + + if (!loadStack.isEmpty()) { throw new UnsupportedOperationException("Cache cannot be modified" - + "while assets are being loaded"); + + "while assets are being loaded"); } - + smartCache.clear(); } } 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 f6640a049..03f06f5a4 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 @@ -71,7 +71,7 @@ public class GLRenderer implements Renderer { private static final Logger logger = Logger.getLogger(GLRenderer.class.getName()); private static final boolean VALIDATE_SHADER = false; private static final Pattern GLVERSION_PATTERN = Pattern.compile(".*?(\\d+)\\.(\\d+).*"); - + private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250); private final StringBuilder stringBuf = new StringBuilder(250); private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1); @@ -81,7 +81,7 @@ public class GLRenderer implements Renderer { private final NativeObjectManager objManager = new NativeObjectManager(); private final EnumSet caps = EnumSet.noneOf(Caps.class); private final EnumMap limits = new EnumMap(Limits.class); - + // private int vertexTextureUnits; // private int fragTextureUnits; // private int vertexUniforms; @@ -110,7 +110,7 @@ public class GLRenderer implements Renderer { private final GLExt glext; private final GLFbo glfbo; private final TextureUtil texUtil; - + public GLRenderer(GL gl, GLFbo glfbo) { this.gl = gl; this.gl2 = gl instanceof GL2 ? (GL2)gl : null; @@ -129,7 +129,7 @@ public class GLRenderer implements Renderer { public EnumSet getCaps() { return caps; } - + // Not making public yet ... public EnumMap getLimits() { return limits; @@ -142,7 +142,7 @@ public class GLRenderer implements Renderer { } return extensionSet; } - + public static int extractVersion(String version) { Matcher m = GLVERSION_PATTERN.matcher(version); if (m.matches()) { @@ -162,17 +162,17 @@ public class GLRenderer implements Renderer { private boolean hasExtension(String extensionName) { return extensions.contains(extensionName); } - + private void loadCapabilitiesES() { caps.add(Caps.GLSL100); caps.add(Caps.OpenGLES20); - + // Important: Do not add OpenGL20 - that's the desktop capability! } - + private void loadCapabilitiesGL2() { int oglVer = extractVersion(gl.glGetString(GL.GL_VERSION)); - + if (oglVer >= 200) { caps.add(Caps.OpenGL20); if (oglVer >= 210) { @@ -194,9 +194,9 @@ public class GLRenderer implements Renderer { } } } - + int glslVer = extractVersion(gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION)); - + switch (glslVer) { default: if (glslVer < 400) { @@ -222,27 +222,27 @@ public class GLRenderer implements Renderer { caps.add(Caps.GLSL100); break; } - + // Workaround, always assume we support GLSL100 & GLSL110 // Supporting OpenGL 2.0 means supporting GLSL 1.10. caps.add(Caps.GLSL110); caps.add(Caps.GLSL100); - + // Fix issue in TestRenderToMemory when GL.GL_FRONT is the main // buffer being used. context.initialDrawBuf = getInteger(GL2.GL_DRAW_BUFFER); context.initialReadBuf = getInteger(GL2.GL_READ_BUFFER); - + // XXX: This has to be GL.GL_BACK for canvas on Mac // Since initialDrawBuf is GL.GL_FRONT for pbuffer, gotta // change this value later on ... // initialDrawBuf = GL.GL_BACK; // initialReadBuf = GL.GL_BACK; } - + private void loadCapabilitiesCommon() { extensions = loadExtensions(gl.glGetString(GL.GL_EXTENSIONS)); - + limits.put(Limits.VertexTextureUnits, getInteger(GL.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS)); if (limits.get(Limits.VertexTextureUnits) > 0) { caps.add(Caps.VertexTextureFetch); @@ -262,7 +262,7 @@ public class GLRenderer implements Renderer { limits.put(Limits.TextureSize, getInteger(GL.GL_MAX_TEXTURE_SIZE)); limits.put(Limits.CubemapSize, getInteger(GL.GL_MAX_CUBE_MAP_TEXTURE_SIZE)); - if (hasExtension("GL_ARB_draw_instanced") && + if (hasExtension("GL_ARB_draw_instanced") && hasExtension("GL_ARB_instanced_arrays")) { caps.add(Caps.MeshInstancing); } @@ -270,43 +270,43 @@ public class GLRenderer implements Renderer { if (hasExtension("GL_OES_element_index_uint") || gl2 != null) { caps.add(Caps.IntegerIndexBuffer); } - + if (hasExtension("GL_ARB_texture_buffer_object")) { caps.add(Caps.TextureBuffer); } - + // == texture format extensions == - + boolean hasFloatTexture = false; - hasFloatTexture = hasExtension("GL_OES_texture_half_float") && + hasFloatTexture = hasExtension("GL_OES_texture_half_float") && hasExtension("GL_OES_texture_float"); - + if (!hasFloatTexture) { hasFloatTexture = hasExtension("GL_ARB_texture_float") && hasExtension("GL_ARB_half_float_pixel"); - + if (!hasFloatTexture) { hasFloatTexture = caps.contains(Caps.OpenGL30); } } - + if (hasFloatTexture) { caps.add(Caps.FloatTexture); } - + if (hasExtension("GL_OES_depth_texture") || gl2 != null) { caps.add(Caps.DepthTexture); - + // TODO: GL_OES_depth24 } - - if (hasExtension("GL_OES_rgb8_rgba8") || - hasExtension("GL_ARM_rgba8") || + + if (hasExtension("GL_OES_rgb8_rgba8") || + hasExtension("GL_ARM_rgba8") || hasExtension("GL_EXT_texture_format_BGRA8888")) { caps.add(Caps.Rgba8); } - + if (caps.contains(Caps.OpenGL30) || hasExtension("GL_OES_packed_depth_stencil")) { caps.add(Caps.PackedDepthStencilBuffer); } @@ -321,35 +321,35 @@ public class GLRenderer implements Renderer { caps.add(Caps.FloatDepthBuffer); } - if ((hasExtension("GL_EXT_packed_float") && hasFloatTexture) || + if ((hasExtension("GL_EXT_packed_float") && hasFloatTexture) || caps.contains(Caps.OpenGL30)) { // Either OpenGL3 is available or both packed_float & half_float_pixel. caps.add(Caps.PackedFloatColorBuffer); caps.add(Caps.PackedFloatTexture); } - + if (hasExtension("GL_EXT_texture_shared_exponent") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.SharedExponentTexture); } - + if (hasExtension("GL_EXT_texture_compression_s3tc")) { caps.add(Caps.TextureCompressionS3TC); } - + if (hasExtension("GL_ARB_ES3_compatibility")) { caps.add(Caps.TextureCompressionETC2); caps.add(Caps.TextureCompressionETC1); } else if (hasExtension("GL_OES_compressed_ETC1_RGB8_texture")) { caps.add(Caps.TextureCompressionETC1); } - + // == end texture format extensions == - + if (hasExtension("GL_ARB_vertex_array_object") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.VertexBufferArray); } - if (hasExtension("GL_ARB_texture_non_power_of_two") || + if (hasExtension("GL_ARB_texture_non_power_of_two") || hasExtension("GL_OES_texture_npot") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.NonPowerOfTwoTextures); @@ -358,7 +358,7 @@ public class GLRenderer implements Renderer { + "support non-power-of-2 textures. " + "Some features might not work."); } - + if (caps.contains(Caps.OpenGLES20)) { // OpenGL ES 2 has some limited support for NPOT textures caps.add(Caps.PartialNonPowerOfTwoTextures); @@ -374,14 +374,14 @@ public class GLRenderer implements Renderer { if (hasExtension("GL_EXT_framebuffer_object")) { caps.add(Caps.FrameBuffer); - + limits.put(Limits.RenderBufferSize, getInteger(GLExt.GL_MAX_RENDERBUFFER_SIZE_EXT)); limits.put(Limits.FrameBufferAttachments, getInteger(GLExt.GL_MAX_COLOR_ATTACHMENTS_EXT)); - + if (hasExtension("GL_EXT_framebuffer_blit")) { caps.add(Caps.FrameBufferBlit); } - + if (hasExtension("GL_EXT_framebuffer_multisample")) { caps.add(Caps.FrameBufferMultisample); limits.put(Limits.FrameBufferSamples, getInteger(GLExt.GL_MAX_SAMPLES_EXT)); @@ -419,9 +419,9 @@ public class GLRenderer implements Renderer { } caps.add(Caps.Multisample); } - + // Supports sRGB pipeline. - if ( (hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB")) + if ( (hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB")) || caps.contains(Caps.OpenGL30) ) { caps.add(Caps.Srgb); } @@ -430,24 +430,24 @@ public class GLRenderer implements Renderer { if (hasExtension("GL_ARB_seamless_cube_map") || caps.contains(Caps.OpenGL32)) { caps.add(Caps.SeamlessCubemap); } - + // if (hasExtension("GL_ARB_get_program_binary")) { // int binaryFormats = getInteger(GLExt.GL_NUM_PROGRAM_BINARY_FORMATS); // } - + // Print context information logger.log(Level.INFO, "OpenGL Renderer Information\n" + " * Vendor: {0}\n" + " * Renderer: {1}\n" + " * OpenGL Version: {2}\n" + " * GLSL Version: {3}", - new Object[]{ - gl.glGetString(GL.GL_VENDOR), + new Object[]{ + gl.glGetString(GL.GL_VENDOR), gl.glGetString(GL.GL_RENDERER), gl.glGetString(GL.GL_VERSION), gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION) }); - + // Print capabilities (if fine logging is enabled) if (logger.isLoggable(Level.FINE)) { StringBuilder sb = new StringBuilder(); @@ -458,10 +458,10 @@ public class GLRenderer implements Renderer { } logger.log(Level.FINE, sb.toString()); } - + texUtil.initialize(caps); } - + private void loadCapabilities() { if (gl2 != null) { loadCapabilitiesGL2(); @@ -470,22 +470,22 @@ public class GLRenderer implements Renderer { } loadCapabilitiesCommon(); } - + private int getInteger(int en) { intBuf16.clear(); gl.glGetInteger(en, intBuf16); return intBuf16.get(0); } - + private boolean getBoolean(int en) { gl.glGetBoolean(en, nameBuf); return nameBuf.get(0) != (byte)0; } - + @SuppressWarnings("fallthrough") public void initialize() { loadCapabilities(); - + // Initialize default state.. gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); } @@ -579,7 +579,7 @@ public class GLRenderer implements Renderer { } if (state.isDepthTest() && !context.depthTestEnabled) { - gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthFunc(convertTestFunction(context.depthFunc)); context.depthTestEnabled = true; } else if (!state.isDepthTest() && context.depthTestEnabled) { @@ -718,7 +718,7 @@ public class GLRenderer implements Renderer { break; case Screen: gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_COLOR); - break; + break; case Exclusion: gl.glBlendFunc(GL.GL_ONE_MINUS_DST_COLOR, GL.GL_ONE_MINUS_SRC_COLOR); break; @@ -1043,12 +1043,12 @@ public class GLRenderer implements Renderer { boolean gles2 = caps.contains(Caps.OpenGLES20); String language = source.getLanguage(); - + if (gles2 && !language.equals("GLSL100")) { throw new RendererException("This shader cannot run in OpenGL ES 2. " + "Only GLSL 1.00 shaders are supported."); } - + // Upload shader source. // Merge the defines and source code. stringBuf.setLength(0); @@ -1075,14 +1075,14 @@ public class GLRenderer implements Renderer { } } } - + if (linearizeSrgbImages) { stringBuf.append("#define SRGB 1\n"); } - + stringBuf.append(source.getDefines()); stringBuf.append(source.getSource()); - + intBuf1.clear(); intBuf1.put(0, stringBuf.length()); gl.glShaderSource(id, new String[]{ stringBuf.toString() }, intBuf1); @@ -1140,7 +1140,7 @@ public class GLRenderer implements Renderer { // If using GLSL 1.5, we bind the outputs for the user // For versions 3.3 and up, user should use layout qualifiers instead. boolean bindFragDataRequired = false; - + for (ShaderSource source : shader.getSources()) { if (source.isUpdateNeeded()) { updateShaderSourceData(source); @@ -1412,7 +1412,7 @@ public class GLRenderer implements Renderer { } else if (attachmentSlot < 0 || attachmentSlot >= 16) { throw new UnsupportedOperationException("Invalid FBO attachment slot: " + attachmentSlot); } - + return GLExt.GL_COLOR_ATTACHMENT0_EXT + attachmentSlot; } @@ -1422,7 +1422,7 @@ public class GLRenderer implements Renderer { if (image.isUpdateNeeded()) { // Check NPOT requirements checkNonPowerOfTwo(tex); - + updateTexImageData(image, tex.getType(), 0); // NOTE: For depth textures, sets nearest/no-mips mode @@ -1583,7 +1583,7 @@ public class GLRenderer implements Renderer { // update viewport to reflect framebuffer's resolution setViewPort(0, 0, fb.getWidth(), fb.getHeight()); - + if (context.boundFBO != fb.getId()) { glfbo.glBindFramebufferEXT(GLExt.GL_FRAMEBUFFER_EXT, fb.getId()); statistics.onFrameBufferUse(fb, true); @@ -1656,7 +1656,7 @@ public class GLRenderer implements Renderer { public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { readFrameBufferWithGLFormat(fb, byteBuf, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); } - + private void readFrameBufferWithGLFormat(FrameBuffer fb, ByteBuffer byteBuf, int glFormat, int dataType) { if (fb != null) { RenderBuffer rb = fb.getColorBuffer(); @@ -1678,8 +1678,8 @@ public class GLRenderer implements Renderer { gl.glReadPixels(vpX, vpY, vpW, vpH, glFormat, dataType, byteBuf); } - - public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { + + public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { GLImageFormat glFormat = texUtil.getImageFormatWithError(format, false); readFrameBufferWithGLFormat(fb, byteBuf, glFormat.format, glFormat.dataType); } @@ -1716,10 +1716,10 @@ public class GLRenderer implements Renderer { \*********************************************************************/ private int convertTextureType(Texture.Type type, int samples, int face) { if (samples > 1 && !caps.contains(Caps.TextureMultisample)) { - throw new RendererException("Multisample textures are not supported" + + throw new RendererException("Multisample textures are not supported" + " by the video hardware."); } - + switch (type) { case TwoDimensional: if (samples > 1) { @@ -1739,7 +1739,7 @@ public class GLRenderer implements Renderer { } case ThreeDimensional: if (!caps.contains(Caps.OpenGL20)) { - throw new RendererException("3D textures are not supported" + + throw new RendererException("3D textures are not supported" + " by the video hardware."); } return GL2.GL_TEXTURE_3D; @@ -1823,11 +1823,11 @@ public class GLRenderer implements Renderer { int target = convertTextureType(tex.getType(), image != null ? image.getMultiSamples() : 1, -1); boolean haveMips = true; - + if (image != null) { haveMips = image.isGeneratedMipmapsRequired() || image.hasMipmaps(); } - + // filter things if (image.getLastTextureState().magFilter != tex.getMagFilter()) { int magFilter = convertMagFilter(tex.getMagFilter()); @@ -1850,7 +1850,7 @@ public class GLRenderer implements Renderer { context.seamlessCubemap = false; } } - + if (tex.getAnisotropicFilter() > 1) { if (caps.contains(Caps.TextureFilterAnisotropic)) { gl.glTexParameterf(target, @@ -1862,7 +1862,7 @@ public class GLRenderer implements Renderer { if (context.pointSprite) { return; // Attempt to fix glTexParameter crash for some ATI GPUs } - + // repeat modes switch (tex.getType()) { case ThreeDimensional: @@ -1891,7 +1891,7 @@ public class GLRenderer implements Renderer { // R to Texture compare mode if (tex.getShadowCompareMode() != Texture.ShadowCompareMode.Off) { gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL2.GL_COMPARE_R_TO_TEXTURE); - gl2.glTexParameteri(target, GL2.GL_DEPTH_TEXTURE_MODE, GL2.GL_INTENSITY); + gl2.glTexParameteri(target, GL2.GL_DEPTH_TEXTURE_MODE, GL2.GL_INTENSITY); if (tex.getShadowCompareMode() == Texture.ShadowCompareMode.GreaterOrEqual) { gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_FUNC, GL.GL_GEQUAL); } else { @@ -1899,7 +1899,7 @@ public class GLRenderer implements Renderer { } }else{ //restoring default value - gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL.GL_NONE); + gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL.GL_NONE); } tex.compareModeUpdated(); } @@ -1908,10 +1908,10 @@ public class GLRenderer implements Renderer { /** * Validates if a potentially NPOT texture is supported by the hardware. *

- * Textures with power-of-2 dimensions are supported on all hardware, however + * Textures with power-of-2 dimensions are supported on all hardware, however * non-power-of-2 textures may or may not be supported depending on which * texturing features are used. - * + * * @param tex The texture to validate. * @throws RendererException If the texture is not supported by the hardware */ @@ -1920,19 +1920,19 @@ public class GLRenderer implements Renderer { // Texture is power-of-2, safe to use. return; } - + if (caps.contains(Caps.NonPowerOfTwoTextures)) { // Texture is NPOT but it is supported by video hardware. return; } - + // Maybe we have some / partial support for NPOT? if (!caps.contains(Caps.PartialNonPowerOfTwoTextures)) { // Cannot use any type of NPOT texture (uncommon) throw new RendererException("non-power-of-2 textures are not " + "supported by the video hardware"); } - + // Partial NPOT supported.. if (tex.getMinFilter().usesMipMapLevels()) { throw new RendererException("non-power-of-2 textures with mip-maps " @@ -1959,10 +1959,10 @@ public class GLRenderer implements Renderer { throw new UnsupportedOperationException("unrecongized texture type"); } } - + /** * Uploads the given image to the GL driver. - * + * * @param img The image to upload * @param type How the data in the image argument should be interpreted. * @param unit The texture slot to be used to upload the image, not important @@ -1986,7 +1986,7 @@ public class GLRenderer implements Renderer { gl.glActiveTexture(GL.GL_TEXTURE0 + unit); context.boundTextureUnit = unit; } - + gl.glBindTexture(target, texId); context.boundTextures[unit] = img; @@ -2029,12 +2029,12 @@ public class GLRenderer implements Renderer { throw new RendererException("Multisample textures are not supported by the video hardware"); } } - + // Check if graphics card doesn't support depth textures if (img.getFormat().isDepthFormat() && !caps.contains(Caps.DepthTexture)) { throw new RendererException("Depth textures are not supported by the video hardware"); } - + if (target == GL.GL_TEXTURE_CUBE_MAP) { // Check max texture size before upload int cubeSize = limits.get(Limits.CubemapSize); @@ -2065,12 +2065,12 @@ public class GLRenderer implements Renderer { if (!caps.contains(Caps.TextureArray)) { throw new RendererException("Texture arrays not supported by graphics hardware"); } - + List data = img.getData(); - + // -1 index specifies prepare data for 2D Array texUtil.uploadTexture(img, target, -1, linearizeSrgbImages); - + for (int i = 0; i < data.size(); i++) { // upload each slice of 2D array in turn // this time with the appropriate index @@ -2101,7 +2101,7 @@ public class GLRenderer implements Renderer { if (image.isUpdateNeeded() || (image.isGeneratedMipmapsRequired() && !image.isMipmapsGenerated())) { // Check NPOT requirements checkNonPowerOfTwo(tex); - + updateTexImageData(image, tex.getType(), unit); } @@ -2222,7 +2222,7 @@ public class GLRenderer implements Renderer { //statistics.onVertexBufferUse(vb, false); } } - + int usage = convertUsage(vb.getUsage()); vb.getData().rewind(); @@ -2311,7 +2311,7 @@ public class GLRenderer implements Renderer { if (context.boundShaderProgram <= 0) { throw new IllegalStateException("Cannot render mesh without shader bound"); } - + Attribute attrib = context.boundShader.getAttribute(vb.getBufferType()); int loc = attrib.getLocation(); if (loc == -1) { @@ -2441,7 +2441,7 @@ public class GLRenderer implements Renderer { // What is this? throw new RendererException("Unexpected format for index buffer: " + indexBuf.getFormat()); } - + if (indexBuf.isUpdateNeeded()) { updateBufferData(indexBuf); } @@ -2556,7 +2556,7 @@ public class GLRenderer implements Renderer { if (interleavedData != null && interleavedData.isUpdateNeeded()) { updateBufferData(interleavedData); } - + if (instanceData != null) { setVertexAttrib(instanceData, null); } @@ -2606,11 +2606,11 @@ public class GLRenderer implements Renderer { } private void renderMeshDefault(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) { - + // Here while count is still passed in. Can be removed when/if // the method is collapsed again. -pspeed count = Math.max(mesh.getInstanceCount(), count); - + VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); if (interleavedData != null && interleavedData.isUpdateNeeded()) { updateBufferData(interleavedData); @@ -2628,7 +2628,7 @@ public class GLRenderer implements Renderer { setVertexAttrib(vb, null); } } - + for (VertexBuffer vb : mesh.getBufferList().getArray()) { if (vb.getBufferType() == Type.InterleavedData || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers @@ -2696,12 +2696,12 @@ public class GLRenderer implements Renderer { // Gamma correction if (!caps.contains(Caps.Srgb)) { // Not supported, sorry. - logger.warning("sRGB framebuffer is not supported " + - "by video hardware, but was requested."); - + logger.warning("sRGB framebuffer is not supported " + + "by video hardware, but was requested."); + return; } - + setFrameBuffer(null); if (enableSrgb) { diff --git a/jme3-core/src/main/java/com/jme3/shader/ShaderKey.java b/jme3-core/src/main/java/com/jme3/shader/ShaderKey.java index 9207c56aa..222c57af4 100644 --- a/jme3-core/src/main/java/com/jme3/shader/ShaderKey.java +++ b/jme3-core/src/main/java/com/jme3/shader/ShaderKey.java @@ -38,6 +38,7 @@ 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 { @@ -141,6 +142,18 @@ public class ShaderKey extends AssetKey { 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 shaderName.get(shaderType); + } + @Override public void write(JmeExporter ex) throws IOException{ super.write(ex); 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 727072e86..7ac4dd69f 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 @@ -49,6 +49,7 @@ import com.jme3.texture.image.ColorSpace; import com.jme3.util.PlaceholderAssets; import com.jme3.util.blockparser.BlockLanguageParser; import com.jme3.util.blockparser.Statement; + import java.io.IOException; import java.io.InputStream; import java.util.EnumMap; @@ -59,7 +60,7 @@ import java.util.logging.Logger; public class J3MLoader implements AssetLoader { private static final Logger logger = Logger.getLogger(J3MLoader.class.getName()); - // private ErrorLogger errors; + // private ErrorLogger errors; private ShaderNodeLoaderDelegate nodesLoaderDelegate; boolean isUseNodes = false; @@ -71,14 +72,14 @@ public class J3MLoader implements AssetLoader { private TechniqueDef technique; private RenderState renderState; - private EnumMap shaderLanguage; - private EnumMap shaderName; + private EnumMap shaderLanguage; + private EnumMap shaderName; private static final String whitespacePattern = "\\p{javaWhitespace}+"; - public J3MLoader(){ - shaderLanguage=new EnumMap(Shader.ShaderType.class); - shaderName=new EnumMap(Shader.ShaderType.class); + public J3MLoader() { + shaderLanguage = new EnumMap(Shader.ShaderType.class); + shaderName = new EnumMap(Shader.ShaderType.class); } @@ -94,21 +95,21 @@ public class J3MLoader implements AssetLoader { } for (Shader.ShaderType shaderType : Shader.ShaderType.values()) { - if(typeAndLang[0].equals(shaderType.toString()+"Shader")){ - readShaderDefinition(shaderType,split[1].trim(),typeAndLang[1]); + if (typeAndLang[0].equals(shaderType.toString() + "Shader")) { + readShaderDefinition(shaderType, split[1].trim(), typeAndLang[1]); } } } - private void readShaderDefinition(Shader.ShaderType shaderType,String name,String language){ - shaderName.put(shaderType,name); - shaderLanguage.put(shaderType,language); + private void readShaderDefinition(Shader.ShaderType shaderType, String name, String language) { + shaderName.put(shaderType, name); + shaderLanguage.put(shaderType, language); } // LightMode - private void readLightMode(String statement) throws IOException{ + private void readLightMode(String statement) throws IOException { String[] split = statement.split(whitespacePattern); - if (split.length != 2){ + if (split.length != 2) { throw new IOException("LightMode statement syntax incorrect"); } LightMode lm = LightMode.valueOf(split[1]); @@ -116,29 +117,29 @@ public class J3MLoader implements AssetLoader { } // ShadowMode - private void readShadowMode(String statement) throws IOException{ + private void readShadowMode(String statement) throws IOException { String[] split = statement.split(whitespacePattern); - if (split.length != 2){ + if (split.length != 2) { throw new IOException("ShadowMode statement syntax incorrect"); } ShadowMode sm = ShadowMode.valueOf(split[1]); technique.setShadowMode(sm); } - private Object readValue(VarType type, String value) throws IOException{ - if (type.isTextureType()){ + private Object readValue(VarType type, String value) throws IOException { + if (type.isTextureType()) { // String texturePath = readString("[\n;(//)(\\})]"); String texturePath = value.trim(); boolean flipY = false; boolean repeat = false; - if (texturePath.startsWith("Flip Repeat ")){ + if (texturePath.startsWith("Flip Repeat ")) { texturePath = texturePath.substring(12).trim(); flipY = true; repeat = true; - }else if (texturePath.startsWith("Flip ")){ + } else if (texturePath.startsWith("Flip ")) { texturePath = texturePath.substring(5).trim(); flipY = true; - }else if (texturePath.startsWith("Repeat ")){ + } else if (texturePath.startsWith("Repeat ")) { texturePath = texturePath.substring(7).trim(); repeat = true; } @@ -160,76 +161,76 @@ public class J3MLoader implements AssetLoader { Texture tex; try { tex = assetManager.loadTexture(texKey); - } catch (AssetNotFoundException ex){ + } catch (AssetNotFoundException ex) { logger.log(Level.WARNING, "Cannot locate {0} for material {1}", new Object[]{texKey, key}); tex = null; } - if (tex != null){ - if (repeat){ + if (tex != null) { + if (repeat) { tex.setWrap(WrapMode.Repeat); } - }else{ + } else { tex = new Texture2D(PlaceholderAssets.getPlaceholderImage(assetManager)); - if (repeat){ + if (repeat) { tex.setWrap(WrapMode.Repeat); } tex.setKey(texKey); } return tex; - }else{ + } else { String[] split = value.trim().split(whitespacePattern); - switch (type){ + switch (type) { case Float: - if (split.length != 1){ + if (split.length != 1) { throw new IOException("Float value parameter must have 1 entry: " + value); } - return Float.parseFloat(split[0]); + return Float.parseFloat(split[0]); case Vector2: - if (split.length != 2){ + if (split.length != 2) { throw new IOException("Vector2 value parameter must have 2 entries: " + value); } return new Vector2f(Float.parseFloat(split[0]), - Float.parseFloat(split[1])); + Float.parseFloat(split[1])); case Vector3: - if (split.length != 3){ + if (split.length != 3) { throw new IOException("Vector3 value parameter must have 3 entries: " + value); } return new Vector3f(Float.parseFloat(split[0]), - Float.parseFloat(split[1]), - Float.parseFloat(split[2])); + Float.parseFloat(split[1]), + Float.parseFloat(split[2])); case Vector4: - if (split.length != 4){ + if (split.length != 4) { throw new IOException("Vector4 value parameter must have 4 entries: " + value); } return new ColorRGBA(Float.parseFloat(split[0]), - Float.parseFloat(split[1]), - Float.parseFloat(split[2]), - Float.parseFloat(split[3])); + Float.parseFloat(split[1]), + Float.parseFloat(split[2]), + Float.parseFloat(split[3])); case Int: - if (split.length != 1){ + if (split.length != 1) { throw new IOException("Int value parameter must have 1 entry: " + value); } return Integer.parseInt(split[0]); case Boolean: - if (split.length != 1){ + if (split.length != 1) { throw new IOException("Boolean value parameter must have 1 entry: " + value); } return Boolean.parseBoolean(split[0]); default: - throw new UnsupportedOperationException("Unknown type: "+type); + throw new UnsupportedOperationException("Unknown type: " + type); } } } // [ "(" ")" ] [ ":" ] [-LINEAR] - private void readParam(String statement) throws IOException{ + private void readParam(String statement) throws IOException { String name; String defaultVal = null; ColorSpace colorSpace = null; String[] split = statement.split("-"); - if(split.length>1){ - if(split[1].equalsIgnoreCase("LINEAR")){ + if (split.length > 1) { + if (split[1].equalsIgnoreCase("LINEAR")) { colorSpace = ColorSpace.Linear; } statement = split[0].trim(); @@ -238,10 +239,10 @@ public class J3MLoader implements AssetLoader { split = statement.split(":"); // Parse default val - if (split.length == 1){ + if (split.length == 1) { // Doesn't contain default value - }else{ - if (split.length != 2){ + } else { + if (split.length != 2) { throw new IOException("Parameter statement syntax incorrect"); } statement = split[0].trim(); @@ -250,137 +251,137 @@ public class J3MLoader implements AssetLoader { // Parse ffbinding int startParen = statement.indexOf("("); - if (startParen != -1){ + if (startParen != -1) { // get content inside parentheses int endParen = statement.indexOf(")", startParen); - String bindingStr = statement.substring(startParen+1, endParen).trim(); + String bindingStr = statement.substring(startParen + 1, endParen).trim(); // don't care about bindingStr statement = statement.substring(0, startParen); } // Parse type + name split = statement.split(whitespacePattern); - if (split.length != 2){ + if (split.length != 2) { throw new IOException("Parameter statement syntax incorrect"); } VarType type; - if (split[0].equals("Color")){ + if (split[0].equals("Color")) { type = VarType.Vector4; - }else{ + } else { type = VarType.valueOf(split[0]); } name = split[1]; Object defaultValObj = null; - if (defaultVal != null){ + if (defaultVal != null) { defaultValObj = readValue(type, defaultVal); } - if(type.isTextureType()){ + if (type.isTextureType()) { materialDef.addMaterialParamTexture(type, name, colorSpace); - }else{ + } else { materialDef.addMaterialParam(type, name, defaultValObj); } } - private void readValueParam(String statement) throws IOException{ + private void readValueParam(String statement) throws IOException { // Use limit=1 incase filename contains colons String[] split = statement.split(":", 2); - if (split.length != 2){ + if (split.length != 2) { throw new IOException("Value parameter statement syntax incorrect"); } String name = split[0].trim(); // parse value MatParam p = material.getMaterialDef().getMaterialParam(name); - if (p == null){ - throw new IOException("The material parameter: "+name+" is undefined."); + if (p == null) { + throw new IOException("The material parameter: " + name + " is undefined."); } Object valueObj = readValue(p.getVarType(), split[1]); - if (p.getVarType().isTextureType()){ + if (p.getVarType().isTextureType()) { material.setTextureParam(name, p.getVarType(), (Texture) valueObj); - }else{ + } else { material.setParam(name, p.getVarType(), valueObj); } } - private void readMaterialParams(List paramsList) throws IOException{ - for (Statement statement : paramsList){ + private void readMaterialParams(List paramsList) throws IOException { + for (Statement statement : paramsList) { readParam(statement.getLine()); } } - private void readExtendingMaterialParams(List paramsList) throws IOException{ - for (Statement statement : paramsList){ + private void readExtendingMaterialParams(List paramsList) throws IOException { + for (Statement statement : paramsList) { readValueParam(statement.getLine()); } } - private void readWorldParams(List worldParams) throws IOException{ - for (Statement statement : worldParams){ + private void readWorldParams(List worldParams) throws IOException { + for (Statement statement : worldParams) { technique.addWorldParam(statement.getLine()); } } - private boolean parseBoolean(String word){ + private boolean parseBoolean(String word) { return word != null && word.equals("On"); } - private void readRenderStateStatement(Statement statement) throws IOException{ + private void readRenderStateStatement(Statement statement) throws IOException { String[] split = statement.getLine().split(whitespacePattern); - if (split[0].equals("Wireframe")){ + if (split[0].equals("Wireframe")) { renderState.setWireframe(parseBoolean(split[1])); - }else if (split[0].equals("FaceCull")){ + } else if (split[0].equals("FaceCull")) { renderState.setFaceCullMode(FaceCullMode.valueOf(split[1])); - }else if (split[0].equals("DepthWrite")){ + } else if (split[0].equals("DepthWrite")) { renderState.setDepthWrite(parseBoolean(split[1])); - }else if (split[0].equals("DepthTest")){ + } else if (split[0].equals("DepthTest")) { renderState.setDepthTest(parseBoolean(split[1])); - }else if (split[0].equals("Blend")){ + } else if (split[0].equals("Blend")) { renderState.setBlendMode(BlendMode.valueOf(split[1])); - }else if (split[0].equals("AlphaTestFalloff")){ + } else if (split[0].equals("AlphaTestFalloff")) { renderState.setAlphaTest(true); renderState.setAlphaFallOff(Float.parseFloat(split[1])); - }else if (split[0].equals("PolyOffset")){ + } else if (split[0].equals("PolyOffset")) { float factor = Float.parseFloat(split[1]); float units = Float.parseFloat(split[2]); renderState.setPolyOffset(factor, units); - }else if (split[0].equals("ColorWrite")){ + } else if (split[0].equals("ColorWrite")) { renderState.setColorWrite(parseBoolean(split[1])); - }else if (split[0].equals("PointSprite")){ + } else if (split[0].equals("PointSprite")) { renderState.setPointSprite(parseBoolean(split[1])); - }else if (split[0].equals("DepthFunc")){ + } else if (split[0].equals("DepthFunc")) { renderState.setDepthFunc(RenderState.TestFunction.valueOf(split[1])); - }else if (split[0].equals("AlphaFunc")){ + } else if (split[0].equals("AlphaFunc")) { renderState.setAlphaFunc(RenderState.TestFunction.valueOf(split[1])); } else { throw new MatParseException(null, split[0], statement); } } - private void readAdditionalRenderState(List renderStates) throws IOException{ + private void readAdditionalRenderState(List renderStates) throws IOException { renderState = material.getAdditionalRenderState(); - for (Statement statement : renderStates){ + for (Statement statement : renderStates) { readRenderStateStatement(statement); } renderState = null; } - private void readRenderState(List renderStates) throws IOException{ + private void readRenderState(List renderStates) throws IOException { renderState = new RenderState(); - for (Statement statement : renderStates){ + for (Statement statement : renderStates) { readRenderStateStatement(statement); } technique.setRenderState(renderState); renderState = null; } - private void readForcedRenderState(List renderStates) throws IOException{ + private void readForcedRenderState(List renderStates) throws IOException { renderState = new RenderState(); - for (Statement statement : renderStates){ + for (Statement statement : renderStates) { readRenderStateStatement(statement); } technique.setForcedRenderState(renderState); @@ -388,41 +389,44 @@ public class J3MLoader implements AssetLoader { } // [ ":" ] - private void readDefine(String statement) throws IOException{ + private void readDefine(String statement) throws IOException { String[] split = statement.split(":"); - if (split.length == 1){ + if (split.length == 1) { // add preset define technique.addShaderPresetDefine(split[0].trim(), VarType.Boolean, true); - }else if (split.length == 2){ + } else if (split.length == 2) { technique.addShaderParamDefine(split[1].trim(), split[0].trim()); - }else{ + } else { throw new IOException("Define syntax incorrect"); } } - private void readDefines(List defineList) throws IOException{ - for (Statement statement : defineList){ + private void readDefines(List defineList) throws IOException { + for (Statement statement : defineList) { readDefine(statement.getLine()); } } - private void readTechniqueStatement(Statement statement) throws IOException{ + private void readTechniqueStatement(Statement statement) throws IOException { String[] split = statement.getLine().split("[ \\{]"); if (split[0].equals("VertexShader") || - split[0].equals("FragmentShader")){ + split[0].equals("FragmentShader") || + split[0].equals("GeometryShader") || + split[0].equals("TesselationControlShader") || + split[0].equals("TesselationEvaluationShader")) { readShaderStatement(statement.getLine()); - }else if (split[0].equals("LightMode")){ + } else if (split[0].equals("LightMode")) { readLightMode(statement.getLine()); - }else if (split[0].equals("ShadowMode")){ + } else if (split[0].equals("ShadowMode")) { readShadowMode(statement.getLine()); - }else if (split[0].equals("WorldParameters")){ + } else if (split[0].equals("WorldParameters")) { readWorldParams(statement.getContents()); - }else if (split[0].equals("RenderState")){ + } else if (split[0].equals("RenderState")) { readRenderState(statement.getContents()); - }else if (split[0].equals("ForcedRenderState")){ + } else if (split[0].equals("ForcedRenderState")) { readForcedRenderState(statement.getContents()); - }else if (split[0].equals("Defines")){ + } else if (split[0].equals("Defines")) { readDefines(statement.getContents()); } else if (split[0].equals("ShaderNodesDefinitions")) { initNodesLoader(); @@ -444,15 +448,15 @@ public class J3MLoader implements AssetLoader { } } - private void readTransparentStatement(String statement) throws IOException{ + private void readTransparentStatement(String statement) throws IOException { String[] split = statement.split(whitespacePattern); - if (split.length != 2){ + if (split.length != 2) { throw new IOException("Transparent statement syntax incorrect"); } material.setTransparent(parseBoolean(split[1])); } - private void readTechnique(Statement techStat) throws IOException{ + private void readTechnique(Statement techStat) throws IOException { isUseNodes = false; String[] split = techStat.getLine().split(whitespacePattern); if (split.length == 1) { @@ -464,18 +468,18 @@ public class J3MLoader implements AssetLoader { throw new IOException("Technique statement syntax incorrect"); } - for (Statement statement : techStat.getContents()){ + for (Statement statement : techStat.getContents()) { readTechniqueStatement(statement); } - if(isUseNodes){ + if (isUseNodes) { nodesLoaderDelegate.computeConditions(); //used for caching later, the shader here is not a file. technique.setShaderFile(technique.hashCode() + "", technique.hashCode() + "", "GLSL100", "GLSL100"); } - if(shaderName.containsKey(Shader.ShaderType.Vertex) && shaderName.containsKey(Shader.ShaderType.Fragment)){ - technique.setShaderFile(shaderName,shaderLanguage); + if (shaderName.containsKey(Shader.ShaderType.Vertex) && shaderName.containsKey(Shader.ShaderType.Fragment)) { + technique.setShaderFile(shaderName, shaderLanguage); } materialDef.addTechniqueDef(technique); @@ -484,40 +488,40 @@ public class J3MLoader implements AssetLoader { shaderName.clear(); } - private void loadFromRoot(List roots) throws IOException{ - if (roots.size() == 2){ + private void loadFromRoot(List roots) throws IOException { + if (roots.size() == 2) { Statement exception = roots.get(0); String line = exception.getLine(); - if (line.startsWith("Exception")){ + if (line.startsWith("Exception")) { throw new AssetLoadException(line.substring("Exception ".length())); - }else{ + } else { throw new IOException("In multiroot material, expected first statement to be 'Exception'"); } - }else if (roots.size() != 1){ + } else if (roots.size() != 1) { throw new IOException("Too many roots in J3M/J3MD file"); } boolean extending = false; Statement materialStat = roots.get(0); String materialName = materialStat.getLine(); - if (materialName.startsWith("MaterialDef")){ + if (materialName.startsWith("MaterialDef")) { materialName = materialName.substring("MaterialDef ".length()).trim(); extending = false; - }else if (materialName.startsWith("Material")){ + } else if (materialName.startsWith("Material")) { materialName = materialName.substring("Material ".length()).trim(); extending = true; - }else{ + } else { throw new IOException("Specified file is not a Material file"); } String[] split = materialName.split(":", 2); - if (materialName.equals("")){ + if (materialName.equals("")) { throw new MatParseException("Material name cannot be empty", materialStat); } - if (split.length == 2){ - if (!extending){ + if (split.length == 2) { + if (!extending) { throw new MatParseException("Must use 'Material' when extending.", materialStat); } @@ -531,35 +535,35 @@ public class J3MLoader implements AssetLoader { material = new Material(def); material.setKey(key); // material.setAssetName(fileName); - }else if (split.length == 1){ - if (extending){ + } else if (split.length == 1) { + if (extending) { throw new MatParseException("Expected ':', got '{'", materialStat); } materialDef = new MaterialDef(assetManager, materialName); // NOTE: pass file name for defs so they can be loaded later materialDef.setAssetName(key.getName()); - }else{ + } else { throw new MatParseException("Cannot use colon in material name/path", materialStat); } - for (Statement statement : materialStat.getContents()){ + for (Statement statement : materialStat.getContents()) { split = statement.getLine().split("[ \\{]"); String statType = split[0]; - if (extending){ - if (statType.equals("MaterialParameters")){ + if (extending) { + if (statType.equals("MaterialParameters")) { readExtendingMaterialParams(statement.getContents()); - }else if (statType.equals("AdditionalRenderState")){ + } else if (statType.equals("AdditionalRenderState")) { readAdditionalRenderState(statement.getContents()); - }else if (statType.equals("Transparent")){ + } else if (statType.equals("Transparent")) { readTransparentStatement(statement.getLine()); } - }else{ - if (statType.equals("Technique")){ + } else { + if (statType.equals("Technique")) { readTechnique(statement); - }else if (statType.equals("MaterialParameters")){ + } else if (statType.equals("MaterialParameters")) { readMaterialParams(statement.getContents()); - }else{ - throw new MatParseException("Expected material statement, got '"+statType+"'", statement); + } else { + throw new MatParseException("Expected material statement, got '" + statType + "'", statement); } } } @@ -573,18 +577,18 @@ public class J3MLoader implements AssetLoader { key = info.getKey(); loadFromRoot(BlockLanguageParser.parse(in)); } finally { - if (in != null){ + if (in != null) { in.close(); } } - if (material != null){ - if (!(info.getKey() instanceof MaterialKey)){ + if (material != null) { + if (!(info.getKey() instanceof MaterialKey)) { throw new IOException("Material instances must be loaded via MaterialKey"); } // material implementation return material; - }else{ + } else { // material definition return materialDef; } @@ -601,9 +605,9 @@ public class J3MLoader implements AssetLoader { if (!isUseNodes) { isUseNodes = shaderName.get(Shader.ShaderType.Vertex) == null && shaderName.get(Shader.ShaderType.Fragment) == null; if (isUseNodes) { - if(nodesLoaderDelegate == null){ + if (nodesLoaderDelegate == null) { nodesLoaderDelegate = new ShaderNodeLoaderDelegate(); - }else{ + } else { nodesLoaderDelegate.clear(); } nodesLoaderDelegate.setTechniqueDef(technique); diff --git a/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.frag b/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.frag new file mode 100644 index 000000000..636af0c7e --- /dev/null +++ b/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.frag @@ -0,0 +1,3 @@ +void main(){ + gl_FragColor=vec4(1.0,0.0,1.0,0.5); +} \ No newline at end of file diff --git a/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.geom b/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.geom new file mode 100644 index 000000000..e0c5d7b9e --- /dev/null +++ b/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.geom @@ -0,0 +1,19 @@ +layout (points) in; +layout (line_strip) out; +layout (max_vertices = 11) out; + +uniform mat4 g_WorldViewProjectionMatrix; +const float PI = 3.1415926; +void main(){ + for (int i = 0; i <= 10; i++) { + + float ang = PI * 2.0 / 10.0 * i; + vec4 offset = vec4(cos(ang) * 5, -sin(ang) * 5, 0.0, 0.0); + gl_Position = g_WorldViewProjectionMatrix*vec4(gl_in[0].gl_Position.xyz + offset.xyz,1.0); + + EmitVertex(); + } + + EndPrimitive(); +} + diff --git a/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.j3m b/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.j3m new file mode 100644 index 000000000..25ac6a523 --- /dev/null +++ b/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.j3m @@ -0,0 +1,4 @@ +Material Pong Rock : Materials/Geom/SimpleGeom.j3md { + MaterialParameters { + } +} \ No newline at end of file diff --git a/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.j3md b/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.j3md new file mode 100644 index 000000000..4ae79e3ed --- /dev/null +++ b/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.j3md @@ -0,0 +1,17 @@ +MaterialDef SimpleGeom { + + MaterialParameters { + + } + + Technique { + VertexShader GLSL330: Materials/Geom/SimpleGeom.vert + GeometryShader GLSL330: Materials/Geom/SimpleGeom.geom + FragmentShader GLSL330: Materials/Geom/SimpleGeom.frag + + WorldParameters { + WorldViewProjectionMatrix + } + } + +} \ No newline at end of file diff --git a/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.vert b/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.vert new file mode 100644 index 000000000..f82ebb79b --- /dev/null +++ b/jme3-testdata/src/main/resources/Materials/Geom/SimpleGeom.vert @@ -0,0 +1,5 @@ +attribute vec3 inPosition; + +void main(){ + gl_Position=vec4(inPosition,1); +} \ No newline at end of file