diff --git a/.gitignore b/.gitignore index 49ca1902d..be1334611 100644 --- a/.gitignore +++ b/.gitignore @@ -1,34 +1,22 @@ +**/nbproject/private/ /.gradle/ -/.nb-gradle/private/ -/.nb-gradle/profiles/private/ +/.nb-gradle/ /.idea/ /dist/ /build/ +/bin/ /netbeans/ -/sdk/jdks/local/ -/jme3-core/build/ +/.classpath +/.project +/.settings +*.dll +*.so +*.jnilib +*.dylib +*.iml +.DS_Store /jme3-core/src/main/resources/com/jme3/system/version.properties -/jme3-plugins/build/ -/jme3-desktop/build/ -/jme3-android-native/build/ -/jme3-android/build/ -/jme3-android-examples/build/ -/jme3-blender/build/ -/jme3-effects/build/ -/jme3-bullet/build/ -/jme3-terrain/build/ -/jme3-bullet-native/build/ -/jme3-bullet-native-android/build/ -/jme3-jogg/build/ -/jme3-jbullet/build/ -/jme3-lwjgl/build/ -/jme3-networking/build/ -/jme3-niftygui/build/ -/jme3-testdata/build/ -/jme3-examples/build/ -/jme3-jogl/build/ -/jme3-ios/build/ -/jme3-gl-autogen/build/ +/jme3-*/build/ /jme3-bullet-native/bullet.zip /jme3-bullet-native/bullet-2.82-r2704/ /jme3-android-native/openal-soft/ @@ -38,113 +26,9 @@ /jme3-android-native/src/native/jme_decode/com_jme3_audio_plugins_NativeVorbisFile.h /jme3-android-native/src/native/jme_decode/com_jme3_texture_plugins_AndroidNativeImageLoader.h /jme3-android-native/stb_image.h -/sdk/jme3-tests-template/src/com/jme3/gde/templates/tests/JmeTestsProject.zip -/sdk/jme3-tests-template/src/com/jme3/gde/templates/tests/JME3TestsAndroidProject.zip -/sdk/jme3-project-testdata/release/ -/sdk/JME3TestsTemplateAndroid/src/jme3test/ -/sdk/JME3TestsTemplate/src/jme3test/ -/sdk/build/ -/sdk/jme3-core-baselibs/release/ -/sdk/jme3-core-libraries/release/ -/sdk/jme3-project-baselibs/release/ -/sdk/jme3-project-libraries/release/ -/sdk/jme3-codepalette/build/ -/sdk/jme3-core-libraries/build/ -/sdk/jme3-code-check/build/ -/sdk/jme3-core-baselibs/build/ -/sdk/jme3-documentation/build/ -/sdk/jme3-core-updatecenters/build/ -/sdk/jme3-project-testdata/build/ -/sdk/jme3-project-libraries/build/ -/sdk/jme3-project-baselibs/build/ -/sdk/jme3-templates/build/ -/sdk/jme3-texture-editor/build/ -/sdk/jme3-tests-template/build/ -/sdk/jme3-upgrader/build/ -/sdk/jme3-core/build/ -/sdk/jme3-obfuscate/build/ -/sdk/jme3-gui/build/ -/sdk/jme3-cinematics/build/ -/sdk/jme3-terrain-editor/build/ -/sdk/jme3-lwjgl-applet/build/ -/sdk/jme3-blender/build/ -/sdk/jme3-navmesh-gen/build/ -/sdk/jme3-angelfont/build/ -/sdk/jme3-materialeditor/build/ -/sdk/jme3-android/build/ -/sdk/jme3-desktop-executables/build/ -/sdk/jme3-ogrexml/build/ -/sdk/jme3-ogretools/build/ -/sdk/jme3-scenecomposer/build/ -/sdk/jme3-assetpack-support/build/ -/sdk/jme3-model-importer/build/ -/sdk/jme3-wavefront/build/ -/sdk/jme3-vehicle-creator/build/ -/sdk/jme3-welcome-screen/build/ -/sdk/jme3-glsl-support/build/ -/sdk/jme3-dark-laf/build/ -/sdk/nbproject/private/ -/sdk/jme3-scenecomposer/nbproject/private/ -/sdk/jme3-core/nbproject/private/ -/sdk/jme3-core-baselibs/nbproject/private/ -/sdk/jme3-welcome-screen/nbproject/private/ -/sdk/jme3-lwjgl-applet/nbproject/private/ -/sdk/jme3-ogrexml/nbproject/private/ -/sdk/jme3-upgrader/nbproject/private/ -/sdk/jme3-obfuscate/nbproject/private/ -/sdk/jme3-navmesh-gen/nbproject/private/ -/sdk/jme3-wavefront/nbproject/private/ -/sdk/jme3-project-libraries/nbproject/private/ -/sdk/jme3-ogretools/nbproject/private/ -/sdk/jme3-assetpack-support/nbproject/private/ -/sdk/jme3-cinematics/nbproject/private/ -/sdk/jme3-model-importer/nbproject/private/ -/sdk/jme3-desktop-executables/nbproject/private/ -/sdk/jme3-glsl-support/nbproject/private/ -/sdk/jme3-android/nbproject/private/ -/sdk/jme3-angelfont/nbproject/private/ -/sdk/jme3-codepalette/nbproject/private/ -/sdk/jme3-documentation/nbproject/private/ -/sdk/jme3-vehicle-creator/nbproject/private/ -/sdk/jme3-code-check/nbproject/private/ -/sdk/jme3-blender/nbproject/private/ -/sdk/jme3-core-libraries/nbproject/private/ -/sdk/jme3-core-updatecenters/nbproject/private/ -/sdk/jme3-gui/nbproject/private/ -/sdk/jme3-materialeditor/nbproject/private/ -/sdk/jme3-project-baselibs/nbproject/private/ -/sdk/jme3-project-testdata/nbproject/private/ -/sdk/jme3-templates/nbproject/private/ -/sdk/jme3-terrain-editor/nbproject/private/ -/sdk/jme3-tests-template/nbproject/private/ -/sdk/jme3-texture-editor/nbproject/private/ -/sdk/JME3TestsTemplate/nbproject/private/ -/sdk/JME3TestsTemplateAndroid/nbproject/private/ -/bin -/.classpath -/.project -/.settings -*.dll -*.so -*.jnilib -*.dylib -*.iml -.DS_Store -/sdk/dist/ !/jme3-bullet-native/libs/native/windows/x86_64/bulletjme.dll !/jme3-bullet-native/libs/native/windows/x86/bulletjme.dll !/jme3-bullet-native/libs/native/osx/x86/libbulletjme.dylib !/jme3-bullet-native/libs/native/osx/x86_64/libbulletjme.dylib !/jme3-bullet-native/libs/native/linux/x86/libbulletjme.so !/jme3-bullet-native/libs/native/linux/x86_64/libbulletjme.so -/.nb-gradle/ -/sdk/ant-jme/nbproject/private/ -/sdk/nbi/stub/ext/engine/nbproject/private/ -/sdk/nbi/stub/ext/components/products/jdk/nbproject/private/ -/sdk/nbi/stub/ext/components/products/blender/nbproject/private/ -/sdk/nbi/stub/ext/components/products/helloworld/nbproject/private/ -/sdk/BasicGameTemplate/nbproject/private/ -/sdk/nbi/stub/ext/components/products/jdk/build/ -/sdk/nbi/stub/ext/components/products/jdk/dist/ -/sdk/jme3-dark-laf/nbproject/private/ -jme3-lwjgl3/build/ diff --git a/common.gradle b/common.gradle index 2cad48bf2..9a4aba272 100644 --- a/common.gradle +++ b/common.gradle @@ -51,6 +51,12 @@ javadoc { } } +test { + testLogging { + exceptionFormat = 'full' + } +} + task sourcesJar(type: Jar, dependsOn: classes, description: 'Creates a jar from the source files.') { classifier = 'sources' from sourceSets*.allSource diff --git a/jme3-android/src/main/java/com/jme3/asset/AndroidImageInfo.java b/jme3-android/src/main/java/com/jme3/asset/AndroidImageInfo.java deleted file mode 100644 index 8d064f5fe..000000000 --- a/jme3-android/src/main/java/com/jme3/asset/AndroidImageInfo.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.jme3.asset; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Matrix; -import com.jme3.math.ColorRGBA; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.texture.image.ImageRaster; -import java.io.IOException; -import java.io.InputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * AndroidImageInfo is set in a jME3 image via the {@link Image#setEfficentData(java.lang.Object) } - * method to retrieve a {@link Bitmap} when it is needed by the renderer. - * User code may extend AndroidImageInfo and provide their own implementation of the - * {@link AndroidImageInfo#loadBitmap()} method to acquire a bitmap by their own means. - * - * @author Kirill Vainer - */ -@Deprecated -public class AndroidImageInfo extends ImageRaster { - - private static final Logger logger = Logger.getLogger(AndroidImageInfo.class.getName()); - - protected AssetInfo assetInfo; - protected Bitmap bitmap; - protected Format format; - - public AndroidImageInfo(AssetInfo assetInfo) { - this.assetInfo = assetInfo; - } - - public Bitmap getBitmap(){ - if (bitmap == null || bitmap.isRecycled()){ - try { - loadBitmap(); - } catch (IOException ex) { - // If called first inside AssetManager, the error will propagate - // correctly. Assuming that if the first calls succeeds - // then subsequent calls will as well. - throw new AssetLoadException("Failed to load image " + assetInfo.getKey(), ex); - } - } - return bitmap; - } - - public void notifyBitmapUploaded() { - // Default function is to recycle the bitmap. - if (bitmap != null && !bitmap.isRecycled()) { - bitmap.recycle(); - bitmap = null; - logger.log(Level.FINE, "Bitmap was deleted. "); - } - } - - public Format getFormat(){ - return format; - } - - @Override - public int getWidth() { - return getBitmap().getWidth(); - } - - @Override - public int getHeight() { - return getBitmap().getHeight(); - } - - @Override - public void setPixel(int x, int y, ColorRGBA color) { - getBitmap().setPixel(x, y, color.asIntARGB()); - } - - @Override - public ColorRGBA getPixel(int x, int y, ColorRGBA store) { - if (store == null) { - store = new ColorRGBA(); - } - store.fromIntARGB(getBitmap().getPixel(x, y)); - return store; - } - - /** - * Loads the bitmap directly from the asset info, possibly updating - * or creating the image object. - */ - protected void loadBitmap() throws IOException{ - InputStream in = null; - try { - in = assetInfo.openStream(); - bitmap = BitmapFactory.decodeStream(in); - if (bitmap == null) { - throw new IOException("Failed to load image: " + assetInfo.getKey().getName()); - } - } finally { - if (in != null) { - in.close(); - } - } - - switch (bitmap.getConfig()) { - case ALPHA_8: - format = Image.Format.Alpha8; - break; - case ARGB_8888: - format = Image.Format.RGBA8; - break; - case RGB_565: - format = Image.Format.RGB565; - break; - default: - // This should still work as long - // as renderer doesn't check format - // but just loads bitmap directly. - format = null; - } - - TextureKey texKey = (TextureKey) assetInfo.getKey(); - if (texKey.isFlipY()) { - // Flip the image, then delete the old one. - Matrix flipMat = new Matrix(); - flipMat.preScale(1.0f, -1.0f); - Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), flipMat, false); - bitmap.recycle(); - bitmap = newBitmap; - - if (bitmap == null) { - throw new IOException("Failed to flip image: " + texKey); - } - } - } -} diff --git a/jme3-android/src/main/java/com/jme3/audio/android/AndroidMediaPlayerAudioRenderer.java b/jme3-android/src/main/java/com/jme3/audio/android/AndroidMediaPlayerAudioRenderer.java deleted file mode 100644 index 394cc257b..000000000 --- a/jme3-android/src/main/java/com/jme3/audio/android/AndroidMediaPlayerAudioRenderer.java +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Copyright (c) 2009-2012 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.audio.android; - -import android.app.Activity; -import android.content.Context; -import android.content.res.AssetFileDescriptor; -import android.content.res.AssetManager; -import android.media.AudioManager; -import android.media.MediaPlayer; -import android.media.SoundPool; -import com.jme3.asset.AssetKey; -import com.jme3.audio.*; -import com.jme3.audio.AudioSource.Status; -import com.jme3.audio.openal.ALAudioRenderer; -import com.jme3.math.FastMath; -import com.jme3.math.Vector3f; -import java.io.IOException; -import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * This class is the android implementation for {@link AudioRenderer} - * - * @author larynx - * @author plan_rich - * - * @deprecated No longer supported due to too many limitations. - * Please use the generic {@link ALAudioRenderer} instead. - */ -@Deprecated -public class AndroidMediaPlayerAudioRenderer implements AudioRenderer, - SoundPool.OnLoadCompleteListener, MediaPlayer.OnCompletionListener { - - private static final Logger logger = Logger.getLogger(AndroidMediaPlayerAudioRenderer.class.getName()); - private final static int MAX_NUM_CHANNELS = 16; - private final HashMap musicPlaying = new HashMap(); - private SoundPool soundPool = null; - private final Vector3f listenerPosition = new Vector3f(); - // For temp use - private final Vector3f distanceVector = new Vector3f(); - private final AssetManager assetManager; - private HashMap soundpoolStillLoading = new HashMap(); - private Listener listener; - private boolean audioDisabled = false; - private final AudioManager manager; - - public AndroidMediaPlayerAudioRenderer(Activity context) { - manager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - context.setVolumeControlStream(AudioManager.STREAM_MUSIC); - assetManager = context.getAssets(); - } - - @Override - public void initialize() { - soundPool = new SoundPool(MAX_NUM_CHANNELS, AudioManager.STREAM_MUSIC, - 0); - soundPool.setOnLoadCompleteListener(this); - } - - @Override - public void updateSourceParam(AudioSource src, AudioParam param) { - if (audioDisabled) { - return; - } - - if (src.getChannel() < 0) { - return; - } - - switch (param) { - case Position: - if (!src.isPositional()) { - return; - } - - Vector3f pos = src.getPosition(); - break; - case Velocity: - if (!src.isPositional()) { - return; - } - - Vector3f vel = src.getVelocity(); - break; - case MaxDistance: - if (!src.isPositional()) { - return; - } - break; - case RefDistance: - if (!src.isPositional()) { - return; - } - break; - case ReverbFilter: - if (!src.isPositional() || !src.isReverbEnabled()) { - return; - } - break; - case ReverbEnabled: - if (!src.isPositional()) { - return; - } - - if (src.isReverbEnabled()) { - updateSourceParam(src, AudioParam.ReverbFilter); - } - break; - case IsPositional: - break; - case Direction: - if (!src.isDirectional()) { - return; - } - - Vector3f dir = src.getDirection(); - break; - case InnerAngle: - if (!src.isDirectional()) { - return; - } - break; - case OuterAngle: - if (!src.isDirectional()) { - return; - } - break; - case IsDirectional: - if (src.isDirectional()) { - updateSourceParam(src, AudioParam.Direction); - updateSourceParam(src, AudioParam.InnerAngle); - updateSourceParam(src, AudioParam.OuterAngle); - } else { - } - break; - case DryFilter: - if (src.getDryFilter() != null) { - Filter f = src.getDryFilter(); - if (f.isUpdateNeeded()) { - // updateFilter(f); - } - } - break; - case Looping: - if (src.isLooping()) { - } - break; - case Volume: - MediaPlayer mp = musicPlaying.get(src); - if (mp != null) { - mp.setVolume(src.getVolume(), src.getVolume()); - } else { - soundPool.setVolume(src.getChannel(), src.getVolume(), - src.getVolume()); - } - - break; - case Pitch: - - break; - } - - } - - @Override - public void updateListenerParam(Listener listener, ListenerParam param) { - if (audioDisabled) { - return; - } - - switch (param) { - case Position: - listenerPosition.set(listener.getLocation()); - break; - case Rotation: - Vector3f dir = listener.getDirection(); - Vector3f up = listener.getUp(); - - break; - case Velocity: - Vector3f vel = listener.getVelocity(); - - break; - case Volume: - // alListenerf(AL_GAIN, listener.getVolume()); - break; - } - - } - - @Override - public void update(float tpf) { - float distance; - float volume; - - // Loop over all mediaplayers - for (AudioSource src : musicPlaying.keySet()) { - - MediaPlayer mp = musicPlaying.get(src); - - // Calc the distance to the listener - distanceVector.set(listenerPosition); - distanceVector.subtractLocal(src.getPosition()); - distance = FastMath.abs(distanceVector.length()); - - if (distance < src.getRefDistance()) { - distance = src.getRefDistance(); - } - if (distance > src.getMaxDistance()) { - distance = src.getMaxDistance(); - } - volume = src.getRefDistance() / distance; - - AndroidAudioData audioData = (AndroidAudioData) src.getAudioData(); - - if (FastMath.abs(audioData.getCurrentVolume() - volume) > FastMath.FLT_EPSILON) { - // Left / Right channel get the same volume by now, only - // positional - mp.setVolume(volume, volume); - - audioData.setCurrentVolume(volume); - } - - } - } - - public void setListener(Listener listener) { - if (audioDisabled) { - return; - } - - if (this.listener != null) { - // previous listener no longer associated with current - // renderer - this.listener.setRenderer(null); - } - - this.listener = listener; - this.listener.setRenderer(this); - - } - - @Override - public void cleanup() { - // Cleanup sound pool - if (soundPool != null) { - soundPool.release(); - soundPool = null; - } - - // Cleanup media player - for (AudioSource src : musicPlaying.keySet()) { - MediaPlayer mp = musicPlaying.get(src); - { - mp.stop(); - mp.release(); - src.setStatus(Status.Stopped); - } - } - musicPlaying.clear(); - } - - @Override - public void onCompletion(MediaPlayer mp) { - if (mp.isPlaying()) { - mp.seekTo(0); - mp.stop(); - } - // XXX: This has bad performance -> maybe change overall structure of - // mediaplayer in this audiorenderer? - for (AudioSource src : musicPlaying.keySet()) { - if (musicPlaying.get(src) == mp) { - src.setStatus(Status.Stopped); - break; - } - } - - } - - /** - * Plays using the {@link SoundPool} of Android. Due to hard limitation of - * the SoundPool: After playing more instances of the sound you only have - * the channel of the last played instance. - * - * It is not possible to get information about the state of the soundpool of - * a specific streamid, so removing is not possilbe -> noone knows when - * sound finished. - */ - public void playSourceInstance(AudioSource src) { - if (audioDisabled) { - return; - } - - AndroidAudioData audioData = (AndroidAudioData) src.getAudioData(); - - if (!(audioData.getAssetKey() instanceof AudioKey)) { - throw new IllegalArgumentException("Asset is not a AudioKey"); - } - - AudioKey assetKey = (AudioKey) audioData.getAssetKey(); - - try { - - if (audioData.getId() < 0) { // found something to load - int soundId = soundPool.load( - assetManager.openFd(assetKey.getName()), 1); - audioData.setId(soundId); - } - - int channel = soundPool.play(audioData.getId(), 1f, 1f, 1, 0, 1f); - - if (channel == 0) { - soundpoolStillLoading.put(audioData.getId(), src); - } else { - if (src.getStatus() != Status.Stopped) { - soundPool.stop(channel); - src.setStatus(Status.Stopped); - } - src.setChannel(channel); // receive a channel at the last - setSourceParams(src); - // playing at least - - - } - } catch (IOException e) { - logger.log(Level.SEVERE, - "Failed to load sound " + assetKey.getName(), e); - audioData.setId(-1); - } - } - - @Override - public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { - AudioSource src = soundpoolStillLoading.remove(sampleId); - - if (src == null) { - logger.warning("Something went terribly wrong! onLoadComplete" - + " had sampleId which was not in the HashMap of loading items"); - return; - } - - AudioData audioData = src.getAudioData(); - - // load was successfull - if (status == 0) { - int channelIndex; - channelIndex = soundPool.play(audioData.getId(), 1f, 1f, 1, 0, 1f); - src.setChannel(channelIndex); - setSourceParams(src); - } - } - - public void playSource(AudioSource src) { - if (audioDisabled) { - return; - } - - AndroidAudioData audioData = (AndroidAudioData) src.getAudioData(); - - MediaPlayer mp = musicPlaying.get(src); - if (mp == null) { - mp = new MediaPlayer(); - mp.setOnCompletionListener(this); - mp.setAudioStreamType(AudioManager.STREAM_MUSIC); - } - - try { - if (src.getStatus() == Status.Stopped) { - mp.reset(); - AssetKey key = audioData.getAssetKey(); - - AssetFileDescriptor afd = assetManager.openFd(key.getName()); // assetKey.getName() - mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), - afd.getLength()); - mp.prepare(); - setSourceParams(src, mp); - src.setChannel(0); - src.setStatus(Status.Playing); - musicPlaying.put(src, mp); - mp.start(); - } else { - mp.start(); - } - } catch (IllegalStateException e) { - e.printStackTrace(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private void setSourceParams(AudioSource src, MediaPlayer mp) { - mp.setLooping(src.isLooping()); - mp.setVolume(src.getVolume(), src.getVolume()); - //src.getDryFilter(); - } - - private void setSourceParams(AudioSource src) { - soundPool.setLoop(src.getChannel(), src.isLooping() ? -1 : 0); - soundPool.setVolume(src.getChannel(), src.getVolume(), src.getVolume()); - } - - /** - * Pause the current playing sounds. Both from the {@link SoundPool} and the - * active {@link MediaPlayer}s - */ - public void pauseAll() { - if (soundPool != null) { - soundPool.autoPause(); - for (MediaPlayer mp : musicPlaying.values()) { - if(mp.isPlaying()){ - mp.pause(); - } - } - } - } - - /** - * Resume all paused sounds. - */ - public void resumeAll() { - if (soundPool != null) { - soundPool.autoResume(); - for (MediaPlayer mp : musicPlaying.values()) { - mp.start(); //no resume -> api says call start to resume - } - } - } - - public void pauseSource(AudioSource src) { - if (audioDisabled) { - return; - } - - MediaPlayer mp = musicPlaying.get(src); - if (mp != null) { - mp.pause(); - src.setStatus(Status.Paused); - } else { - int channel = src.getChannel(); - if (channel != -1) { - soundPool.pause(channel); // is not very likley to make - } // something useful :) - } - } - - public void stopSource(AudioSource src) { - if (audioDisabled) { - return; - } - - // can be stream or buffer -> so try to get mediaplayer - // if there is non try to stop soundpool - MediaPlayer mp = musicPlaying.get(src); - if (mp != null) { - mp.stop(); - mp.reset(); - src.setStatus(Status.Stopped); - } else { - int channel = src.getChannel(); - if (channel != -1) { - soundPool.pause(channel); // is not very likley to make - // something useful :) - } - } - - } - - @Override - public void deleteAudioData(AudioData ad) { - - for (AudioSource src : musicPlaying.keySet()) { - if (src.getAudioData() == ad) { - MediaPlayer mp = musicPlaying.remove(src); - mp.stop(); - mp.release(); - src.setStatus(Status.Stopped); - src.setChannel(-1); - ad.setId(-1); - break; - } - } - - if (ad.getId() > 0) { - soundPool.unload(ad.getId()); - ad.setId(-1); - } - } - - @Override - public void setEnvironment(Environment env) { - // not yet supported - } - - @Override - public void deleteFilter(Filter filter) { - } - - @Override - public float getSourcePlaybackTime(AudioSource src) { - throw new UnsupportedOperationException("Not supported yet."); - } -} diff --git a/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java b/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java index b77c4a36d..8aeb883e0 100644 --- a/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java +++ b/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java @@ -523,4 +523,9 @@ public class AndroidGL implements GL, GLExt, GLFbo { public Object glFenceSync(int condition, int flags) { throw new UnsupportedOperationException("OpenGL ES 2 does not support sync fences"); } + + @Override + public void glBlendEquationSeparate(int colorMode, int alphaMode) { + GLES20.glBlendEquationSeparate(colorMode, alphaMode); + } } diff --git a/jme3-android/src/main/java/com/jme3/renderer/android/TextureUtil.java b/jme3-android/src/main/java/com/jme3/renderer/android/TextureUtil.java deleted file mode 100644 index 384824c41..000000000 --- a/jme3-android/src/main/java/com/jme3/renderer/android/TextureUtil.java +++ /dev/null @@ -1,591 +0,0 @@ -/* - * Copyright (c) 2009-2015 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.renderer.android; - -import android.graphics.Bitmap; -import android.opengl.ETC1; -import android.opengl.ETC1Util.ETC1Texture; -import android.opengl.GLES20; -import android.opengl.GLUtils; -import com.jme3.asset.AndroidImageInfo; -import com.jme3.renderer.RendererException; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.util.BufferUtils; -import java.nio.ByteBuffer; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * @deprecated Should not be used anymore. Use {@link GLRenderer} instead. - */ -@Deprecated -public class TextureUtil { - - private static final Logger logger = Logger.getLogger(TextureUtil.class.getName()); - //TODO Make this configurable through appSettings - public static boolean ENABLE_COMPRESSION = true; - private static boolean NPOT = false; - private static boolean ETC1support = false; - private static boolean DXT1 = false; - private static boolean DEPTH24_STENCIL8 = false; - private static boolean DEPTH_TEXTURE = false; - private static boolean RGBA8 = false; - - // Same constant used by both GL_ARM_rgba8 and GL_OES_rgb8_rgba8. - private static final int GL_RGBA8 = 0x8058; - - private static final int GL_DXT1 = 0x83F0; - private static final int GL_DXT1A = 0x83F1; - - private static final int GL_DEPTH_STENCIL_OES = 0x84F9; - private static final int GL_UNSIGNED_INT_24_8_OES = 0x84FA; - private static final int GL_DEPTH24_STENCIL8_OES = 0x88F0; - - public static void loadTextureFeatures(String extensionString) { - ETC1support = extensionString.contains("GL_OES_compressed_ETC1_RGB8_texture"); - DEPTH24_STENCIL8 = extensionString.contains("GL_OES_packed_depth_stencil"); - NPOT = extensionString.contains("GL_IMG_texture_npot") - || extensionString.contains("GL_OES_texture_npot") - || extensionString.contains("GL_NV_texture_npot_2D_mipmap"); - - DXT1 = extensionString.contains("GL_EXT_texture_compression_dxt1"); - DEPTH_TEXTURE = extensionString.contains("GL_OES_depth_texture"); - - RGBA8 = extensionString.contains("GL_ARM_rgba8") || - extensionString.contains("GL_OES_rgb8_rgba8"); - - logger.log(Level.FINE, "Supports ETC1? {0}", ETC1support); - logger.log(Level.FINE, "Supports DEPTH24_STENCIL8? {0}", DEPTH24_STENCIL8); - logger.log(Level.FINE, "Supports NPOT? {0}", NPOT); - logger.log(Level.FINE, "Supports DXT1? {0}", DXT1); - logger.log(Level.FINE, "Supports DEPTH_TEXTURE? {0}", DEPTH_TEXTURE); - logger.log(Level.FINE, "Supports RGBA8? {0}", RGBA8); - } - - private static void buildMipmap(Bitmap bitmap, boolean compress) { - int level = 0; - int height = bitmap.getHeight(); - int width = bitmap.getWidth(); - - logger.log(Level.FINEST, " - Generating mipmaps for bitmap using SOFTWARE"); - - GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); - - while (height >= 1 || width >= 1) { - //First of all, generate the texture from our bitmap and set it to the according level - if (compress) { - logger.log(Level.FINEST, " - Uploading LOD level {0} ({1}x{2}) with compression.", new Object[]{level, width, height}); - uploadBitmapAsCompressed(GLES20.GL_TEXTURE_2D, level, bitmap, false, 0, 0); - } else { - logger.log(Level.FINEST, " - Uploading LOD level {0} ({1}x{2}) directly.", new Object[]{level, width, height}); - GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, level, bitmap, 0); - } - - if (height == 1 || width == 1) { - break; - } - - //Increase the mipmap level - height /= 2; - width /= 2; - Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true); - - // Recycle any bitmaps created as a result of scaling the bitmap. - // Do not recycle the original image (mipmap level 0) - if (level != 0) { - bitmap.recycle(); - } - - bitmap = bitmap2; - - level++; - } - } - - private static void uploadBitmapAsCompressed(int target, int level, Bitmap bitmap, boolean subTexture, int x, int y) { - if (bitmap.hasAlpha()) { - logger.log(Level.FINEST, " - Uploading bitmap directly. Cannot compress as alpha present."); - if (subTexture) { - GLUtils.texSubImage2D(target, level, x, y, bitmap); - RendererUtil.checkGLError(); - } else { - GLUtils.texImage2D(target, level, bitmap, 0); - RendererUtil.checkGLError(); - } - } else { - // Convert to RGB565 - int bytesPerPixel = 2; - Bitmap rgb565 = bitmap.copy(Bitmap.Config.RGB_565, true); - - // Put texture data into ByteBuffer - ByteBuffer inputImage = BufferUtils.createByteBuffer(bitmap.getRowBytes() * bitmap.getHeight()); - rgb565.copyPixelsToBuffer(inputImage); - inputImage.position(0); - - // Delete the copied RGB565 image - rgb565.recycle(); - - // Encode the image into the output bytebuffer - int encodedImageSize = ETC1.getEncodedDataSize(bitmap.getWidth(), bitmap.getHeight()); - ByteBuffer compressedImage = BufferUtils.createByteBuffer(encodedImageSize); - ETC1.encodeImage(inputImage, bitmap.getWidth(), - bitmap.getHeight(), - bytesPerPixel, - bytesPerPixel * bitmap.getWidth(), - compressedImage); - - // Delete the input image buffer - BufferUtils.destroyDirectBuffer(inputImage); - - // Create an ETC1Texture from the compressed image data - ETC1Texture etc1tex = new ETC1Texture(bitmap.getWidth(), bitmap.getHeight(), compressedImage); - - // Upload the ETC1Texture - if (bytesPerPixel == 2) { - int oldSize = (bitmap.getRowBytes() * bitmap.getHeight()); - int newSize = compressedImage.capacity(); - logger.log(Level.FINEST, " - Uploading compressed image to GL, oldSize = {0}, newSize = {1}, ratio = {2}", new Object[]{oldSize, newSize, (float) oldSize / newSize}); - if (subTexture) { - GLES20.glCompressedTexSubImage2D(target, - level, - x, y, - bitmap.getWidth(), - bitmap.getHeight(), - ETC1.ETC1_RGB8_OES, - etc1tex.getData().capacity(), - etc1tex.getData()); - - RendererUtil.checkGLError(); - } else { - GLES20.glCompressedTexImage2D(target, - level, - ETC1.ETC1_RGB8_OES, - bitmap.getWidth(), - bitmap.getHeight(), - 0, - etc1tex.getData().capacity(), - etc1tex.getData()); - - RendererUtil.checkGLError(); - } - -// ETC1Util.loadTexture(target, level, 0, GLES20.GL_RGB, -// GLES20.GL_UNSIGNED_SHORT_5_6_5, etc1Texture); -// } else if (bytesPerPixel == 3) { -// ETC1Util.loadTexture(target, level, 0, GLES20.GL_RGB, -// GLES20.GL_UNSIGNED_BYTE, etc1Texture); - } - - BufferUtils.destroyDirectBuffer(compressedImage); - } - } - - /** - * uploadTextureBitmap uploads a native android bitmap - */ - public static void uploadTextureBitmap(final int target, Bitmap bitmap, boolean needMips) { - uploadTextureBitmap(target, bitmap, needMips, false, 0, 0); - } - - /** - * uploadTextureBitmap uploads a native android bitmap - */ - public static void uploadTextureBitmap(final int target, Bitmap bitmap, boolean needMips, boolean subTexture, int x, int y) { - boolean recycleBitmap = false; - //TODO, maybe this should raise an exception when NPOT is not supported - - boolean willCompress = ENABLE_COMPRESSION && ETC1support && !bitmap.hasAlpha(); - if (needMips && willCompress) { - // Image is compressed and mipmaps are desired, generate them - // using software. - buildMipmap(bitmap, willCompress); - } else { - if (willCompress) { - // Image is compressed but mipmaps are not desired, upload directly. - logger.log(Level.FINEST, " - Uploading compressed bitmap. Mipmaps are not generated."); - uploadBitmapAsCompressed(target, 0, bitmap, subTexture, x, y); - - } else { - // Image is not compressed, mipmaps may or may not be desired. - logger.log(Level.FINEST, " - Uploading bitmap directly.{0}", - (needMips - ? " Mipmaps will be generated in HARDWARE" - : " Mipmaps are not generated.")); - if (subTexture) { - System.err.println("x : " + x + " y :" + y + " , " + bitmap.getWidth() + "/" + bitmap.getHeight()); - GLUtils.texSubImage2D(target, 0, x, y, bitmap); - RendererUtil.checkGLError(); - } else { - GLUtils.texImage2D(target, 0, bitmap, 0); - RendererUtil.checkGLError(); - } - - if (needMips) { - // No pregenerated mips available, - // generate from base level if required - GLES20.glGenerateMipmap(target); - RendererUtil.checkGLError(); - } - } - } - - if (recycleBitmap) { - bitmap.recycle(); - } - } - - public static void uploadTextureAny(Image img, int target, int index, boolean needMips) { - if (img.getEfficentData() instanceof AndroidImageInfo) { - logger.log(Level.FINEST, " === Uploading image {0}. Using BITMAP PATH === ", img); - // If image was loaded from asset manager, use fast path - AndroidImageInfo imageInfo = (AndroidImageInfo) img.getEfficentData(); - uploadTextureBitmap(target, imageInfo.getBitmap(), needMips); - } else { - logger.log(Level.FINEST, " === Uploading image {0}. Using BUFFER PATH === ", img); - boolean wantGeneratedMips = needMips && !img.hasMipmaps(); - if (wantGeneratedMips && img.getFormat().isCompressed()) { - logger.log(Level.WARNING, "Generating mipmaps is only" - + " supported for Bitmap based or non-compressed images!"); - } - - // Upload using slower path - logger.log(Level.FINEST, " - Uploading bitmap directly.{0}", - (wantGeneratedMips - ? " Mipmaps will be generated in HARDWARE" - : " Mipmaps are not generated.")); - - uploadTexture(img, target, index); - - // Image was uploaded using slower path, since it is not compressed, - // then compress it - if (wantGeneratedMips) { - // No pregenerated mips available, - // generate from base level if required - GLES20.glGenerateMipmap(target); - } - } - } - - private static void unsupportedFormat(Format fmt) { - throw new UnsupportedOperationException("The image format '" + fmt + "' is unsupported by the video hardware."); - } - - public static AndroidGLImageFormat getImageFormat(Format fmt, boolean forRenderBuffer) - throws UnsupportedOperationException { - AndroidGLImageFormat imageFormat = new AndroidGLImageFormat(); - switch (fmt) { - case Depth32: - case Depth32F: - throw new UnsupportedOperationException("The image format '" - + fmt + "' is not supported by OpenGL ES 2.0 specification."); - case Alpha8: - imageFormat.format = GLES20.GL_ALPHA; - imageFormat.dataType = GLES20.GL_UNSIGNED_BYTE; - if (RGBA8) { - imageFormat.renderBufferStorageFormat = GL_RGBA8; - } else { - // Highest precision alpha supported by vanilla OGLES2 - imageFormat.renderBufferStorageFormat = GLES20.GL_RGBA4; - } - break; - case Luminance8: - imageFormat.format = GLES20.GL_LUMINANCE; - imageFormat.dataType = GLES20.GL_UNSIGNED_BYTE; - if (RGBA8) { - imageFormat.renderBufferStorageFormat = GL_RGBA8; - } else { - // Highest precision luminance supported by vanilla OGLES2 - imageFormat.renderBufferStorageFormat = GLES20.GL_RGB565; - } - break; - case Luminance8Alpha8: - imageFormat.format = GLES20.GL_LUMINANCE_ALPHA; - imageFormat.dataType = GLES20.GL_UNSIGNED_BYTE; - if (RGBA8) { - imageFormat.renderBufferStorageFormat = GL_RGBA8; - } else { - imageFormat.renderBufferStorageFormat = GLES20.GL_RGBA4; - } - break; - case RGB565: - imageFormat.format = GLES20.GL_RGB; - imageFormat.dataType = GLES20.GL_UNSIGNED_SHORT_5_6_5; - imageFormat.renderBufferStorageFormat = GLES20.GL_RGB565; - break; - case RGB5A1: - imageFormat.format = GLES20.GL_RGBA; - imageFormat.dataType = GLES20.GL_UNSIGNED_SHORT_5_5_5_1; - imageFormat.renderBufferStorageFormat = GLES20.GL_RGB5_A1; - break; - case RGB8: - imageFormat.format = GLES20.GL_RGB; - imageFormat.dataType = GLES20.GL_UNSIGNED_BYTE; - if (RGBA8) { - imageFormat.renderBufferStorageFormat = GL_RGBA8; - } else { - // Fallback: Use RGB565 if RGBA8 is not available. - imageFormat.renderBufferStorageFormat = GLES20.GL_RGB565; - } - break; - case BGR8: - imageFormat.format = GLES20.GL_RGB; - imageFormat.dataType = GLES20.GL_UNSIGNED_BYTE; - if (RGBA8) { - imageFormat.renderBufferStorageFormat = GL_RGBA8; - } else { - imageFormat.renderBufferStorageFormat = GLES20.GL_RGB565; - } - break; - case RGBA8: - imageFormat.format = GLES20.GL_RGBA; - imageFormat.dataType = GLES20.GL_UNSIGNED_BYTE; - if (RGBA8) { - imageFormat.renderBufferStorageFormat = GL_RGBA8; - } else { - imageFormat.renderBufferStorageFormat = GLES20.GL_RGBA4; - } - break; - case Depth: - case Depth16: - if (!DEPTH_TEXTURE && !forRenderBuffer) { - unsupportedFormat(fmt); - } - imageFormat.format = GLES20.GL_DEPTH_COMPONENT; - imageFormat.dataType = GLES20.GL_UNSIGNED_SHORT; - imageFormat.renderBufferStorageFormat = GLES20.GL_DEPTH_COMPONENT16; - break; - case Depth24: - case Depth24Stencil8: - if (!DEPTH_TEXTURE) { - unsupportedFormat(fmt); - } - if (DEPTH24_STENCIL8) { - // NEW: True Depth24 + Stencil8 format. - imageFormat.format = GL_DEPTH_STENCIL_OES; - imageFormat.dataType = GL_UNSIGNED_INT_24_8_OES; - imageFormat.renderBufferStorageFormat = GL_DEPTH24_STENCIL8_OES; - } else { - // Vanilla OGLES2, only Depth16 available. - imageFormat.format = GLES20.GL_DEPTH_COMPONENT; - imageFormat.dataType = GLES20.GL_UNSIGNED_SHORT; - imageFormat.renderBufferStorageFormat = GLES20.GL_DEPTH_COMPONENT16; - } - break; - case DXT1: - if (!DXT1) { - unsupportedFormat(fmt); - } - imageFormat.format = GL_DXT1; - imageFormat.dataType = GLES20.GL_UNSIGNED_BYTE; - imageFormat.compress = true; - break; - case DXT1A: - if (!DXT1) { - unsupportedFormat(fmt); - } - imageFormat.format = GL_DXT1A; - imageFormat.dataType = GLES20.GL_UNSIGNED_BYTE; - imageFormat.compress = true; - break; - default: - throw new UnsupportedOperationException("Unrecognized format: " + fmt); - } - return imageFormat; - } - - public static class AndroidGLImageFormat { - - boolean compress = false; - int format = -1; - int renderBufferStorageFormat = -1; - int dataType = -1; - } - - private static void uploadTexture(Image img, - int target, - int index) { - - if (img.getEfficentData() instanceof AndroidImageInfo) { - throw new RendererException("This image uses efficient data. " - + "Use uploadTextureBitmap instead."); - } - - // Otherwise upload image directly. - // Prefer to only use power of 2 textures here to avoid errors. - Image.Format fmt = img.getFormat(); - ByteBuffer data; - if (index >= 0 || img.getData() != null && img.getData().size() > 0) { - data = img.getData(index); - } else { - data = null; - } - - int width = img.getWidth(); - int height = img.getHeight(); - - if (!NPOT && img.isNPOT()) { - // Check if texture is POT - throw new RendererException("Non-power-of-2 textures " - + "are not supported by the video hardware " - + "and no scaling path available for image: " + img); - } - AndroidGLImageFormat imageFormat = getImageFormat(fmt, false); - - if (data != null) { - GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); - } - - int[] mipSizes = img.getMipMapSizes(); - int pos = 0; - if (mipSizes == null) { - if (data != null) { - mipSizes = new int[]{data.capacity()}; - } else { - mipSizes = new int[]{width * height * fmt.getBitsPerPixel() / 8}; - } - } - - for (int i = 0; i < mipSizes.length; i++) { - int mipWidth = Math.max(1, width >> i); - int mipHeight = Math.max(1, height >> i); - - if (data != null) { - data.position(pos); - data.limit(pos + mipSizes[i]); - } - - if (imageFormat.compress && data != null) { - GLES20.glCompressedTexImage2D(target, - i, - imageFormat.format, - mipWidth, - mipHeight, - 0, - data.remaining(), - data); - } else { - GLES20.glTexImage2D(target, - i, - imageFormat.format, - mipWidth, - mipHeight, - 0, - imageFormat.format, - imageFormat.dataType, - data); - } - - pos += mipSizes[i]; - } - } - - /** - * Update the texture currently bound to target at with data from the given - * Image at position x and y. The parameter index is used as the zoffset in - * case a 3d texture or texture 2d array is being updated. - * - * @param image Image with the source data (this data will be put into the - * texture) - * @param target the target texture - * @param index the mipmap level to update - * @param x the x position where to put the image in the texture - * @param y the y position where to put the image in the texture - */ - public static void uploadSubTexture( - Image img, - int target, - int index, - int x, - int y) { - if (img.getEfficentData() instanceof AndroidImageInfo) { - AndroidImageInfo imageInfo = (AndroidImageInfo) img.getEfficentData(); - uploadTextureBitmap(target, imageInfo.getBitmap(), true, true, x, y); - return; - } - - // Otherwise upload image directly. - // Prefer to only use power of 2 textures here to avoid errors. - Image.Format fmt = img.getFormat(); - ByteBuffer data; - if (index >= 0 || img.getData() != null && img.getData().size() > 0) { - data = img.getData(index); - } else { - data = null; - } - - int width = img.getWidth(); - int height = img.getHeight(); - - if (!NPOT && img.isNPOT()) { - // Check if texture is POT - throw new RendererException("Non-power-of-2 textures " - + "are not supported by the video hardware " - + "and no scaling path available for image: " + img); - } - AndroidGLImageFormat imageFormat = getImageFormat(fmt, false); - - if (data != null) { - GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); - } - - int[] mipSizes = img.getMipMapSizes(); - int pos = 0; - if (mipSizes == null) { - if (data != null) { - mipSizes = new int[]{data.capacity()}; - } else { - mipSizes = new int[]{width * height * fmt.getBitsPerPixel() / 8}; - } - } - - for (int i = 0; i < mipSizes.length; i++) { - int mipWidth = Math.max(1, width >> i); - int mipHeight = Math.max(1, height >> i); - - if (data != null) { - data.position(pos); - data.limit(pos + mipSizes[i]); - } - - if (imageFormat.compress && data != null) { - GLES20.glCompressedTexSubImage2D(target, i, x, y, mipWidth, mipHeight, imageFormat.format, data.remaining(), data); - RendererUtil.checkGLError(); - } else { - GLES20.glTexSubImage2D(target, i, x, y, mipWidth, mipHeight, imageFormat.format, imageFormat.dataType, data); - RendererUtil.checkGLError(); - } - - pos += mipSizes[i]; - } - } -} diff --git a/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidImageLoader.java b/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidImageLoader.java deleted file mode 100644 index f3c1464a2..000000000 --- a/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidImageLoader.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.jme3.texture.plugins; - -import android.graphics.Bitmap; -import com.jme3.asset.AndroidImageInfo; -import com.jme3.asset.AssetInfo; -import com.jme3.asset.AssetLoader; -import com.jme3.texture.Image; -import com.jme3.texture.image.ColorSpace; -import java.io.IOException; - -@Deprecated -public class AndroidImageLoader implements AssetLoader { - - public Object load(AssetInfo info) throws IOException { - AndroidImageInfo imageInfo = new AndroidImageInfo(info); - Bitmap bitmap = imageInfo.getBitmap(); - - Image image = new Image(imageInfo.getFormat(), bitmap.getWidth(), bitmap.getHeight(), null, ColorSpace.sRGB); - - image.setEfficentData(imageInfo); - return image; - } -} diff --git a/jme3-android/src/main/java/jme3test/android/SimpleTexturedTest.java b/jme3-android/src/main/java/jme3test/android/SimpleTexturedTest.java index bfc106b17..4ff0c5df7 100644 --- a/jme3-android/src/main/java/jme3test/android/SimpleTexturedTest.java +++ b/jme3-android/src/main/java/jme3test/android/SimpleTexturedTest.java @@ -46,7 +46,7 @@ public class SimpleTexturedTest extends SimpleApplication { shapeSphere = new Sphere(16, 16, .5f); - shapeBox = new Box(Vector3f.ZERO, 0.3f, 0.3f, 0.3f); + shapeBox = new Box(0.3f, 0.3f, 0.3f); // ModelConverter.optimize(geom); diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java index 3b5a8eefb..c8dedcd40 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java @@ -1,6 +1,7 @@ package com.jme3.scene.plugins.blender.materials; import java.io.IOException; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -157,14 +158,14 @@ public final class MaterialContext implements Savable { } // applying textures + int textureIndex = 0; if (loadedTextures != null && loadedTextures.size() > 0) { - int textureIndex = 0; if (loadedTextures.size() > TextureHelper.TEXCOORD_TYPES.length) { LOGGER.log(Level.WARNING, "The blender file has defined more than {0} different textures. JME supports only {0} UV mappings.", TextureHelper.TEXCOORD_TYPES.length); } for (CombinedTexture combinedTexture : loadedTextures) { if (textureIndex < TextureHelper.TEXCOORD_TYPES.length) { - combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext); + String usedUserUVSet = combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext); this.setTexture(material, combinedTexture.getMappingType(), combinedTexture.getResultTexture()); List uvs = combinedTexture.getResultUVS(); @@ -173,13 +174,19 @@ public final class MaterialContext implements Savable { uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()]))); geometry.getMesh().setBuffer(uvCoordsBuffer); }//uvs might be null if the user assigned non existing UV coordinates group name to the mesh (this should be fixed in blender file) + + if(usedUserUVSet != null) { + userDefinedUVCoordinates = new HashMap<>(userDefinedUVCoordinates); + userDefinedUVCoordinates.remove(usedUserUVSet); + } } else { LOGGER.log(Level.WARNING, "The texture could not be applied because JME only supports up to {0} different UV's.", TextureHelper.TEXCOORD_TYPES.length); } } - } else if (userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) { - LOGGER.fine("No textures found for the mesh, but UV coordinates are applied."); - int textureIndex = 0; + } + + if (userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) { + LOGGER.fine("Storing unused, user defined UV coordinates sets."); if (userDefinedUVCoordinates.size() > TextureHelper.TEXCOORD_TYPES.length) { LOGGER.log(Level.WARNING, "The blender file has defined more than {0} different UV coordinates for the mesh. JME supports only {0} UV coordinates buffers.", TextureHelper.TEXCOORD_TYPES.length); } @@ -190,7 +197,9 @@ public final class MaterialContext implements Savable { uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()]))); geometry.getMesh().setBuffer(uvCoordsBuffer); } else { - LOGGER.log(Level.WARNING, "The texture could not be applied because JME only supports up to {0} different UV's.", TextureHelper.TEXCOORD_TYPES.length); + LOGGER.log(Level.WARNING, "The user's UV set named: '{0}' could not be stored because JME only supports up to {1} different UV's.", new Object[] { + entry.getKey(), TextureHelper.TEXCOORD_TYPES.length + }); } } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/CombinedTexture.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/CombinedTexture.java index e406447eb..6c40542e2 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/CombinedTexture.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/CombinedTexture.java @@ -119,22 +119,24 @@ public class CombinedTexture { } } - /** - * This method flattens the texture and creates a single result of Texture2D - * type. - * - * @param geometry - * the geometry the texture is created for - * @param geometriesOMA - * the old memory address of the geometries list that the given - * geometry belongs to (needed for bounding box creation) - * @param userDefinedUVCoordinates - * the UV's defined by user (null or zero length table if none - * were defined) - * @param blenderContext - * the blender context - */ - public void flatten(Geometry geometry, Long geometriesOMA, Map> userDefinedUVCoordinates, BlenderContext blenderContext) { + /** + * This method flattens the texture and creates a single result of Texture2D + * type. + * + * @param geometry + * the geometry the texture is created for + * @param geometriesOMA + * the old memory address of the geometries list that the given + * geometry belongs to (needed for bounding box creation) + * @param userDefinedUVCoordinates + * the UV's defined by user (null or zero length table if none + * were defined) + * @param blenderContext + * the blender context + * @return the name of the user UV coordinates used (null if the UV's were + * generated) + */ + public String flatten(Geometry geometry, Long geometriesOMA, Map> userDefinedUVCoordinates, BlenderContext blenderContext) { Mesh mesh = geometry.getMesh(); Texture previousTexture = null; UVCoordinatesType masterUVCoordinatesType = null; @@ -226,6 +228,7 @@ public class CombinedTexture { } resultUVS = ((TriangulatedTexture) resultTexture).getResultUVS(); resultTexture = ((TriangulatedTexture) resultTexture).getResultTexture(); + masterUserUVSetName = null; } // setting additional data @@ -234,6 +237,8 @@ public class CombinedTexture { // otherwise ugly lines appear between the mesh faces resultTexture.setMagFilter(MagFilter.Nearest); resultTexture.setMinFilter(MinFilter.NearestNoMipMaps); + + return masterUserUVSetName; } /** diff --git a/jme3-bullet-native/build.gradle b/jme3-bullet-native/build.gradle index dbb74981a..62a30fb1b 100644 --- a/jme3-bullet-native/build.gradle +++ b/jme3-bullet-native/build.gradle @@ -34,7 +34,14 @@ libraries { // linker.args "-static-libstdc++" } else if (targetPlatform.operatingSystem.name == "windows") { if (toolChain in Gcc) { - cppCompiler.args '-I', "${org.gradle.internal.jvm.Jvm.current().javaHome}/include/win32" + if (toolChain.name.startsWith('mingw')) { + cppCompiler.args '-I', "${org.gradle.internal.jvm.Jvm.current().javaHome}/include/linux" + } else { + cppCompiler.args '-I', "${org.gradle.internal.jvm.Jvm.current().javaHome}/include/win32" + } + cppCompiler.args "-fpermissive" + cppCompiler.args "-static" + linker.args "-static" } else if (toolChain in VisualCpp) { cppCompiler.args "/I${org.gradle.internal.jvm.Jvm.current().javaHome}\\include\\win32" @@ -76,6 +83,31 @@ sourceSets { // Set of target platforms, will be available based on build system model { + + toolChains { + gcc(Gcc) + mingw_x86(Gcc) { + eachPlatform() { + cCompiler.executable "i686-w64-mingw32-gcc" + cppCompiler.executable "i686-w64-mingw32-g++" + linker.executable "i686-w64-mingw32-g++" + assembler.executable "i686-w64-mingw32-g++" + staticLibArchiver.executable "i686-w64-mingw32-gcc-ar" + } + target("windows_x86") + } + mingw_x86_64(Gcc) { + eachPlatform() { + cCompiler.executable "x86_64-w64-mingw32-gcc" + cppCompiler.executable "x86_64-w64-mingw32-g++" + linker.executable "x86_64-w64-mingw32-g++" + assembler.executable "x86_64-w64-mingw32-g++" + staticLibArchiver.executable "x86_64-w64-mingw32-gcc-ar" + } + target("windows_x86_64") + } + } + platforms{ // osx_universal { // TODO: universal binary doesn't work? // architecture 'x86_64' diff --git a/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java b/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java index 2e0b17c3b..b753ad2cb 100644 --- a/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java +++ b/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java @@ -111,7 +111,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl * Material references used for hardware skinning */ private Set materials = new HashSet(); - + /** * Serialization only. Do not use. */ @@ -204,6 +204,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl * @param skeleton the skeleton */ public SkeletonControl(Skeleton skeleton) { + if (skeleton == null) { + throw new IllegalArgumentException("skeleton cannot be null"); + } this.skeleton = skeleton; } @@ -406,7 +409,23 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl // Not automatic set cloning yet Set newMaterials = new HashSet(); for( Material m : this.materials ) { - newMaterials.add(cloner.clone(m)); + Material mClone = cloner.clone(m); + newMaterials.add(mClone); + if( mClone != m ) { + // Material was really cloned so clear the bone matrices in case + // this is hardware skinned. This allows a local version to be + // used and will be reset on the material. Really this just avoids + // the 'safety' check in controlRenderHardware(). Right now material + // doesn't clone itself with the cloner (and doesn't clone its parameters) + // else this would be unnecessary. + MatParam boneMatrices = mClone.getParam("BoneMatrices"); + + // ...because for some strange reason you can't clear a non-existant + // parameter. + if( boneMatrices != null ) { + mClone.clearParam("BoneMatrices"); + } + } } this.materials = newMaterials; } diff --git a/jme3-core/src/main/java/com/jme3/animation/SpatialAnimation.java b/jme3-core/src/main/java/com/jme3/animation/SpatialAnimation.java deleted file mode 100644 index 4a552bba6..000000000 --- a/jme3-core/src/main/java/com/jme3/animation/SpatialAnimation.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2009-2012 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.animation; - -/** - * @deprecated use Animation instead with tracks of selected type (ie. BoneTrack, SpatialTrack, MeshTrack) - */ -@Deprecated -public class SpatialAnimation extends Animation { - public SpatialAnimation(String name, float length) { - super(name, length); - } -} diff --git a/jme3-core/src/main/java/com/jme3/app/SimpleApplication.java b/jme3-core/src/main/java/com/jme3/app/SimpleApplication.java index 2ab008c5c..01c04601c 100644 --- a/jme3-core/src/main/java/com/jme3/app/SimpleApplication.java +++ b/jme3-core/src/main/java/com/jme3/app/SimpleApplication.java @@ -32,6 +32,7 @@ package com.jme3.app; import com.jme3.app.state.AppState; +import com.jme3.audio.AudioListenerState; import com.jme3.font.BitmapFont; import com.jme3.font.BitmapText; import com.jme3.input.FlyByCamera; @@ -96,7 +97,7 @@ public abstract class SimpleApplication extends LegacyApplication { } public SimpleApplication() { - this( new StatsAppState(), new FlyCamAppState(), new DebugKeysAppState() ); + this(new StatsAppState(), new FlyCamAppState(), new AudioListenerState(), new DebugKeysAppState()); } public SimpleApplication( AppState... initialStates ) { diff --git a/jme3-core/src/main/java/com/jme3/asset/AssetManager.java b/jme3-core/src/main/java/com/jme3/asset/AssetManager.java index a077512ef..4cd284340 100644 --- a/jme3-core/src/main/java/com/jme3/asset/AssetManager.java +++ b/jme3-core/src/main/java/com/jme3/asset/AssetManager.java @@ -41,9 +41,7 @@ import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.Caps; import com.jme3.scene.Spatial; import com.jme3.scene.plugins.OBJLoader; -import com.jme3.shader.Shader; import com.jme3.shader.ShaderGenerator; -import com.jme3.shader.ShaderKey; import com.jme3.texture.Texture; import com.jme3.texture.plugins.TGALoader; import java.io.IOException; @@ -320,13 +318,6 @@ public interface AssetManager { */ public Material loadMaterial(String name); - /** - * Loads shader file(s), shouldn't be used by end-user in most cases. - * - * @see AssetManager#loadAsset(com.jme3.asset.AssetKey) - */ - public Shader loadShader(ShaderKey key); - /** * Load a font file. Font files are in AngelCode text format, * and are with the extension "fnt". 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 66a6fbbdf..94ee68ceb 100644 --- a/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java +++ b/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java @@ -32,7 +32,6 @@ package com.jme3.asset; import com.jme3.asset.cache.AssetCache; -import com.jme3.asset.cache.SimpleAssetCache; import com.jme3.audio.AudioData; import com.jme3.audio.AudioKey; import com.jme3.font.BitmapFont; @@ -42,9 +41,7 @@ import com.jme3.renderer.Caps; import com.jme3.scene.Spatial; import com.jme3.shader.Glsl100ShaderGenerator; import com.jme3.shader.Glsl150ShaderGenerator; -import com.jme3.shader.Shader; import com.jme3.shader.ShaderGenerator; -import com.jme3.shader.ShaderKey; import com.jme3.system.JmeSystem; import com.jme3.texture.Texture; import java.io.IOException; @@ -431,36 +428,6 @@ public class DesktopAssetManager implements AssetManager { return loadFilter(new FilterKey(name)); } - /** - * Load a vertex/fragment shader combo. - * - * @param key - * @return the loaded {@link Shader} - */ - public Shader loadShader(ShaderKey key){ - // cache abuse in method - // that doesn't use loaders/locators - AssetCache cache = handler.getCache(SimpleAssetCache.class); - Shader shader = (Shader) cache.getFromCache(key); - if (shader == null){ - if (key.isUsesShaderNodes()) { - if(shaderGenerator == null){ - throw new UnsupportedOperationException("ShaderGenerator was not initialized, make sure assetManager.getGenerator(caps) has been called"); - } - shader = shaderGenerator.generateShader(); - } else { - shader = new Shader(); - shader.initialize(); - 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); - } - return shader; - } - /** * {@inheritDoc} */ diff --git a/jme3-core/src/main/java/com/jme3/asset/TextureKey.java b/jme3-core/src/main/java/com/jme3/asset/TextureKey.java index c2b5154ab..cb5450b35 100644 --- a/jme3-core/src/main/java/com/jme3/asset/TextureKey.java +++ b/jme3-core/src/main/java/com/jme3/asset/TextureKey.java @@ -123,24 +123,6 @@ public class TextureKey extends AssetKey { this.anisotropy = anisotropy; } - /** - * @deprecated Use {@link #setTextureTypeHint(com.jme3.texture.Texture.Type) } - * instead. - */ - @Deprecated - public boolean isAsCube() { - return textureTypeHint == Type.CubeMap; - } - - /** - * @deprecated Use {@link #setTextureTypeHint(com.jme3.texture.Texture.Type) } - * instead. - */ - @Deprecated - public void setAsCube(boolean asCube) { - textureTypeHint = asCube ? Type.CubeMap : Type.TwoDimensional; - } - public boolean isGenerateMips() { return generateMips; } @@ -149,24 +131,6 @@ public class TextureKey extends AssetKey { this.generateMips = generateMips; } - /** - * @deprecated Use {@link #setTextureTypeHint(com.jme3.texture.Texture.Type) } - * instead. - */ - @Deprecated - public boolean isAsTexture3D() { - return textureTypeHint == Type.ThreeDimensional; - } - - /** - * @deprecated Use {@link #setTextureTypeHint(com.jme3.texture.Texture.Type) } - * instead. - */ - @Deprecated - public void setAsTexture3D(boolean asTexture3D) { - textureTypeHint = asTexture3D ? Type.ThreeDimensional : Type.TwoDimensional; - } - /** * The type of texture expected to be returned. * diff --git a/jme3-core/src/main/java/com/jme3/audio/AudioListenerState.java b/jme3-core/src/main/java/com/jme3/audio/AudioListenerState.java new file mode 100644 index 000000000..947cb9231 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/audio/AudioListenerState.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2009-2016 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.audio; + +import com.jme3.app.Application; +import com.jme3.app.state.BaseAppState; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; + +/** + * AudioListenerState updates the audio listener's position, + * orientation, and velocity from a {@link Camera}. + * + * @author Kirill Vainer + */ +public class AudioListenerState extends BaseAppState { + + private Listener listener; + private Camera camera; + private float lastTpf; + + public AudioListenerState() { + } + + @Override + protected void initialize(Application app) { + this.camera = app.getCamera(); + this.listener = app.getListener(); + } + + @Override + protected void cleanup(Application app) { + } + + @Override + public void update(float tpf) { + lastTpf = tpf; + } + + @Override + public void render(RenderManager rm) { + if (!isEnabled()) { + return; + } + + Vector3f lastLocation = listener.getLocation(); + Vector3f currentLocation = camera.getLocation(); + Vector3f velocity = listener.getVelocity(); + + if (!lastLocation.equals(currentLocation)) { + velocity.set(currentLocation).subtractLocal(lastLocation); + velocity.multLocal(1f / lastTpf); + listener.setLocation(currentLocation); + listener.setVelocity(velocity); + } else if (!velocity.equals(Vector3f.ZERO)) { + listener.setVelocity(Vector3f.ZERO); + } + + Quaternion lastRotation = listener.getRotation(); + Quaternion currentRotation = camera.getRotation(); + if (!lastRotation.equals(currentRotation)) { + listener.setRotation(currentRotation); + } + } + + @Override + protected void onEnable() { + } + + @Override + protected void onDisable() { + } +} diff --git a/jme3-core/src/main/java/com/jme3/audio/AudioNode.java b/jme3-core/src/main/java/com/jme3/audio/AudioNode.java index 55a57768d..9f44c82be 100644 --- a/jme3-core/src/main/java/com/jme3/audio/AudioNode.java +++ b/jme3-core/src/main/java/com/jme3/audio/AudioNode.java @@ -78,6 +78,7 @@ public class AudioNode extends Node implements AudioSource { protected transient AudioData data = null; protected transient volatile AudioSource.Status status = AudioSource.Status.Stopped; protected transient volatile int channel = -1; + protected Vector3f previousWorldTranslation = Vector3f.NAN; protected Vector3f velocity = new Vector3f(); protected boolean reverbEnabled = false; protected float maxDistance = 200; // 200 meters @@ -88,6 +89,8 @@ public class AudioNode extends Node implements AudioSource { protected float innerAngle = 360; protected float outerAngle = 360; protected boolean positional = true; + protected boolean velocityFromTranslation = false; + protected float lastTpf; /** * Status indicates the current status of the audio node. @@ -702,17 +705,44 @@ public class AudioNode extends Node implements AudioSource { } } + public boolean isVelocityFromTranslation() { + return velocityFromTranslation; + } + + public void setVelocityFromTranslation(boolean velocityFromTranslation) { + this.velocityFromTranslation = velocityFromTranslation; + } + @Override - public void updateGeometricState(){ - boolean updatePos = false; - if ((refreshFlags & RF_TRANSFORM) != 0){ - updatePos = true; - } + public void updateLogicalState(float tpf) { + super.updateLogicalState(tpf); + lastTpf = tpf; + } + @Override + public void updateGeometricState() { super.updateGeometricState(); - if (updatePos && channel >= 0) + if (channel < 0) { + return; + } + + Vector3f currentWorldTranslation = worldTransform.getTranslation(); + + if (Float.isNaN(previousWorldTranslation.x) + || !previousWorldTranslation.equals(currentWorldTranslation)) { + getRenderer().updateSourceParam(this, AudioParam.Position); + + if (velocityFromTranslation) { + velocity.set(currentWorldTranslation).subtractLocal(previousWorldTranslation); + velocity.multLocal(1f / lastTpf); + + getRenderer().updateSourceParam(this, AudioParam.Velocity); + } + + previousWorldTranslation.set(currentWorldTranslation); + } } @Override @@ -772,6 +802,7 @@ public class AudioNode extends Node implements AudioSource { oc.write(outerAngle, "outer_angle", 360); oc.write(positional, "positional", false); + oc.write(velocityFromTranslation, "velocity_from_translation", false); } @Override @@ -806,6 +837,7 @@ public class AudioNode extends Node implements AudioSource { outerAngle = ic.readFloat("outer_angle", 360); positional = ic.readBoolean("positional", false); + velocityFromTranslation = ic.readBoolean("velocity_from_translation", false); if (audioKey != null) { try { diff --git a/jme3-core/src/main/java/com/jme3/audio/Listener.java b/jme3-core/src/main/java/com/jme3/audio/Listener.java index 8e59eac0c..afd08a730 100644 --- a/jme3-core/src/main/java/com/jme3/audio/Listener.java +++ b/jme3-core/src/main/java/com/jme3/audio/Listener.java @@ -36,9 +36,9 @@ import com.jme3.math.Vector3f; public class Listener { - private Vector3f location; - private Vector3f velocity; - private Quaternion rotation; + private final Vector3f location; + private final Vector3f velocity; + private final Quaternion rotation; private float volume = 1; private AudioRenderer renderer; diff --git a/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java b/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java index 0878e23fa..82c588d4d 100644 --- a/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java +++ b/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java @@ -904,11 +904,12 @@ public class ALAudioRenderer implements AudioRenderer, Runnable { } else { // Buffer finished playing. if (src.isLooping()) { - throw new AssertionError("Unexpected state: " + - "A looping sound has stopped playing"); - } else { - reclaimChannel = true; + // When a device is disconnected, all sources + // will enter the "stopped" state. + logger.warning("A looping sound has stopped playing"); } + + reclaimChannel = true; } if (reclaimChannel) { diff --git a/jme3-core/src/main/java/com/jme3/cinematic/MotionPath.java b/jme3-core/src/main/java/com/jme3/cinematic/MotionPath.java index 9eef4b8d3..2a6325747 100644 --- a/jme3-core/src/main/java/com/jme3/cinematic/MotionPath.java +++ b/jme3-core/src/main/java/com/jme3/cinematic/MotionPath.java @@ -121,7 +121,8 @@ public class MotionPath implements Savable { Material m = assetManager.loadMaterial("Common/Materials/RedColor.j3m"); for (Iterator it = spline.getControlPoints().iterator(); it.hasNext();) { Vector3f cp = it.next(); - Geometry geo = new Geometry("box", new Box(cp, 0.3f, 0.3f, 0.3f)); + Geometry geo = new Geometry("box", new Box(0.3f, 0.3f, 0.3f)); + geo.setLocalTranslation(cp); geo.setMaterial(m); debugNode.attachChild(geo); diff --git a/jme3-core/src/main/java/com/jme3/effect/ParticleMesh.java b/jme3-core/src/main/java/com/jme3/effect/ParticleMesh.java index ed1b80d2a..7d0d2d92d 100644 --- a/jme3-core/src/main/java/com/jme3/effect/ParticleMesh.java +++ b/jme3-core/src/main/java/com/jme3/effect/ParticleMesh.java @@ -50,8 +50,9 @@ public abstract class ParticleMesh extends Mesh { public enum Type { /** * The particle mesh is composed of points. Each particle is a point. - * This can be used in conjuction with {@link RenderState#setPointSprite(boolean) point sprites} - * to render particles the usual way. + * Note that point based particles do not support certain features such + * as {@link ParticleEmitter#setRotateSpeed(float) rotation}, and + * {@link ParticleEmitter#setFacingVelocity(boolean) velocity following}. */ Point, diff --git a/jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java b/jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java index f7230fd4e..23542230f 100644 --- a/jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java +++ b/jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java @@ -54,10 +54,10 @@ import java.util.logging.Logger; */ public class SavableClassUtil { - private final static HashMap classRemappings = new HashMap(); + private final static HashMap CLASS_REMAPPINGS = new HashMap<>(); private static void addRemapping(String oldClass, Class newClass){ - classRemappings.put(oldClass, newClass.getName()); + CLASS_REMAPPINGS.put(oldClass, newClass.getName()); } static { @@ -74,7 +74,7 @@ public class SavableClassUtil { } private static String remapClass(String className) throws ClassNotFoundException { - String result = classRemappings.get(className); + String result = CLASS_REMAPPINGS.get(className); if (result == null) { return className; } else { diff --git a/jme3-core/src/main/java/com/jme3/material/MatParam.java b/jme3-core/src/main/java/com/jme3/material/MatParam.java index 677c17d55..8d965e363 100644 --- a/jme3-core/src/main/java/com/jme3/material/MatParam.java +++ b/jme3-core/src/main/java/com/jme3/material/MatParam.java @@ -34,7 +34,6 @@ package com.jme3.material; import com.jme3.asset.TextureKey; import com.jme3.export.*; import com.jme3.math.*; -import com.jme3.renderer.Renderer; import com.jme3.shader.VarType; import com.jme3.texture.Texture; import com.jme3.texture.Texture.WrapMode; @@ -129,9 +128,6 @@ public class MatParam implements Savable, Cloneable { this.value = value; } - void apply(Renderer r, Technique technique) { - technique.updateUniformParam(getPrefixedName(), getVarType(), getValue()); - } /** * Returns the material parameter value as it would appear in a J3M diff --git a/jme3-core/src/main/java/com/jme3/material/MatParamOverride.java b/jme3-core/src/main/java/com/jme3/material/MatParamOverride.java new file mode 100644 index 000000000..8a7355b87 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/material/MatParamOverride.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2009-2016 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.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.scene.Spatial; +import com.jme3.shader.VarType; +import java.io.IOException; + +/** + * MatParamOverride is a mechanism by which + * {@link MatParam material parameters} can be overridden on the scene graph. + *

+ * A scene branch which has a MatParamOverride applied to it will + * cause all material parameters with the same name and type to have their value + * replaced with the value set on the MatParamOverride. If those + * parameters are mapped to a define, then the define will be overridden as well + * using the same rules as the ones used for regular material parameters. + *

+ * MatParamOverrides are applied to a {@link Spatial} via the + * {@link Spatial#addMatParamOverride(com.jme3.material.MatParamOverride)} + * method. They are propagated to child Spatials via + * {@link Spatial#updateGeometricState()} similar to how lights are propagated. + *

+ * Example:
+ *

+ * {@code
+ *
+ * Geometry box = new Geometry("Box", new Box(1,1,1));
+ * Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ * mat.setColor("Color", ColorRGBA.Blue);
+ * box.setMaterial(mat);
+ * rootNode.attachChild(box);
+ *
+ * // ... later ...
+ * MatParamOverride override = new MatParamOverride(Type.Vector4, "Color", ColorRGBA.Red);
+ * rootNode.addMatParamOverride(override);
+ *
+ * // After adding the override to the root node, the box becomes red.
+ * }
+ * 
+ * + * @author Kirill Vainer + * @see Spatial#addMatParamOverride(com.jme3.material.MatParamOverride) + * @see Spatial#getWorldMatParamOverrides() + */ +public final class MatParamOverride extends MatParam { + + private boolean enabled = true; + + /** + * Serialization only. Do not use. + */ + public MatParamOverride() { + super(); + } + + /** + * Create a new MatParamOverride. + * + * Overrides are created enabled by default. + * + * @param type The type of parameter. + * @param name The name of the parameter. + * @param value The value to set the material parameter to. + */ + public MatParamOverride(VarType type, String name, Object value) { + super(type, name, value); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj) && this.enabled == ((MatParamOverride) obj).enabled; + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + hash = 59 * hash + (enabled ? 1 : 0); + return hash; + } + + /** + * Determine if the MatParamOverride is enabled or disabled. + * + * @return true if enabled, false if disabled. + * @see #setEnabled(boolean) + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Enable or disable this MatParamOverride. + * + * When disabled, the override will continue to propagate through the scene + * graph like before, but it will have no effect on materials. Overrides are + * enabled by default. + * + * @param enabled Whether to enable or disable this override. + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule oc = ex.getCapsule(this); + oc.write(enabled, "enabled", true); + } + + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule ic = im.getCapsule(this); + enabled = ic.readBoolean("enabled", true); + } +} diff --git a/jme3-core/src/main/java/com/jme3/material/MatParamTexture.java b/jme3-core/src/main/java/com/jme3/material/MatParamTexture.java index a3db63a1c..cb800e75b 100644 --- a/jme3-core/src/main/java/com/jme3/material/MatParamTexture.java +++ b/jme3-core/src/main/java/com/jme3/material/MatParamTexture.java @@ -35,7 +35,6 @@ import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; -import com.jme3.renderer.Renderer; import com.jme3.shader.VarType; import com.jme3.texture.Texture; import com.jme3.texture.image.ColorSpace; @@ -44,13 +43,11 @@ import java.io.IOException; public class MatParamTexture extends MatParam { private Texture texture; - private int unit; private ColorSpace colorSpace; - public MatParamTexture(VarType type, String name, Texture texture, int unit, ColorSpace colorSpace) { + public MatParamTexture(VarType type, String name, Texture texture, ColorSpace colorSpace) { super(type, name, texture); this.texture = texture; - this.unit = unit; this.colorSpace = colorSpace; } @@ -92,37 +89,18 @@ public class MatParamTexture extends MatParam { this.colorSpace = colorSpace; } - public void setUnit(int unit) { - this.unit = unit; - } - - public int getUnit() { - return unit; - } - - @Override - public void apply(Renderer r, Technique technique) { - TechniqueDef techDef = technique.getDef(); - r.setTexture(getUnit(), getTextureValue()); - technique.updateUniformParam(getPrefixedName(), getVarType(), getUnit()); - } - @Override public void write(JmeExporter ex) throws IOException { super.write(ex); OutputCapsule oc = ex.getCapsule(this); - oc.write(unit, "texture_unit", -1); - - // For backwards compat - oc.write(texture, "texture", null); + oc.write(0, "texture_unit", -1); + oc.write(texture, "texture", null); // For backwards compatibility } @Override public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule ic = im.getCapsule(this); - unit = ic.readInt("texture_unit", -1); texture = (Texture) value; - //texture = (Texture) ic.readSavable("texture", null); } } \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/material/Material.java b/jme3-core/src/main/java/com/jme3/material/Material.java index 2aabbd667..d66f88a0b 100644 --- a/jme3-core/src/main/java/com/jme3/material/Material.java +++ b/jme3-core/src/main/java/com/jme3/material/Material.java @@ -44,18 +44,16 @@ import com.jme3.math.*; import com.jme3.renderer.Caps; import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; -import com.jme3.renderer.RendererException; import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.scene.Geometry; -import com.jme3.scene.Mesh; -import com.jme3.scene.instancing.InstancedGeometry; import com.jme3.shader.Shader; import com.jme3.shader.Uniform; +import com.jme3.shader.UniformBindingManager; import com.jme3.shader.VarType; +import com.jme3.texture.Image; import com.jme3.texture.Texture; import com.jme3.texture.image.ColorSpace; import com.jme3.util.ListMap; -import com.jme3.util.TempVars; import java.io.IOException; import java.util.*; import java.util.logging.Level; @@ -77,32 +75,18 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { // Version #2: Fixed issue with RenderState.apply*** flags not getting exported public static final int SAVABLE_VERSION = 2; private static final Logger logger = Logger.getLogger(Material.class.getName()); - private static final RenderState additiveLight = new RenderState(); - private static final RenderState depthOnly = new RenderState(); - private static final Quaternion nullDirLight = new Quaternion(0, -1, 0, -1); - - static { - depthOnly.setDepthTest(true); - depthOnly.setDepthWrite(true); - depthOnly.setFaceCullMode(RenderState.FaceCullMode.Back); - depthOnly.setColorWrite(false); - - additiveLight.setBlendMode(RenderState.BlendMode.AlphaAdditive); - additiveLight.setDepthWrite(false); - } + private AssetKey key; private String name; private MaterialDef def; private ListMap paramValues = new ListMap(); private Technique technique; private HashMap techniques = new HashMap(); - private int nextTexUnit = 0; private RenderState additionalState = null; private RenderState mergedRenderState = new RenderState(); private boolean transparent = false; private boolean receivesShadows = false; private int sortingId = -1; - private transient ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1); public Material(MaterialDef def) { if (def == null) { @@ -175,22 +159,29 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { * @return The sorting ID used for sorting geometries for rendering. */ public int getSortId() { - Technique t = getActiveTechnique(); - if (sortingId == -1 && t != null && t.getShader() != null) { - int texId = -1; + if (sortingId == -1 && technique != null) { + sortingId = technique.getSortId() << 16; + int texturesSortId = 17; for (int i = 0; i < paramValues.size(); i++) { MatParam param = paramValues.getValue(i); - if (param instanceof MatParamTexture) { - MatParamTexture tex = (MatParamTexture) param; - if (tex.getTextureValue() != null && tex.getTextureValue().getImage() != null) { - if (texId == -1) { - texId = 0; - } - texId += tex.getTextureValue().getImage().getId() % 0xff; - } + if (!param.getVarType().isTextureType()) { + continue; + } + Texture texture = (Texture) param.getValue(); + if (texture == null) { + continue; + } + Image image = texture.getImage(); + if (image == null) { + continue; + } + int textureId = image.getId(); + if (textureId == -1) { + textureId = 0; } + texturesSortId = texturesSortId * 23 + textureId; } - sortingId = texId + t.getShader().getId() * 1000; + sortingId |= texturesSortId & 0xFFFF; } return sortingId; } @@ -215,6 +206,8 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { mat.paramValues.put(entry.getKey(), entry.getValue().clone()); } + mat.sortingId = -1; + return mat; } catch (CloneNotSupportedException ex) { throw new AssertionError(ex); @@ -258,8 +251,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { // E.g. if user chose custom technique for one material but // uses default technique for other material, the materials // are not equal. - String thisDefName = this.technique != null ? this.technique.getDef().getName() : "Default"; - String otherDefName = other.technique != null ? other.technique.getDef().getName() : "Default"; + String thisDefName = this.technique != null + ? this.technique.getDef().getName() + : TechniqueDef.DEFAULT_TECHNIQUE_NAME; + + String otherDefName = other.technique != null + ? other.technique.getDef().getName() + : TechniqueDef.DEFAULT_TECHNIQUE_NAME; + if (!thisDefName.equals(otherDefName)) { return false; } @@ -444,7 +443,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { * * @see #setParam(java.lang.String, com.jme3.shader.VarType, java.lang.Object) */ - public ListMap getParamsMap() { + public ListMap getParamsMap() { return paramValues; } @@ -504,16 +503,6 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { paramValues.remove(name); if (matParam instanceof MatParamTexture) { - int texUnit = ((MatParamTexture) matParam).getUnit(); - nextTexUnit--; - for (MatParam param : paramValues.values()) { - if (param instanceof MatParamTexture) { - MatParamTexture texParam = (MatParamTexture) param; - if (texParam.getUnit() > texUnit) { - texParam.setUnit(texParam.getUnit() - 1); - } - } - } sortingId = -1; } if (technique != null) { @@ -556,13 +545,13 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { + "Linear using texture.getImage.setColorSpace().", new Object[]{value.getName(), value.getImage().getColorSpace().name(), name}); } - paramValues.put(name, new MatParamTexture(type, name, value, nextTexUnit++, null)); + paramValues.put(name, new MatParamTexture(type, name, value, null)); } else { val.setTextureValue(value); } if (technique != null) { - technique.notifyParamChanged(name, type, nextTexUnit - 1); + technique.notifyParamChanged(name, type, value); } // need to recompute sort ID @@ -695,277 +684,21 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { setParam(name, VarType.Vector4, value); } - private ColorRGBA getAmbientColor(LightList lightList, boolean removeLights) { - ambientLightColor.set(0, 0, 0, 1); - for (int j = 0; j < lightList.size(); j++) { - Light l = lightList.get(j); - if (l instanceof AmbientLight) { - ambientLightColor.addLocal(l.getColor()); - if(removeLights){ - lightList.remove(l); - } - } - } - ambientLightColor.a = 1.0f; - return ambientLightColor; - } - - private static void renderMeshFromGeometry(Renderer renderer, Geometry geom) { - Mesh mesh = geom.getMesh(); - int lodLevel = geom.getLodLevel(); - if (geom instanceof InstancedGeometry) { - InstancedGeometry instGeom = (InstancedGeometry) geom; - int numInstances = instGeom.getActualNumInstances(); - if (numInstances == 0) { - return; - } - if (renderer.getCaps().contains(Caps.MeshInstancing)) { - renderer.renderMesh(mesh, lodLevel, numInstances, instGeom.getAllInstanceData()); - } else { - throw new RendererException("Mesh instancing is not supported by the video hardware"); - } - } else { - renderer.renderMesh(mesh, lodLevel, 1, null); - } - } - - /** - * Uploads the lights in the light list as two uniform arrays.

* - *

- * uniform vec4 g_LightColor[numLights];
// - * g_LightColor.rgb is the diffuse/specular color of the light.
// - * g_Lightcolor.a is the type of light, 0 = Directional, 1 = Point,
// - * 2 = Spot.

- * uniform vec4 g_LightPosition[numLights];
// - * g_LightPosition.xyz is the position of the light (for point lights)
- * // or the direction of the light (for directional lights).
// - * g_LightPosition.w is the inverse radius (1/r) of the light (for - * attenuation)

- */ - protected int updateLightListUniforms(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex) { - if (numLights == 0) { // this shader does not do lighting, ignore. - return 0; - } - - Uniform lightData = shader.getUniform("g_LightData"); - lightData.setVector4Length(numLights * 3);//8 lights * max 3 - Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); - - - if (startIndex != 0) { - // apply additive blending for 2nd and future passes - rm.getRenderer().applyRenderState(additiveLight); - ambientColor.setValue(VarType.Vector4, ColorRGBA.Black); - }else{ - ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList,true)); - } - - int lightDataIndex = 0; - TempVars vars = TempVars.get(); - Vector4f tmpVec = vars.vect4f1; - int curIndex; - int endIndex = numLights + startIndex; - for (curIndex = startIndex; curIndex < endIndex && curIndex < lightList.size(); curIndex++) { - - - Light l = lightList.get(curIndex); - if(l.getType() == Light.Type.Ambient){ - endIndex++; - continue; - } - ColorRGBA color = l.getColor(); - //Color - lightData.setVector4InArray(color.getRed(), - color.getGreen(), - color.getBlue(), - l.getType().getId(), - lightDataIndex); - lightDataIndex++; - - switch (l.getType()) { - case Directional: - DirectionalLight dl = (DirectionalLight) l; - Vector3f dir = dl.getDirection(); - //Data directly sent in view space to avoid a matrix mult for each pixel - tmpVec.set(dir.getX(), dir.getY(), dir.getZ(), 0.0f); - rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); -// tmpVec.divideLocal(tmpVec.w); -// tmpVec.normalizeLocal(); - lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), -1, lightDataIndex); - lightDataIndex++; - //PADDING - lightData.setVector4InArray(0,0,0,0, lightDataIndex); - lightDataIndex++; - break; - case Point: - PointLight pl = (PointLight) l; - Vector3f pos = pl.getPosition(); - float invRadius = pl.getInvRadius(); - tmpVec.set(pos.getX(), pos.getY(), pos.getZ(), 1.0f); - rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); - //tmpVec.divideLocal(tmpVec.w); - lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRadius, lightDataIndex); - lightDataIndex++; - //PADDING - lightData.setVector4InArray(0,0,0,0, lightDataIndex); - lightDataIndex++; - break; - case Spot: - SpotLight sl = (SpotLight) l; - Vector3f pos2 = sl.getPosition(); - Vector3f dir2 = sl.getDirection(); - float invRange = sl.getInvSpotRange(); - float spotAngleCos = sl.getPackedAngleCos(); - tmpVec.set(pos2.getX(), pos2.getY(), pos2.getZ(), 1.0f); - rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); - // tmpVec.divideLocal(tmpVec.w); - lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRange, lightDataIndex); - lightDataIndex++; - - //We transform the spot direction in view space here to save 5 varying later in the lighting shader - //one vec4 less and a vec4 that becomes a vec3 - //the downside is that spotAngleCos decoding happens now in the frag shader. - tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0.0f); - rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); - tmpVec.normalizeLocal(); - lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos, lightDataIndex); - lightDataIndex++; - break; - default: - throw new UnsupportedOperationException("Unknown type of light: " + l.getType()); - } - } - vars.release(); - //Padding of unsued buffer space - while(lightDataIndex < numLights * 3) { - lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex); - lightDataIndex++; - } - return curIndex; - } - - protected void renderMultipassLighting(Shader shader, Geometry g, LightList lightList, RenderManager rm) { - - Renderer r = rm.getRenderer(); - Uniform lightDir = shader.getUniform("g_LightDirection"); - Uniform lightColor = shader.getUniform("g_LightColor"); - Uniform lightPos = shader.getUniform("g_LightPosition"); - Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); - boolean isFirstLight = true; - boolean isSecondLight = false; - - for (int i = 0; i < lightList.size(); i++) { - Light l = lightList.get(i); - if (l instanceof AmbientLight) { - continue; - } - - if (isFirstLight) { - // set ambient color for first light only - ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, false)); - isFirstLight = false; - isSecondLight = true; - } else if (isSecondLight) { - ambientColor.setValue(VarType.Vector4, ColorRGBA.Black); - // apply additive blending for 2nd and future lights - r.applyRenderState(additiveLight); - isSecondLight = false; - } - - TempVars vars = TempVars.get(); - Quaternion tmpLightDirection = vars.quat1; - Quaternion tmpLightPosition = vars.quat2; - ColorRGBA tmpLightColor = vars.color; - Vector4f tmpVec = vars.vect4f1; - - ColorRGBA color = l.getColor(); - tmpLightColor.set(color); - tmpLightColor.a = l.getType().getId(); - lightColor.setValue(VarType.Vector4, tmpLightColor); - - switch (l.getType()) { - case Directional: - DirectionalLight dl = (DirectionalLight) l; - Vector3f dir = dl.getDirection(); - //FIXME : there is an inconstency here due to backward - //compatibility of the lighting shader. - //The directional light direction is passed in the - //LightPosition uniform. The lighting shader needs to be - //reworked though in order to fix this. - tmpLightPosition.set(dir.getX(), dir.getY(), dir.getZ(), -1); - lightPos.setValue(VarType.Vector4, tmpLightPosition); - tmpLightDirection.set(0, 0, 0, 0); - lightDir.setValue(VarType.Vector4, tmpLightDirection); - break; - case Point: - PointLight pl = (PointLight) l; - Vector3f pos = pl.getPosition(); - float invRadius = pl.getInvRadius(); - - tmpLightPosition.set(pos.getX(), pos.getY(), pos.getZ(), invRadius); - lightPos.setValue(VarType.Vector4, tmpLightPosition); - tmpLightDirection.set(0, 0, 0, 0); - lightDir.setValue(VarType.Vector4, tmpLightDirection); - break; - case Spot: - SpotLight sl = (SpotLight) l; - Vector3f pos2 = sl.getPosition(); - Vector3f dir2 = sl.getDirection(); - float invRange = sl.getInvSpotRange(); - float spotAngleCos = sl.getPackedAngleCos(); - - tmpLightPosition.set(pos2.getX(), pos2.getY(), pos2.getZ(), invRange); - lightPos.setValue(VarType.Vector4, tmpLightPosition); - - //We transform the spot direction in view space here to save 5 varying later in the lighting shader - //one vec4 less and a vec4 that becomes a vec3 - //the downside is that spotAngleCos decoding happens now in the frag shader. - tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0); - rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); - tmpLightDirection.set(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos); - - lightDir.setValue(VarType.Vector4, tmpLightDirection); - - break; - default: - throw new UnsupportedOperationException("Unknown type of light: " + l.getType()); - } - vars.release(); - r.setShader(shader); - renderMeshFromGeometry(r, g); - } - - if (isFirstLight) { - // Either there are no lights at all, or only ambient lights. - // Render a dummy "normal light" so we can see the ambient color. - ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, false)); - lightColor.setValue(VarType.Vector4, ColorRGBA.BlackNoAlpha); - lightPos.setValue(VarType.Vector4, nullDirLight); - r.setShader(shader); - renderMeshFromGeometry(r, g); - } - } - /** * Select the technique to use for rendering this material. *

- * If name is "Default", then one of the - * {@link MaterialDef#getDefaultTechniques() default techniques} - * on the material will be selected. Otherwise, the named technique - * will be found in the material definition. - *

* Any candidate technique for selection (either default or named) * must be verified to be compatible with the system, for that, the * renderManager is queried for capabilities. * - * @param name The name of the technique to select, pass "Default" to - * select one of the default techniques. + * @param name The name of the technique to select, pass + * {@link TechniqueDef#DEFAULT_TECHNIQUE_NAME} to select one of the default + * techniques. * @param renderManager The {@link RenderManager render manager} * to query for capabilities. * - * @throws IllegalArgumentException If "Default" is passed and no default - * techniques are available on the material definition, or if a name - * is passed but there's no technique by that name. + * @throws IllegalArgumentException If no technique exists with the given + * name. * @throws UnsupportedOperationException If no candidate technique supports * the system capabilities. */ @@ -974,49 +707,34 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { Technique tech = techniques.get(name); // When choosing technique, we choose one that // supports all the caps. - EnumSet rendererCaps = renderManager.getRenderer().getCaps(); if (tech == null) { + EnumSet rendererCaps = renderManager.getRenderer().getCaps(); + List techDefs = def.getTechniqueDefs(name); - if (name.equals("Default")) { - List techDefs = def.getDefaultTechniques(); - if (techDefs == null || techDefs.isEmpty()) { - throw new IllegalArgumentException("No default techniques are available on material '" + def.getName() + "'"); - } + if (techDefs == null || techDefs.isEmpty()) { + throw new IllegalArgumentException( + String.format("The requested technique %s is not available on material %s", name, def.getName())); + } - TechniqueDef lastTech = null; - for (TechniqueDef techDef : techDefs) { - if (rendererCaps.containsAll(techDef.getRequiredCaps())) { - // use the first one that supports all the caps - tech = new Technique(this, techDef); - techniques.put(name, tech); - if(tech.getDef().getLightMode() == renderManager.getPreferredLightMode() || - tech.getDef().getLightMode() == LightMode.Disable){ - break; - } + TechniqueDef lastTech = null; + for (TechniqueDef techDef : techDefs) { + if (rendererCaps.containsAll(techDef.getRequiredCaps())) { + // use the first one that supports all the caps + tech = new Technique(this, techDef); + techniques.put(name, tech); + if (tech.getDef().getLightMode() == renderManager.getPreferredLightMode() + || tech.getDef().getLightMode() == LightMode.Disable) { + break; } - lastTech = techDef; - } - if (tech == null) { - throw new UnsupportedOperationException("No default technique on material '" + def.getName() + "'\n" - + " is supported by the video hardware. The caps " - + lastTech.getRequiredCaps() + " are required."); - } - - } else { - // create "special" technique instance - TechniqueDef techDef = def.getTechniqueDef(name); - if (techDef == null) { - throw new IllegalArgumentException("For material " + def.getName() + ", technique not found: " + name); - } - - if (!rendererCaps.containsAll(techDef.getRequiredCaps())) { - throw new UnsupportedOperationException("The explicitly chosen technique '" + name + "' on material '" + def.getName() + "'\n" - + "requires caps " + techDef.getRequiredCaps() + " which are not " - + "supported by the video renderer"); } - - tech = new Technique(this, techDef); - techniques.put(name, tech); + lastTech = techDef; + } + if (tech == null) { + throw new UnsupportedOperationException( + String.format("No technique '%s' on material " + + "'%s' is supported by the video hardware. " + + "The capabilities %s are required.", + name, def.getName(), lastTech.getRequiredCaps())); } } else if (technique == tech) { // attempting to switch to an already @@ -1025,20 +743,82 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { } technique = tech; - tech.makeCurrent(def.getAssetManager(), true, rendererCaps, renderManager); + tech.notifyTechniqueSwitched(); // shader was changed sortingId = -1; } - private void autoSelectTechnique(RenderManager rm) { - if (technique == null) { - selectTechnique("Default", rm); - } else { - technique.makeCurrent(def.getAssetManager(), false, rm.getRenderer().getCaps(), rm); + private int applyOverrides(Renderer renderer, Shader shader, List overrides, int unit) { + for (MatParamOverride override : overrides) { + VarType type = override.getVarType(); + + MatParam paramDef = def.getMaterialParam(override.getName()); + + if (paramDef == null || paramDef.getVarType() != type || !override.isEnabled()) { + continue; + } + + Uniform uniform = shader.getUniform(override.getPrefixedName()); + + if (override.getValue() != null) { + if (type.isTextureType()) { + renderer.setTexture(unit, (Texture) override.getValue()); + uniform.setValue(VarType.Int, unit); + unit++; + } else { + uniform.setValue(type, override.getValue()); + } + } else { + uniform.clearValue(); + } } + return unit; } + private void updateShaderMaterialParameters(Renderer renderer, Shader shader, + List worldOverrides, List forcedOverrides) { + + int unit = 0; + if (worldOverrides != null) { + unit = applyOverrides(renderer, shader, worldOverrides, unit); + } + if (forcedOverrides != null) { + unit = applyOverrides(renderer, shader, forcedOverrides, unit); + } + + for (int i = 0; i < paramValues.size(); i++) { + MatParam param = paramValues.getValue(i); + VarType type = param.getVarType(); + Uniform uniform = shader.getUniform(param.getPrefixedName()); + + if (uniform.isSetByCurrentMaterial()) { + continue; + } + + if (type.isTextureType()) { + renderer.setTexture(unit, (Texture) param.getValue()); + uniform.setValue(VarType.Int, unit); + unit++; + } else { + uniform.setValue(type, param.getValue()); + } + } + + } + + private void updateRenderState(RenderManager renderManager, Renderer renderer, TechniqueDef techniqueDef) { + if (renderManager.getForcedRenderState() != null) { + renderer.applyRenderState(renderManager.getForcedRenderState()); + } else { + if (techniqueDef.getRenderState() != null) { + renderer.applyRenderState(techniqueDef.getRenderState().copyMergedTo(additionalState, mergedRenderState)); + } else { + renderer.applyRenderState(RenderState.DEFAULT.copyMergedTo(additionalState, mergedRenderState)); + } + } + } + /** * Preloads this material for the given render manager. *

@@ -1046,20 +826,23 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { * used for rendering, there won't be any delay since the material has * been already been setup for rendering. * - * @param rm The render manager to preload for + * @param renderManager The render manager to preload for */ - public void preload(RenderManager rm) { - autoSelectTechnique(rm); - - Renderer r = rm.getRenderer(); - TechniqueDef techDef = technique.getDef(); + public void preload(RenderManager renderManager) { + if (technique == null) { + selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); + } + TechniqueDef techniqueDef = technique.getDef(); + Renderer renderer = renderManager.getRenderer(); + EnumSet rendererCaps = renderer.getCaps(); - Collection params = paramValues.values(); - for (MatParam param : params) { - param.apply(r, technique); + if (techniqueDef.isNoRender()) { + return; } - r.setShader(technique.getShader()); + Shader shader = technique.makeCurrent(renderManager, null, null, null, rendererCaps); + updateShaderMaterialParameters(renderer, shader, null, null); + renderManager.getRenderer().setShader(shader); } private void clearUniformsSetByCurrent(Shader shader) { @@ -1141,80 +924,46 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { * * * - * @param geom The geometry to render + * @param geometry The geometry to render * @param lights Presorted and filtered light list to use for rendering - * @param rm The render manager requesting the rendering + * @param renderManager The render manager requesting the rendering */ - public void render(Geometry geom, LightList lights, RenderManager rm) { - autoSelectTechnique(rm); - TechniqueDef techDef = technique.getDef(); - - if (techDef.isNoRender()) return; - - Renderer r = rm.getRenderer(); - - if (rm.getForcedRenderState() != null) { - r.applyRenderState(rm.getForcedRenderState()); - } else { - if (techDef.getRenderState() != null) { - r.applyRenderState(techDef.getRenderState().copyMergedTo(additionalState, mergedRenderState)); - } else { - r.applyRenderState(RenderState.DEFAULT.copyMergedTo(additionalState, mergedRenderState)); - } - } - - - // update camera and world matrices - // NOTE: setWorldTransform should have been called already - - // reset unchanged uniform flag - clearUniformsSetByCurrent(technique.getShader()); - rm.updateUniformBindings(technique.getWorldBindUniforms()); - - - // setup textures and uniforms - for (int i = 0; i < paramValues.size(); i++) { - MatParam param = paramValues.getValue(i); - param.apply(r, technique); + public void render(Geometry geometry, LightList lights, RenderManager renderManager) { + if (technique == null) { + selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); } - - Shader shader = technique.getShader(); - - // send lighting information, if needed - switch (techDef.getLightMode()) { - case Disable: - break; - case SinglePass: - int nbRenderedLights = 0; - resetUniformsNotSetByCurrent(shader); - if (lights.size() == 0) { - nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, 0); - r.setShader(shader); - renderMeshFromGeometry(r, geom); - } else { - while (nbRenderedLights < lights.size()) { - nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, nbRenderedLights); - r.setShader(shader); - renderMeshFromGeometry(r, geom); - } - } - return; - case FixedPipeline: - throw new IllegalArgumentException("OpenGL1 is not supported"); - case MultiPass: - // NOTE: Special case! - resetUniformsNotSetByCurrent(shader); - renderMultipassLighting(shader, geom, lights, rm); - // very important, notice the return statement! - return; + + TechniqueDef techniqueDef = technique.getDef(); + Renderer renderer = renderManager.getRenderer(); + EnumSet rendererCaps = renderer.getCaps(); + + if (techniqueDef.isNoRender()) { + return; } - // upload and bind shader - // any unset uniforms will be set to 0 + // Apply render state + updateRenderState(renderManager, renderer, techniqueDef); + + // Get world overrides + List overrides = geometry.getWorldMatParamOverrides(); + + // Select shader to use + Shader shader = technique.makeCurrent(renderManager, overrides, renderManager.getForcedMatParams(), lights, rendererCaps); + + // Begin tracking which uniforms were changed by material. + clearUniformsSetByCurrent(shader); + + // Set uniform bindings + renderManager.updateUniformBindings(shader); + + // Set material parameters + updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams()); + + // Clear any uniforms not changed by material. resetUniformsNotSetByCurrent(shader); - r.setShader(shader); - - renderMeshFromGeometry(r, geom); + + // Delegate rendering to the technique + technique.render(renderManager, shader, geometry, lights); } /** @@ -1239,6 +988,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { oc.write(name, "name", null); oc.writeStringSavableMap(paramValues, "parameters", null); } + + @Override + public String toString() { + return "Material[name=" + name + + ", def=" + def.getName() + + ", tech=" + technique.getDef().getName() + + "]"; + } public void read(JmeImporter im) throws IOException { InputCapsule ic = im.getCapsule(this); @@ -1296,11 +1053,6 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { MatParam param = entry.getValue(); if (param instanceof MatParamTexture) { MatParamTexture texVal = (MatParamTexture) param; - - if (nextTexUnit < texVal.getUnit() + 1) { - nextTexUnit = texVal.getUnit() + 1; - } - // the texture failed to load for this param // do not add to param values if (texVal.getTextureValue() == null || texVal.getTextureValue().getImage() == null) { @@ -1335,14 +1087,11 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { // Try to guess values of "apply" render state based on defaults // if value != default then set apply to true additionalState.applyPolyOffset = additionalState.offsetEnabled; - additionalState.applyAlphaFallOff = additionalState.alphaTest; - additionalState.applyAlphaTest = additionalState.alphaTest; additionalState.applyBlendMode = additionalState.blendMode != BlendMode.Off; additionalState.applyColorWrite = !additionalState.colorWrite; additionalState.applyCullMode = additionalState.cullMode != FaceCullMode.Back; additionalState.applyDepthTest = !additionalState.depthTest; additionalState.applyDepthWrite = !additionalState.depthWrite; - additionalState.applyPointSprite = additionalState.pointSprite; additionalState.applyStencilTest = additionalState.stencilTest; additionalState.applyWireFrame = additionalState.wireframe; } diff --git a/jme3-core/src/main/java/com/jme3/material/MaterialDef.java b/jme3-core/src/main/java/com/jme3/material/MaterialDef.java index 47d672f3b..fa205460e 100644 --- a/jme3-core/src/main/java/com/jme3/material/MaterialDef.java +++ b/jme3-core/src/main/java/com/jme3/material/MaterialDef.java @@ -32,6 +32,7 @@ package com.jme3.material; import com.jme3.asset.AssetManager; +import com.jme3.renderer.Caps; import com.jme3.shader.VarType; import com.jme3.texture.image.ColorSpace; import java.util.*; @@ -51,8 +52,7 @@ public class MaterialDef { private String assetName; private AssetManager assetManager; - private List defaultTechs; - private Map techniques; + private Map> techniques; private Map matParams; /** @@ -70,9 +70,8 @@ public class MaterialDef { public MaterialDef(AssetManager assetManager, String name){ this.assetManager = assetManager; this.name = name; - techniques = new HashMap(); + techniques = new HashMap>(); matParams = new HashMap(); - defaultTechs = new ArrayList(); logger.log(Level.FINE, "Loaded material definition: {0}", name); } @@ -135,7 +134,7 @@ public class MaterialDef { * @see ColorSpace */ public void addMaterialParamTexture(VarType type, String name, ColorSpace colorSpace) { - matParams.put(name, new MatParamTexture(type, name, null , 0, colorSpace)); + matParams.put(name, new MatParamTexture(type, name, null, colorSpace)); } /** @@ -164,40 +163,26 @@ public class MaterialDef { /** * Adds a new technique definition to this material definition. - *

- * If the technique name is "Default", it will be added - * to the list of {@link MaterialDef#getDefaultTechniques() default techniques}. - * + * * @param technique The technique definition to add. */ public void addTechniqueDef(TechniqueDef technique) { - if (technique.getName().equals("Default")) { - defaultTechs.add(technique); - } else { - techniques.put(technique.getName(), technique); + List list = techniques.get(technique.getName()); + if (list == null) { + list = new ArrayList<>(); + techniques.put(technique.getName(), list); } + list.add(technique); } /** - * Returns a list of all default techniques. - * - * @return a list of all default techniques. - */ - public List getDefaultTechniques(){ - return defaultTechs; - } - - /** - * Returns a technique definition with the given name. - * This does not include default techniques which can be - * retrieved via {@link MaterialDef#getDefaultTechniques() }. - * - * @param name The name of the technique definition to find - * - * @return The technique definition, or null if cannot be found. + * Returns technique definitions with the given name. + * + * @param name The name of the technique definitions to find + * + * @return The technique definitions, or null if cannot be found. */ - public TechniqueDef getTechniqueDef(String name) { + public List getTechniqueDefs(String name) { return techniques.get(name); } - } diff --git a/jme3-core/src/main/java/com/jme3/material/RenderState.java b/jme3-core/src/main/java/com/jme3/material/RenderState.java index 94cae3f50..1fb33a079 100644 --- a/jme3-core/src/main/java/com/jme3/material/RenderState.java +++ b/jme3-core/src/main/java/com/jme3/material/RenderState.java @@ -75,12 +75,11 @@ public class RenderState implements Cloneable, Savable { /** * TestFunction specifies the testing function for stencil test - * function and alpha test function. + * function. * - *

The functions work similarly as described except that for stencil - * test function, the reference value given in the stencil command is - * the input value while the reference is the value already in the stencil - * buffer. + *

+ * The reference value given in the stencil command is the input value while + * the reference is the value already in the stencil buffer. */ public enum TestFunction { @@ -118,7 +117,94 @@ public class RenderState implements Cloneable, Savable { /** * The test always passes */ - Always,} + Always + } + + /** + * BlendEquation specifies the blending equation to combine + * pixels. + */ + public enum BlendEquation { + /** + * Sets the blend equation so that the source and destination data are + * added. (Default) Clamps to [0,1] Useful for things like antialiasing + * and transparency. + */ + Add, + /** + * Sets the blend equation so that the source and destination data are + * subtracted (Src - Dest). Clamps to [0,1] Falls back to Add if + * supportsSubtract is false. + */ + Subtract, + /** + * Same as Subtract, but the order is reversed (Dst - Src). Clamps to + * [0,1] Falls back to Add if supportsSubtract is false. + */ + ReverseSubtract, + /** + * Sets the blend equation so that each component of the result color is + * the minimum of the corresponding components of the source and + * destination colors. This and Max are useful for applications that + * analyze image data (image thresholding against a constant color, for + * example). Falls back to Add if supportsMinMax is false. + */ + Min, + /** + * Sets the blend equation so that each component of the result color is + * the maximum of the corresponding components of the source and + * destination colors. This and Min are useful for applications that + * analyze image data (image thresholding against a constant color, for + * example). Falls back to Add if supportsMinMax is false. + */ + Max + } + + /** + * BlendEquationAlpha specifies the blending equation to + * combine pixels for the alpha component. + */ + public enum BlendEquationAlpha { + /** + * Sets the blend equation to be the same as the one defined by + * {@link #blendEquation}. + * + */ + InheritColor, + /** + * Sets the blend equation so that the source and destination data are + * added. (Default) Clamps to [0,1] Useful for things like antialiasing + * and transparency. + */ + Add, + /** + * Sets the blend equation so that the source and destination data are + * subtracted (Src - Dest). Clamps to [0,1] Falls back to Add if + * supportsSubtract is false. + */ + Subtract, + /** + * Same as Subtract, but the order is reversed (Dst - Src). Clamps to + * [0,1] Falls back to Add if supportsSubtract is false. + */ + ReverseSubtract, + /** + * Sets the blend equation so that the result alpha is the minimum of + * the source alpha and destination alpha. This and Max are useful for + * applications that analyze image data (image thresholding against a + * constant color, for example). Falls back to Add if supportsMinMax is + * false. + */ + Min, + /** + * sSets the blend equation so that the result alpha is the maximum of + * the source alpha and destination alpha. This and Min are useful for + * applications that analyze image data (image thresholding against a + * constant color, for example). Falls back to Add if supportsMinMax is + * false. + */ + Max + } /** * BlendMode specifies the blending operation to use. @@ -276,19 +362,16 @@ public class RenderState implements Cloneable, Savable { } static { - ADDITIONAL.applyPointSprite = false; ADDITIONAL.applyWireFrame = false; ADDITIONAL.applyCullMode = false; ADDITIONAL.applyDepthWrite = false; ADDITIONAL.applyDepthTest = false; ADDITIONAL.applyColorWrite = false; + ADDITIONAL.applyBlendEquation = false; + ADDITIONAL.applyBlendEquationAlpha = false; ADDITIONAL.applyBlendMode = false; - ADDITIONAL.applyAlphaTest = false; - ADDITIONAL.applyAlphaFallOff = false; ADDITIONAL.applyPolyOffset = false; } - boolean pointSprite = false; - boolean applyPointSprite = true; boolean wireframe = false; boolean applyWireFrame = true; FaceCullMode cullMode = FaceCullMode.Back; @@ -299,12 +382,12 @@ public class RenderState implements Cloneable, Savable { boolean applyDepthTest = true; boolean colorWrite = true; boolean applyColorWrite = true; + BlendEquation blendEquation = BlendEquation.Add; + boolean applyBlendEquation = true; + BlendEquationAlpha blendEquationAlpha = BlendEquationAlpha.InheritColor; + boolean applyBlendEquationAlpha = true; BlendMode blendMode = BlendMode.Off; boolean applyBlendMode = true; - boolean alphaTest = false; - boolean applyAlphaTest = true; - float alphaFallOff = 0; - boolean applyAlphaFallOff = true; float offsetFactor = 0; float offsetUnits = 0; boolean offsetEnabled = false; @@ -315,10 +398,7 @@ public class RenderState implements Cloneable, Savable { boolean applyLineWidth = false; TestFunction depthFunc = TestFunction.LessOrEqual; //by default depth func will be applied anyway if depth test is applied - boolean applyDepthFunc = false; - //by default alpha func will be applied anyway if alpha test is applied - TestFunction alphaFunc = TestFunction.Greater; - boolean applyAlphaFunc = false; + boolean applyDepthFunc = false; StencilOperation frontStencilStencilFailOperation = StencilOperation.Keep; StencilOperation frontStencilDepthFailOperation = StencilOperation.Keep; StencilOperation frontStencilDepthPassOperation = StencilOperation.Keep; @@ -331,15 +411,13 @@ public class RenderState implements Cloneable, Savable { public void write(JmeExporter ex) throws IOException { OutputCapsule oc = ex.getCapsule(this); - oc.write(pointSprite, "pointSprite", false); + oc.write(true, "pointSprite", false); oc.write(wireframe, "wireframe", false); oc.write(cullMode, "cullMode", FaceCullMode.Back); oc.write(depthWrite, "depthWrite", true); oc.write(depthTest, "depthTest", true); oc.write(colorWrite, "colorWrite", true); oc.write(blendMode, "blendMode", BlendMode.Off); - oc.write(alphaTest, "alphaTest", false); - oc.write(alphaFallOff, "alphaFallOff", 0); oc.write(offsetEnabled, "offsetEnabled", false); oc.write(offsetFactor, "offsetFactor", 0); oc.write(offsetUnits, "offsetUnits", 0); @@ -352,38 +430,34 @@ public class RenderState implements Cloneable, Savable { oc.write(backStencilDepthPassOperation, "backStencilDepthPassOperation", StencilOperation.Keep); oc.write(frontStencilFunction, "frontStencilFunction", TestFunction.Always); oc.write(backStencilFunction, "backStencilFunction", TestFunction.Always); + oc.write(blendEquation, "blendEquation", BlendEquation.Add); + oc.write(blendEquationAlpha, "blendEquationAlpha", BlendEquationAlpha.InheritColor); oc.write(depthFunc, "depthFunc", TestFunction.LessOrEqual); - oc.write(alphaFunc, "alphaFunc", TestFunction.Greater); oc.write(lineWidth, "lineWidth", 1); // Only "additional render state" has them set to false by default - oc.write(applyPointSprite, "applyPointSprite", true); oc.write(applyWireFrame, "applyWireFrame", true); oc.write(applyCullMode, "applyCullMode", true); oc.write(applyDepthWrite, "applyDepthWrite", true); oc.write(applyDepthTest, "applyDepthTest", true); oc.write(applyColorWrite, "applyColorWrite", true); + oc.write(applyBlendEquation, "applyBlendEquation", true); + oc.write(applyBlendEquationAlpha, "applyBlendEquationAlpha", true); oc.write(applyBlendMode, "applyBlendMode", true); - oc.write(applyAlphaTest, "applyAlphaTest", true); - oc.write(applyAlphaFallOff, "applyAlphaFallOff", true); oc.write(applyPolyOffset, "applyPolyOffset", true); oc.write(applyDepthFunc, "applyDepthFunc", true); - oc.write(applyAlphaFunc, "applyAlphaFunc", false); oc.write(applyLineWidth, "applyLineWidth", true); } public void read(JmeImporter im) throws IOException { InputCapsule ic = im.getCapsule(this); - pointSprite = ic.readBoolean("pointSprite", false); wireframe = ic.readBoolean("wireframe", false); cullMode = ic.readEnum("cullMode", FaceCullMode.class, FaceCullMode.Back); depthWrite = ic.readBoolean("depthWrite", true); depthTest = ic.readBoolean("depthTest", true); colorWrite = ic.readBoolean("colorWrite", true); blendMode = ic.readEnum("blendMode", BlendMode.class, BlendMode.Off); - alphaTest = ic.readBoolean("alphaTest", false); - alphaFallOff = ic.readFloat("alphaFallOff", 0); offsetEnabled = ic.readBoolean("offsetEnabled", false); offsetFactor = ic.readFloat("offsetFactor", 0); offsetUnits = ic.readFloat("offsetUnits", 0); @@ -396,23 +470,22 @@ public class RenderState implements Cloneable, Savable { backStencilDepthPassOperation = ic.readEnum("backStencilDepthPassOperation", StencilOperation.class, StencilOperation.Keep); frontStencilFunction = ic.readEnum("frontStencilFunction", TestFunction.class, TestFunction.Always); backStencilFunction = ic.readEnum("backStencilFunction", TestFunction.class, TestFunction.Always); + blendEquation = ic.readEnum("blendEquation", BlendEquation.class, BlendEquation.Add); + blendEquationAlpha = ic.readEnum("blendEquationAlpha", BlendEquationAlpha.class, BlendEquationAlpha.InheritColor); depthFunc = ic.readEnum("depthFunc", TestFunction.class, TestFunction.LessOrEqual); - alphaFunc = ic.readEnum("alphaFunc", TestFunction.class, TestFunction.Greater); lineWidth = ic.readFloat("lineWidth", 1); - applyPointSprite = ic.readBoolean("applyPointSprite", true); applyWireFrame = ic.readBoolean("applyWireFrame", true); applyCullMode = ic.readBoolean("applyCullMode", true); applyDepthWrite = ic.readBoolean("applyDepthWrite", true); applyDepthTest = ic.readBoolean("applyDepthTest", true); applyColorWrite = ic.readBoolean("applyColorWrite", true); + applyBlendEquation = ic.readBoolean("applyBlendEquation", true); + applyBlendEquationAlpha = ic.readBoolean("applyBlendEquationAlpha", true); applyBlendMode = ic.readBoolean("applyBlendMode", true); - applyAlphaTest = ic.readBoolean("applyAlphaTest", true); - applyAlphaFallOff = ic.readBoolean("applyAlphaFallOff", true); applyPolyOffset = ic.readBoolean("applyPolyOffset", true); applyDepthFunc = ic.readBoolean("applyDepthFunc", true); - applyAlphaFunc = ic.readBoolean("applyAlphaFunc", false); applyLineWidth = ic.readBoolean("applyLineWidth", true); @@ -433,8 +506,8 @@ public class RenderState implements Cloneable, Savable { } /** - * returns true if the given renderState is equall to this one - * @param o the renderState to compate to + * returns true if the given renderState is equal to this one + * @param o the renderState to compare to * @return true if the renderStates are equal */ @Override @@ -446,9 +519,6 @@ public class RenderState implements Cloneable, Savable { return false; } RenderState rs = (RenderState) o; - if (pointSprite != rs.pointSprite) { - return false; - } if (wireframe != rs.wireframe) { return false; @@ -475,23 +545,19 @@ public class RenderState implements Cloneable, Savable { return false; } - if (blendMode != rs.blendMode) { + if (blendEquation != rs.blendEquation) { return false; } - if (alphaTest != rs.alphaTest) { + if (blendEquationAlpha != rs.blendEquationAlpha) { return false; } - if (alphaTest) { - if (alphaFunc != rs.alphaFunc) { - return false; - } - } - if (alphaFallOff != rs.alphaFallOff) { + if (blendMode != rs.blendMode) { return false; } + if (offsetEnabled != rs.offsetEnabled) { return false; } @@ -544,70 +610,30 @@ public class RenderState implements Cloneable, Savable { } /** - * Enables point sprite mode. - * - *

When point sprite is enabled, any meshes - * with the type of {@link Mode#Points} will be rendered as 2D quads - * with texturing enabled. Fragment shaders can write to the - * gl_PointCoord variable to manipulate the texture coordinate - * for each pixel. The size of the 2D quad can be controlled by writing - * to the gl_PointSize variable in the vertex shader. - * - * @param pointSprite Enables Point Sprite mode. + * @deprecated Does nothing. Point sprite is already enabled by default for + * all supported platforms. jME3 does not support rendering conventional + * point clouds. */ + @Deprecated public void setPointSprite(boolean pointSprite) { - applyPointSprite = true; - this.pointSprite = pointSprite; - cachedHashCode = -1; } /** - * Sets the alpha fall off value for alpha testing. - * - *

If the pixel's alpha value is greater than the - * alphaFallOff then the pixel will be rendered, otherwise - * the pixel will be discarded. - * - * Note : Alpha test is deprecated since opengl 3.0 and does not exists in - * openglES 2.0. - * The prefered way is to use the alphaDiscardThreshold on the material - * Or have a shader that discards the pixel when its alpha value meets the - * discarding condition. - * - * @param alphaFallOff The alpha of all rendered pixels must be higher - * than this value to be rendered. This value should be between 0 and 1. - * - * @see RenderState#setAlphaTest(boolean) + * @deprecated Does nothing. To use alpha test, set the + * AlphaDiscardThreshold material parameter. + * @param alphaFallOff does nothing */ + @Deprecated public void setAlphaFallOff(float alphaFallOff) { - applyAlphaFallOff = true; - this.alphaFallOff = alphaFallOff; - cachedHashCode = -1; } /** - * Enable alpha testing. - * - *

When alpha testing is enabled, all input pixels' alpha are compared - * to the {@link RenderState#setAlphaFallOff(float) constant alpha falloff}. - * If the input alpha is greater than the falloff, the pixel will be rendered, - * otherwise it will be discarded. - * - * @param alphaTest Set to true to enable alpha testing. - * - * Note : Alpha test is deprecated since opengl 3.0 and does not exists in - * openglES 2.0. - * The prefered way is to use the alphaDiscardThreshold on the material - * Or have a shader that discards the pixel when its alpha value meets the - * discarding condition. - * - * - * @see RenderState#setAlphaFallOff(float) + * @deprecated Does nothing. To use alpha test, set the + * AlphaDiscardThreshold material parameter. + * @param alphaTest does nothing */ + @Deprecated public void setAlphaTest(boolean alphaTest) { - applyAlphaTest = true; - this.alphaTest = alphaTest; - cachedHashCode = -1; } /** @@ -663,6 +689,61 @@ public class RenderState implements Cloneable, Savable { cachedHashCode = -1; } + /** + * Set the blending equation. + *

+ * When blending is enabled, (blendMode is not + * {@link BlendMode#Off}) the input pixel will be blended with the pixel + * already in the color buffer. The blending equation is determined by the + * {@link BlendEquation}. For example, the mode {@link BlendMode#Additive} + * and {@link BlendEquation#Add} will add the input pixel's color to the + * color already in the color buffer: + *
+ * Result = Source Color + Destination Color + *
+ * However, the mode {@link BlendMode#Additive} + * and {@link BlendEquation#Subtract} will subtract the input pixel's color to the + * color already in the color buffer: + *
+ * Result = Source Color - Destination Color + * + * @param blendEquation The blend equation to use. + */ + public void setBlendEquation(BlendEquation blendEquation) { + applyBlendEquation = true; + this.blendEquation = blendEquation; + cachedHashCode = -1; + } + + /** + * Set the blending equation for the alpha component. + *

+ * When blending is enabled, (blendMode is not + * {@link BlendMode#Off}) the input pixel will be blended with the pixel + * already in the color buffer. The blending equation is determined by the + * {@link BlendEquation} and can be overrode for the alpha component using + * the {@link BlendEquationAlpha} . For example, the mode + * {@link BlendMode#Additive} and {@link BlendEquationAlpha#Add} will add + * the input pixel's alpha to the alpha component already in the color + * buffer: + *
+ * Result = Source Alpha + Destination Alpha + *
+ * However, the mode {@link BlendMode#Additive} and + * {@link BlendEquationAlpha#Subtract} will subtract the input pixel's alpha + * to the alpha component already in the color buffer: + *
+ * Result = Source Alpha - Destination Alpha + * + * @param blendEquationAlpha The blend equation to use for the alpha + * component. + */ + public void setBlendEquationAlpha(BlendEquationAlpha blendEquationAlpha) { + applyBlendEquationAlpha = true; + this.blendEquationAlpha = blendEquationAlpha; + cachedHashCode = -1; + } + /** * Enable depth testing. * @@ -796,24 +877,10 @@ public class RenderState implements Cloneable, Savable { } /** - * Sets the alpha comparision function to the given TestFunction - * default is Greater (GL_GREATER) - * - * Note : Alpha test is deprecated since opengl 3.0 and does not exists in - * openglES 2.0. - * The prefered way is to use the alphaDiscardThreshold on the material - * Or have a shader taht discards the pixel when its alpha value meets the - * discarding condition. - * - * @see TestFunction - * @see RenderState#setAlphaTest(boolean) - * @see RenderState#setAlphaFallOff(float) - * @param alphaFunc the alpha comparision function + * @deprecated */ - public void setAlphaFunc(TestFunction alphaFunc) { - applyAlphaFunc = true; - this.alphaFunc = alphaFunc; - cachedHashCode = -1; + @Deprecated + public void setAlphaFunc(TestFunction alphaFunc) { } /** @@ -822,6 +889,9 @@ public class RenderState implements Cloneable, Savable { * @param lineWidth the line width. */ public void setLineWidth(float lineWidth) { + if (lineWidth < 1f) { + throw new IllegalArgumentException("lineWidth must be greater than or equal to 1.0"); + } this.lineWidth = lineWidth; this.applyLineWidth = true; cachedHashCode = -1; @@ -988,6 +1058,24 @@ public class RenderState implements Cloneable, Savable { return backStencilFunction; } + /** + * Retrieve the blend equation. + * + * @return the blend equation. + */ + public BlendEquation getBlendEquation() { + return blendEquation; + } + + /** + * Retrieve the blend equation used for the alpha component. + * + * @return the blend equation for the alpha component. + */ + public BlendEquationAlpha getBlendEquationAlpha() { + return blendEquationAlpha; + } + /** * Retrieve the blend mode. * @@ -998,25 +1086,22 @@ public class RenderState implements Cloneable, Savable { } /** - * Check if point sprite mode is enabled - * - * @return True if point sprite mode is enabled. - * - * @see RenderState#setPointSprite(boolean) + * @return true + * @deprecated Always returns true since point sprite is always enabled. + * @see #setPointSprite(boolean) */ + @Deprecated public boolean isPointSprite() { - return pointSprite; + return true; } /** - * Check if alpha test is enabled. - * - * @return True if alpha test is enabled. - * - * @see RenderState#setAlphaTest(boolean) + * @deprecated To use alpha test, set the AlphaDiscardThreshold + * material parameter. + * @return false */ public boolean isAlphaTest() { - return alphaTest; + return false; } /** @@ -1108,14 +1193,12 @@ public class RenderState implements Cloneable, Savable { } /** - * Retrieve the alpha falloff value. - * - * @return the alpha falloff value. - * - * @see RenderState#setAlphaFallOff(float) + * @return 0 + * @deprecated */ + @Deprecated public float getAlphaFallOff() { - return alphaFallOff; + return 0f; } /** @@ -1130,14 +1213,12 @@ public class RenderState implements Cloneable, Savable { } /** - * Retrieve the alpha comparison function - * - * @return the alpha comparison function - * - * @see RenderState#setAlphaFunc(com.jme3.material.RenderState.TestFunction) + * @return {@link TestFunction#Greater}. + * @deprecated */ + @Deprecated public TestFunction getAlphaFunc() { - return alphaFunc; + return TestFunction.Greater; } /** @@ -1150,16 +1231,17 @@ public class RenderState implements Cloneable, Savable { } - public boolean isApplyAlphaFallOff() { - return applyAlphaFallOff; + + public boolean isApplyBlendMode() { + return applyBlendMode; } - public boolean isApplyAlphaTest() { - return applyAlphaTest; + public boolean isApplyBlendEquation() { + return applyBlendEquation; } - public boolean isApplyBlendMode() { - return applyBlendMode; + public boolean isApplyBlendEquationAlpha() { + return applyBlendEquationAlpha; } public boolean isApplyColorWrite() { @@ -1178,9 +1260,6 @@ public class RenderState implements Cloneable, Savable { return applyDepthWrite; } - public boolean isApplyPointSprite() { - return applyPointSprite; - } public boolean isApplyPolyOffset() { return applyPolyOffset; @@ -1194,9 +1273,6 @@ public class RenderState implements Cloneable, Savable { return applyDepthFunc; } - public boolean isApplyAlphaFunc() { - return applyAlphaFunc; - } public boolean isApplyLineWidth() { return applyLineWidth; @@ -1208,7 +1284,6 @@ public class RenderState implements Cloneable, Savable { public int contentHashCode() { if (cachedHashCode == -1){ int hash = 7; - hash = 79 * hash + (this.pointSprite ? 1 : 0); hash = 79 * hash + (this.wireframe ? 1 : 0); hash = 79 * hash + (this.cullMode != null ? this.cullMode.hashCode() : 0); hash = 79 * hash + (this.depthWrite ? 1 : 0); @@ -1216,9 +1291,8 @@ public class RenderState implements Cloneable, Savable { hash = 79 * hash + (this.depthFunc != null ? this.depthFunc.hashCode() : 0); hash = 79 * hash + (this.colorWrite ? 1 : 0); hash = 79 * hash + (this.blendMode != null ? this.blendMode.hashCode() : 0); - hash = 79 * hash + (this.alphaTest ? 1 : 0); - hash = 79 * hash + (this.alphaFunc != null ? this.alphaFunc.hashCode() : 0); - hash = 79 * hash + Float.floatToIntBits(this.alphaFallOff); + hash = 79 * hash + (this.blendEquation != null ? this.blendEquation.hashCode() : 0); + hash = 79 * hash + (this.blendEquationAlpha != null ? this.blendEquationAlpha.hashCode() : 0); hash = 79 * hash + Float.floatToIntBits(this.offsetFactor); hash = 79 * hash + Float.floatToIntBits(this.offsetUnits); hash = 79 * hash + (this.offsetEnabled ? 1 : 0); @@ -1263,11 +1337,6 @@ public class RenderState implements Cloneable, Savable { return this; } - if (additionalState.applyPointSprite) { - state.pointSprite = additionalState.pointSprite; - } else { - state.pointSprite = pointSprite; - } if (additionalState.applyWireFrame) { state.wireframe = additionalState.wireframe; } else { @@ -1299,27 +1368,22 @@ public class RenderState implements Cloneable, Savable { } else { state.colorWrite = colorWrite; } - if (additionalState.applyBlendMode) { - state.blendMode = additionalState.blendMode; + if (additionalState.applyBlendEquation) { + state.blendEquation = additionalState.blendEquation; } else { - state.blendMode = blendMode; + state.blendEquation = blendEquation; } - if (additionalState.applyAlphaTest) { - state.alphaTest = additionalState.alphaTest; + if (additionalState.applyBlendEquationAlpha) { + state.blendEquationAlpha = additionalState.blendEquationAlpha; } else { - state.alphaTest = alphaTest; - } - if (additionalState.applyAlphaFunc) { - state.alphaFunc = additionalState.alphaFunc; + state.blendEquationAlpha = blendEquationAlpha; + } + if (additionalState.applyBlendMode) { + state.blendMode = additionalState.blendMode; } else { - state.alphaFunc = alphaFunc; + state.blendMode = blendMode; } - if (additionalState.applyAlphaFallOff) { - state.alphaFallOff = additionalState.alphaFallOff; - } else { - state.alphaFallOff = alphaFallOff; - } if (additionalState.applyPolyOffset) { state.offsetEnabled = additionalState.offsetEnabled; state.offsetFactor = additionalState.offsetFactor; @@ -1364,16 +1428,14 @@ public class RenderState implements Cloneable, Savable { state.cachedHashCode = -1; return state; } - public void set(RenderState state) { - pointSprite = state.pointSprite; + + public void set(RenderState state) { wireframe = state.wireframe; cullMode = state.cullMode; depthWrite = state.depthWrite; depthTest = state.depthTest; colorWrite = state.colorWrite; blendMode = state.blendMode; - alphaTest = state.alphaTest; - alphaFallOff = state.alphaFallOff; offsetEnabled = state.offsetEnabled; offsetFactor = state.offsetFactor; offsetUnits = state.offsetUnits; @@ -1386,30 +1448,27 @@ public class RenderState implements Cloneable, Savable { backStencilDepthPassOperation = state.backStencilDepthPassOperation; frontStencilFunction = state.frontStencilFunction; backStencilFunction = state.backStencilFunction; + blendEquationAlpha = state.blendEquationAlpha; + blendEquation = state.blendEquation; depthFunc = state.depthFunc; - alphaFunc = state.alphaFunc; lineWidth = state.lineWidth; - applyPointSprite = true; applyWireFrame = true; applyCullMode = true; applyDepthWrite = true; applyDepthTest = true; applyColorWrite = true; - applyBlendMode = true; - applyAlphaTest = true; - applyAlphaFallOff = true; + applyBlendEquation = true; + applyBlendEquationAlpha = true; + applyBlendMode = true; applyPolyOffset = true; - applyDepthFunc = true; - applyAlphaFunc = false; + applyDepthFunc = true; applyLineWidth = true; } @Override public String toString() { return "RenderState[\n" - + "pointSprite=" + pointSprite - + "\napplyPointSprite=" + applyPointSprite + "\nwireframe=" + wireframe + "\napplyWireFrame=" + applyWireFrame + "\ncullMode=" + cullMode @@ -1421,13 +1480,11 @@ public class RenderState implements Cloneable, Savable { + "\napplyDepthTest=" + applyDepthTest + "\ncolorWrite=" + colorWrite + "\napplyColorWrite=" + applyColorWrite + + "\nblendEquation=" + blendEquation + + "\napplyBlendEquation=" + applyBlendEquation + + "\napplyBlendEquationAlpha=" + applyBlendEquationAlpha + "\nblendMode=" + blendMode + "\napplyBlendMode=" + applyBlendMode - + "\nalphaTest=" + alphaTest - + "\nalphaFunc=" + alphaFunc - + "\napplyAlphaTest=" + applyAlphaTest - + "\nalphaFallOff=" + alphaFallOff - + "\napplyAlphaFallOff=" + applyAlphaFallOff + "\noffsetEnabled=" + offsetEnabled + "\napplyPolyOffset=" + applyPolyOffset + "\noffsetFactor=" + offsetFactor diff --git a/jme3-core/src/main/java/com/jme3/material/Technique.java b/jme3-core/src/main/java/com/jme3/material/Technique.java index 8321991bf..8ca95b178 100644 --- a/jme3-core/src/main/java/com/jme3/material/Technique.java +++ b/jme3-core/src/main/java/com/jme3/material/Technique.java @@ -31,27 +31,30 @@ */ package com.jme3.material; +import com.jme3.material.logic.TechniqueDefLogic; import com.jme3.asset.AssetManager; +import com.jme3.light.LightList; +import com.jme3.material.TechniqueDef.LightMode; import com.jme3.renderer.Caps; import com.jme3.renderer.RenderManager; -import com.jme3.shader.*; +import com.jme3.scene.Geometry; +import com.jme3.shader.DefineList; +import com.jme3.shader.Shader; +import com.jme3.shader.VarType; +import com.jme3.util.ListMap; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; -import java.util.logging.Logger; /** * Represents a technique instance. */ -public class Technique /* implements Savable */ { +public final class Technique { - private static final Logger logger = Logger.getLogger(Technique.class.getName()); - private TechniqueDef def; - private Material owner; - private ArrayList worldBindUniforms; - private DefineList defines; - private Shader shader; - private boolean needReload = true; + private final TechniqueDef def; + private final Material owner; + private final DefineList paramDefines; + private final DefineList dynamicDefines; /** * Creates a new technique instance that implements the given @@ -63,14 +66,8 @@ public class Technique /* implements Savable */ { public Technique(Material owner, TechniqueDef def) { this.owner = owner; this.def = def; - this.worldBindUniforms = new ArrayList(); - this.defines = new DefineList(); - } - - /** - * Serialization only. Do not use. - */ - public Technique() { + this.paramDefines = def.createDefineList(); + this.dynamicDefines = def.createDefineList(); } /** @@ -85,157 +82,125 @@ public class Technique /* implements Savable */ { } /** - * Returns the shader currently used by this technique instance. - *

- * Shaders are typically loaded dynamically when the technique is first - * used, therefore, this variable will most likely be null most of the time. - * - * @return the shader currently used by this technique instance. + * Called by the material to tell the technique a parameter was modified. + * Specify null for value if the param is to be cleared. */ - public Shader getShader() { - return shader; - } + final void notifyParamChanged(String paramName, VarType type, Object value) { + Integer defineId = def.getShaderParamDefineId(paramName); + + if (defineId == null) { + return; + } + paramDefines.set(defineId, type, value); + } + /** - * Returns a list of uniforms that implements the world parameters - * that were requested by the material definition. - * - * @return a list of uniforms implementing the world parameters. + * Called by the material to tell the technique that it has been made + * current. + * The technique updates dynamic defines based on the + * currently set material parameters. */ - public List getWorldBindUniforms() { - return worldBindUniforms; + final void notifyTechniqueSwitched() { + ListMap paramMap = owner.getParamsMap(); + paramDefines.clear(); + for (int i = 0; i < paramMap.size(); i++) { + MatParam param = paramMap.getValue(i); + notifyParamChanged(param.getName(), param.getVarType(), param.getValue()); + } } - /** - * Called by the material to tell the technique a parameter was modified. - * Specify null for value if the param is to be cleared. - */ - void notifyParamChanged(String paramName, VarType type, Object value) { - // Check if there's a define binding associated with this - // parameter. - String defineName = def.getShaderParamDefine(paramName); - if (defineName != null) { - // There is a define. Change it on the define list. - // The "needReload" variable will determine - // if the shader will be reloaded when the material - // is rendered. - - if (value == null) { - // Clear the define. - needReload = defines.remove(defineName) || needReload; - } else { - // Set the define. - needReload = defines.set(defineName, type, value) || needReload; + private void applyOverrides(DefineList defineList, List overrides) { + for (MatParamOverride override : overrides) { + if (!override.isEnabled()) { + continue; + } + Integer defineId = def.getShaderParamDefineId(override.name); + if (defineId != null) { + if (def.getDefineIdType(defineId) == override.type) { + defineList.set(defineId, override.type, override.value); + } } } } - void updateUniformParam(String paramName, VarType type, Object value) { - if (paramName == null) { - throw new IllegalArgumentException(); + /** + * Called by the material to determine which shader to use for rendering. + * + * The {@link TechniqueDefLogic} is used to determine the shader to use + * based on the {@link LightMode}. + * + * @param renderManager The render manager for which the shader is to be selected. + * @param rendererCaps The renderer capabilities which the shader should support. + * @return A compatible shader. + */ + Shader makeCurrent(RenderManager renderManager, List worldOverrides, + List forcedOverrides, + LightList lights, EnumSet rendererCaps) { + TechniqueDefLogic logic = def.getLogic(); + AssetManager assetManager = owner.getMaterialDef().getAssetManager(); + + dynamicDefines.clear(); + dynamicDefines.setAll(paramDefines); + + if (worldOverrides != null) { + applyOverrides(dynamicDefines, worldOverrides); } - - Uniform u = shader.getUniform(paramName); - switch (type) { - case TextureBuffer: - case Texture2D: // fall intentional - case Texture3D: - case TextureArray: - case TextureCubeMap: - case Int: - u.setValue(VarType.Int, value); - break; - default: - u.setValue(type, value); - break; + if (forcedOverrides != null) { + applyOverrides(dynamicDefines, forcedOverrides); } - } + return logic.makeCurrent(assetManager, renderManager, rendererCaps, lights, dynamicDefines); + } + /** - * Returns true if the technique must be reloaded. - *

- * If a technique needs to reload, then the {@link Material} should - * call {@link #makeCurrent(com.jme3.asset.AssetManager) } on this - * technique. + * Render the technique according to its {@link TechniqueDefLogic}. * - * @return true if the technique must be reloaded. + * @param renderManager The render manager to perform the rendering against. + * @param shader The shader that was selected in + * {@link #makeCurrent(com.jme3.renderer.RenderManager, java.util.EnumSet)}. + * @param geometry The geometry to render + * @param lights Lights which influence the geometry. */ - public boolean isNeedReload() { - return needReload; + void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights) { + TechniqueDefLogic logic = def.getLogic(); + logic.render(renderManager, shader, geometry, lights); } - + /** - * Prepares the technique for use by loading the shader and setting - * the proper defines based on material parameters. + * Get the {@link DefineList} for dynamic defines. + * + * Dynamic defines are used to implement material parameter -> define + * bindings as well as {@link TechniqueDefLogic} specific functionality. * - * @param assetManager The asset manager to use for loading shaders. + * @return all dynamic defines. */ - public void makeCurrent(AssetManager assetManager, boolean techniqueSwitched, EnumSet rendererCaps, RenderManager rm) { - if (techniqueSwitched) { - if (defines.update(owner.getParamsMap(), def)) { - needReload = true; - } - if (getDef().getLightMode() == TechniqueDef.LightMode.SinglePass) { - defines.set("SINGLE_PASS_LIGHTING", VarType.Boolean, true); - defines.set("NB_LIGHTS", VarType.Int, rm.getSinglePassLightBatchSize() * 3); - } else { - defines.set("SINGLE_PASS_LIGHTING", VarType.Boolean, null); - } - } - - if (needReload) { - loadShader(assetManager,rendererCaps); - } - } - - private void loadShader(AssetManager manager,EnumSet rendererCaps) { - - ShaderKey key = new ShaderKey(getAllDefines(),def.getShaderProgramLanguages(),def.getShaderProgramNames()); - - if (getDef().isUsingShaderNodes()) { - manager.getShaderGenerator(rendererCaps).initialize(this); - key.setUsesShaderNodes(true); - } - shader = manager.loadShader(key); - - // register the world bound uniforms - worldBindUniforms.clear(); - if (def.getWorldBindings() != null) { - for (UniformBinding binding : def.getWorldBindings()) { - Uniform uniform = shader.getUniform("g_" + binding.name()); - uniform.setBinding(binding); - worldBindUniforms.add(uniform); - } - } - needReload = false; + public DefineList getDynamicDefines() { + return dynamicDefines; } /** - * Computes the define list - * @return the complete define list + * @return nothing. + * + * @deprecated Preset defines are precompiled into + * {@link TechniqueDef#getShaderPrologue()}, whereas dynamic defines are + * available via {@link #getParamDefines()}. */ + @Deprecated public DefineList getAllDefines() { - DefineList allDefines = new DefineList(); - allDefines.addFrom(def.getShaderPresetDefines()); - allDefines.addFrom(defines); - return allDefines; - } - - /* - public void write(JmeExporter ex) throws IOException { - OutputCapsule oc = ex.getCapsule(this); - oc.write(def, "def", null); - oc.writeSavableArrayList(worldBindUniforms, "worldBindUniforms", null); - oc.write(defines, "defines", null); - oc.write(shader, "shader", null); + throw new UnsupportedOperationException(); } - - public void read(JmeImporter im) throws IOException { - InputCapsule ic = im.getCapsule(this); - def = (TechniqueDef) ic.readSavable("def", null); - worldBindUniforms = ic.readSavableArrayList("worldBindUniforms", null); - defines = (DefineList) ic.readSavable("defines", null); - shader = (Shader) ic.readSavable("shader", null); + + /** + * Compute the sort ID. Similar to {@link Object#hashCode()} but used + * for sorting geometries for rendering. + * + * @return the sort ID for this technique instance. + */ + public int getSortId() { + int hash = 17; + hash = hash * 23 + def.getSortId(); + hash = hash * 23 + paramDefines.hashCode(); + return hash; } - */ } diff --git a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java index d7523956c..8edc8e19f 100644 --- a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java +++ b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java @@ -31,9 +31,12 @@ */ package com.jme3.material; +import com.jme3.material.logic.TechniqueDefLogic; +import com.jme3.asset.AssetManager; import com.jme3.export.*; import com.jme3.renderer.Caps; import com.jme3.shader.*; +import com.jme3.shader.Shader.ShaderType; import java.io.IOException; import java.util.*; @@ -50,6 +53,14 @@ public class TechniqueDef implements Savable { */ public static final int SAVABLE_VERSION = 1; + /** + * The default technique name. + * + * The technique with this name is selected if no specific technique is + * requested by the user. Currently set to "Default". + */ + public static final String DEFAULT_TECHNIQUE_NAME = "Default"; + /** * Describes light rendering mode. */ @@ -91,13 +102,19 @@ public class TechniqueDef implements Savable { PostPass, } - private EnumSet requiredCaps = EnumSet.noneOf(Caps.class); + private final EnumSet requiredCaps = EnumSet.noneOf(Caps.class); private String name; - + private int sortId; + private EnumMap shaderLanguages; private EnumMap shaderNames; - private DefineList presetDefines; + private String shaderPrologue; + private ArrayList defineNames; + private ArrayList defineTypes; + private HashMap paramToDefineId; + private final HashMap definesToShaderMap; + private boolean usesNodes = false; private List shaderNodes; private ShaderGenerationInfo shaderGenerationInfo; @@ -106,10 +123,10 @@ public class TechniqueDef implements Savable { private RenderState renderState; private RenderState forcedRenderState; - private LightMode lightMode = LightMode.Disable; + private LightMode lightMode = LightMode.Disable; private ShadowMode shadowMode = ShadowMode.Disable; + private TechniqueDefLogic logic; - private HashMap defineParams; private ArrayList worldBinds; /** @@ -117,25 +134,38 @@ public class TechniqueDef implements Savable { *

* Used internally by the J3M/J3MD loader. * - * @param name The name of the technique, should be set to null - * for default techniques. + * @param name The name of the technique */ - public TechniqueDef(String name){ + public TechniqueDef(String name, int sortId){ this(); - this.name = name == null ? "Default" : name; + this.sortId = sortId; + this.name = name; } /** * Serialization only. Do not use. */ - public TechniqueDef(){ - shaderLanguages=new EnumMap(Shader.ShaderType.class); - shaderNames=new EnumMap(Shader.ShaderType.class); + public TechniqueDef() { + shaderLanguages = new EnumMap(Shader.ShaderType.class); + shaderNames = new EnumMap(Shader.ShaderType.class); + defineNames = new ArrayList(); + defineTypes = new ArrayList(); + paramToDefineId = new HashMap(); + definesToShaderMap = new HashMap(); + } + + /** + * @return A unique sort ID. + * No other technique definition can have the same ID. + */ + public int getSortId() { + return sortId; } /** * Returns the name of this technique as specified in the J3MD file. - * Default techniques have the name "Default". + * Default + * techniques have the name {@link #DEFAULT_TECHNIQUE_NAME}. * * @return the name of this technique */ @@ -162,7 +192,15 @@ public class TechniqueDef implements Savable { public void setLightMode(LightMode lightMode) { this.lightMode = lightMode; } + + public void setLogic(TechniqueDefLogic logic) { + this.logic = logic; + } + public TechniqueDefLogic getLogic() { + return logic; + } + /** * Returns the shadow mode. * @return the shadow mode. @@ -224,14 +262,6 @@ public class TechniqueDef implements Savable { return noRender; } - /** - * @deprecated jME3 always requires shaders now - */ - @Deprecated - public boolean isUsingShaders(){ - return true; - } - /** * Returns true if this technique uses Shader Nodes, false otherwise. * @@ -273,34 +303,24 @@ public class TechniqueDef implements Savable { requiredCaps.add(fragCap); } - /** - * Sets the shaders that this technique definition will use. - * - * @param shaderNames EnumMap containing all shader names for this stage - * @param shaderLanguages EnumMap containing all shader languages for this stage + * Set a string which is prepended to every shader used by this technique. + * + * Typically this is used for preset defines. + * + * @param shaderPrologue The prologue to append before the technique's shaders. */ - public void setShaderFile(EnumMap shaderNames, EnumMap shaderLanguages) { - requiredCaps.clear(); - - for (Shader.ShaderType shaderType : shaderNames.keySet()) { - String language = shaderLanguages.get(shaderType); - String shaderFile = shaderNames.get(shaderType); - - this.shaderLanguages.put(shaderType, language); - this.shaderNames.put(shaderType, shaderFile); - - Caps vertCap = Caps.valueOf(language); - requiredCaps.add(vertCap); - - if (shaderType.equals(Shader.ShaderType.Geometry)) { - requiredCaps.add(Caps.GeometryShader); - } else if (shaderType.equals(Shader.ShaderType.TessellationControl)) { - requiredCaps.add(Caps.TesselationShader); - } - } + public void setShaderPrologue(String shaderPrologue) { + this.shaderPrologue = shaderPrologue; } - + + /** + * @return the shader prologue which is prepended to every shader. + */ + public String getShaderPrologue() { + return shaderPrologue; + } + /** * Returns the define name which the given material parameter influences. * @@ -310,60 +330,186 @@ public class TechniqueDef implements Savable { * @see #addShaderParamDefine(java.lang.String, java.lang.String) */ public String getShaderParamDefine(String paramName){ - if (defineParams == null) { + Integer defineId = paramToDefineId.get(paramName); + if (defineId != null) { + return defineNames.get(defineId); + } else { return null; } - return defineParams.get(paramName); + } + + /** + * Get the define ID for a given material parameter. + * + * @param paramName The parameter name to look up + * @return The define ID, or null if not found. + */ + public Integer getShaderParamDefineId(String paramName) { + return paramToDefineId.get(paramName); } + /** + * Get the type of a particular define. + * + * @param defineId The define ID to lookup. + * @return The type of the define, or null if not found. + */ + public VarType getDefineIdType(int defineId) { + return defineId < defineTypes.size() ? defineTypes.get(defineId) : null; + } + /** * 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. + * When set, the material parameter will be mapped to an integer define, + * typically 1 if it is set, unless it is an integer or a float, + * in which case it will converted into an integer. * * @param paramName The name of the material parameter to link to. + * @param paramType The type 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(); + public void addShaderParamDefine(String paramName, VarType paramType, String defineName){ + int defineId = defineNames.size(); + + if (defineId >= DefineList.MAX_DEFINES) { + throw new IllegalStateException("Cannot have more than " + + DefineList.MAX_DEFINES + " defines on a technique."); + } + + paramToDefineId.put(paramName, defineId); + defineNames.add(defineName); + defineTypes.add(paramType); + } + + /** + * Add an unmapped define which can only be set by define ID. + * + * Unmapped defines are used by technique renderers to + * configure the shader internally before rendering. + * + * @param defineName The define name to create + * @return The define ID of the created define + */ + public int addShaderUnmappedDefine(String defineName, VarType defineType) { + int defineId = defineNames.size(); + + if (defineId >= DefineList.MAX_DEFINES) { + throw new IllegalStateException("Cannot have more than " + + DefineList.MAX_DEFINES + " defines on a technique."); } - defineParams.put(paramName, defineName); + + defineNames.add(defineName); + defineTypes.add(defineType); + return defineId; } /** - * Returns the {@link DefineList} for the preset defines. + * Get the names of all defines declared on this technique definition. * - * @return the {@link DefineList} for the preset defines. + * The defines are returned in order of declaration. * - * @see #addShaderPresetDefine(java.lang.String, com.jme3.shader.VarType, java.lang.Object) + * @return the names of all defines declared. */ - public DefineList getShaderPresetDefines() { - return presetDefines; + public String[] getDefineNames() { + return defineNames.toArray(new String[0]); } /** - * 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. + * Get the types of all defines declared on this technique definition. * - * @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. + * The types are returned in order of declaration. * - * @param value The value of the define + * @return the types of all defines declared. */ - public void addShaderPresetDefine(String defineName, VarType type, Object value){ - if (presetDefines == null) { - presetDefines = new DefineList(); + public VarType[] getDefineTypes() { + return defineTypes.toArray(new VarType[0]); + } + + /** + * Create a define list with the size matching the number + * of defines on this technique. + * + * @return a define list with the size matching the number + * of defines on this technique. + */ + public DefineList createDefineList() { + return new DefineList(defineNames.size()); + } + + private Shader loadShader(AssetManager assetManager, EnumSet rendererCaps, DefineList defines) { + StringBuilder sb = new StringBuilder(); + sb.append(shaderPrologue); + defines.generateSource(sb, defineNames, defineTypes); + String definesSourceCode = sb.toString(); + + Shader shader; + if (isUsingShaderNodes()) { + ShaderGenerator shaderGenerator = assetManager.getShaderGenerator(rendererCaps); + if (shaderGenerator == null) { + throw new UnsupportedOperationException("ShaderGenerator was not initialized, " + + "make sure assetManager.getGenerator(caps) has been called"); + } + shaderGenerator.initialize(this); + shader = shaderGenerator.generateShader(definesSourceCode); + } else { + shader = new Shader(); + for (ShaderType type : ShaderType.values()) { + String language = shaderLanguages.get(type); + String shaderSourceAssetName = shaderNames.get(type); + if (language == null || shaderSourceAssetName == null) { + continue; + } + String shaderSourceCode = (String) assetManager.loadAsset(shaderSourceAssetName); + shader.addSource(type, shaderSourceAssetName, shaderSourceCode, definesSourceCode, language); + } + } + + if (getWorldBindings() != null) { + for (UniformBinding binding : getWorldBindings()) { + shader.addUniformBinding(binding); + } + } + + return shader; + } + + public Shader getShader(AssetManager assetManager, EnumSet rendererCaps, DefineList defines) { + Shader shader = definesToShaderMap.get(defines); + if (shader == null) { + shader = loadShader(assetManager, rendererCaps, defines); + definesToShaderMap.put(defines.deepClone(), shader); + } + return shader; + } + + /** + * Sets the shaders that this technique definition will use. + * + * @param shaderNames EnumMap containing all shader names for this stage + * @param shaderLanguages EnumMap containing all shader languages for this stage + */ + public void setShaderFile(EnumMap shaderNames, EnumMap shaderLanguages) { + requiredCaps.clear(); + + for (Shader.ShaderType shaderType : shaderNames.keySet()) { + String language = shaderLanguages.get(shaderType); + String shaderFile = shaderNames.get(shaderType); + + this.shaderLanguages.put(shaderType, language); + this.shaderNames.put(shaderType, shaderFile); + + Caps vertCap = Caps.valueOf(language); + requiredCaps.add(vertCap); + + if (shaderType.equals(Shader.ShaderType.Geometry)) { + requiredCaps.add(Caps.GeometryShader); + } else if (shaderType.equals(Shader.ShaderType.TessellationControl)) { + requiredCaps.add(Caps.TesselationShader); + } } - presetDefines.set(defineName, type, value); } /** @@ -467,7 +613,7 @@ public class TechniqueDef implements Savable { oc.write(shaderLanguages.get(Shader.ShaderType.TessellationControl), "tsctrlLanguage", null); oc.write(shaderLanguages.get(Shader.ShaderType.TessellationEvaluation), "tsevalLanguage", null); - oc.write(presetDefines, "presetDefines", null); + oc.write(shaderPrologue, "shaderPrologue", null); oc.write(lightMode, "lightMode", LightMode.Disable); oc.write(shadowMode, "shadowMode", ShadowMode.Disable); oc.write(renderState, "renderState", null); @@ -490,7 +636,7 @@ public class TechniqueDef implements Savable { shaderNames.put(Shader.ShaderType.Geometry,ic.readString("geomName", null)); shaderNames.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrlName", null)); shaderNames.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tsevalName", null)); - presetDefines = (DefineList) ic.readSavable("presetDefines", null); + shaderPrologue = ic.readString("shaderPrologue", null); lightMode = ic.readEnum("lightMode", LightMode.class, LightMode.Disable); shadowMode = ic.readEnum("shadowMode", ShadowMode.class, ShadowMode.Disable); renderState = (RenderState) ic.readSavable("renderState", null); @@ -547,9 +693,14 @@ public class TechniqueDef implements Savable { this.shaderGenerationInfo = shaderGenerationInfo; } - //todo: make toString return something usefull @Override public String toString() { - return "TechniqueDef{" + "requiredCaps=" + requiredCaps + ", name=" + name /*+ ", vertName=" + vertName + ", fragName=" + fragName + ", vertLanguage=" + vertLanguage + ", fragLanguage=" + fragLanguage */+ ", presetDefines=" + presetDefines + ", usesNodes=" + usesNodes + ", shaderNodes=" + shaderNodes + ", shaderGenerationInfo=" + shaderGenerationInfo + ", renderState=" + renderState + ", forcedRenderState=" + forcedRenderState + ", lightMode=" + lightMode + ", shadowMode=" + shadowMode + ", defineParams=" + defineParams + ", worldBinds=" + worldBinds + ", noRender=" + noRender + '}'; + return "TechniqueDef[name=" + name + + ", requiredCaps=" + requiredCaps + + ", noRender=" + noRender + + ", lightMode=" + lightMode + + ", usesNodes=" + usesNodes + + ", renderState=" + renderState + + ", forcedRenderState=" + forcedRenderState + "]"; } } diff --git a/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java new file mode 100644 index 000000000..ffe72cc00 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2009-2015 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.logic; + +import com.jme3.asset.AssetManager; +import com.jme3.light.AmbientLight; +import com.jme3.light.Light; +import com.jme3.light.LightList; +import com.jme3.material.TechniqueDef; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.instancing.InstancedGeometry; +import com.jme3.shader.DefineList; +import com.jme3.shader.Shader; +import java.util.EnumSet; + +public class DefaultTechniqueDefLogic implements TechniqueDefLogic { + + protected final TechniqueDef techniqueDef; + + public DefaultTechniqueDefLogic(TechniqueDef techniqueDef) { + this.techniqueDef = techniqueDef; + } + + @Override + public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, + EnumSet rendererCaps, LightList lights, DefineList defines) { + return techniqueDef.getShader(assetManager, rendererCaps, defines); + } + + public static void renderMeshFromGeometry(Renderer renderer, Geometry geom) { + Mesh mesh = geom.getMesh(); + int lodLevel = geom.getLodLevel(); + if (geom instanceof InstancedGeometry) { + InstancedGeometry instGeom = (InstancedGeometry) geom; + renderer.renderMesh(mesh, lodLevel, instGeom.getActualNumInstances(), + instGeom.getAllInstanceData()); + } else { + renderer.renderMesh(mesh, lodLevel, 1, null); + } + } + + protected static ColorRGBA getAmbientColor(LightList lightList, boolean removeLights, ColorRGBA ambientLightColor) { + ambientLightColor.set(0, 0, 0, 1); + for (int j = 0; j < lightList.size(); j++) { + Light l = lightList.get(j); + if (l instanceof AmbientLight) { + ambientLightColor.addLocal(l.getColor()); + if (removeLights) { + lightList.remove(l); + } + } + } + ambientLightColor.a = 1.0f; + return ambientLightColor; + } + + @Override + public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights) { + Renderer renderer = renderManager.getRenderer(); + renderer.setShader(shader); + renderMeshFromGeometry(renderer, geometry); + } +} diff --git a/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java new file mode 100644 index 000000000..7b5e2f4a5 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2009-2015 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.logic; + +import com.jme3.asset.AssetManager; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.light.Light; +import com.jme3.light.LightList; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.material.RenderState; +import com.jme3.material.TechniqueDef; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.math.Vector4f; +import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.scene.Geometry; +import com.jme3.shader.DefineList; +import com.jme3.shader.Shader; +import com.jme3.shader.Uniform; +import com.jme3.shader.VarType; +import com.jme3.util.TempVars; +import java.util.EnumSet; + +public final class MultiPassLightingLogic extends DefaultTechniqueDefLogic { + + private static final RenderState ADDITIVE_LIGHT = new RenderState(); + private static final Quaternion NULL_DIR_LIGHT = new Quaternion(0, -1, 0, -1); + + private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1); + + static { + ADDITIVE_LIGHT.setBlendMode(RenderState.BlendMode.AlphaAdditive); + ADDITIVE_LIGHT.setDepthWrite(false); + } + + public MultiPassLightingLogic(TechniqueDef techniqueDef) { + super(techniqueDef); + } + + @Override + public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights) { + Renderer r = renderManager.getRenderer(); + Uniform lightDir = shader.getUniform("g_LightDirection"); + Uniform lightColor = shader.getUniform("g_LightColor"); + Uniform lightPos = shader.getUniform("g_LightPosition"); + Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); + boolean isFirstLight = true; + boolean isSecondLight = false; + + getAmbientColor(lights, false, ambientLightColor); + + for (int i = 0; i < lights.size(); i++) { + Light l = lights.get(i); + if (l instanceof AmbientLight) { + continue; + } + + if (isFirstLight) { + // set ambient color for first light only + ambientColor.setValue(VarType.Vector4, ambientLightColor); + isFirstLight = false; + isSecondLight = true; + } else if (isSecondLight) { + ambientColor.setValue(VarType.Vector4, ColorRGBA.Black); + // apply additive blending for 2nd and future lights + r.applyRenderState(ADDITIVE_LIGHT); + isSecondLight = false; + } + + TempVars vars = TempVars.get(); + Quaternion tmpLightDirection = vars.quat1; + Quaternion tmpLightPosition = vars.quat2; + ColorRGBA tmpLightColor = vars.color; + Vector4f tmpVec = vars.vect4f1; + + ColorRGBA color = l.getColor(); + tmpLightColor.set(color); + tmpLightColor.a = l.getType().getId(); + lightColor.setValue(VarType.Vector4, tmpLightColor); + + switch (l.getType()) { + case Directional: + DirectionalLight dl = (DirectionalLight) l; + Vector3f dir = dl.getDirection(); + //FIXME : there is an inconstency here due to backward + //compatibility of the lighting shader. + //The directional light direction is passed in the + //LightPosition uniform. The lighting shader needs to be + //reworked though in order to fix this. + tmpLightPosition.set(dir.getX(), dir.getY(), dir.getZ(), -1); + lightPos.setValue(VarType.Vector4, tmpLightPosition); + tmpLightDirection.set(0, 0, 0, 0); + lightDir.setValue(VarType.Vector4, tmpLightDirection); + break; + case Point: + PointLight pl = (PointLight) l; + Vector3f pos = pl.getPosition(); + float invRadius = pl.getInvRadius(); + + tmpLightPosition.set(pos.getX(), pos.getY(), pos.getZ(), invRadius); + lightPos.setValue(VarType.Vector4, tmpLightPosition); + tmpLightDirection.set(0, 0, 0, 0); + lightDir.setValue(VarType.Vector4, tmpLightDirection); + break; + case Spot: + SpotLight sl = (SpotLight) l; + Vector3f pos2 = sl.getPosition(); + Vector3f dir2 = sl.getDirection(); + float invRange = sl.getInvSpotRange(); + float spotAngleCos = sl.getPackedAngleCos(); + + tmpLightPosition.set(pos2.getX(), pos2.getY(), pos2.getZ(), invRange); + lightPos.setValue(VarType.Vector4, tmpLightPosition); + + //We transform the spot direction in view space here to save 5 varying later in the lighting shader + //one vec4 less and a vec4 that becomes a vec3 + //the downside is that spotAngleCos decoding happens now in the frag shader. + tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0); + renderManager.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); + tmpLightDirection.set(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos); + + lightDir.setValue(VarType.Vector4, tmpLightDirection); + + break; + default: + throw new UnsupportedOperationException("Unknown type of light: " + l.getType()); + } + vars.release(); + r.setShader(shader); + renderMeshFromGeometry(r, geometry); + } + + if (isFirstLight) { + // Either there are no lights at all, or only ambient lights. + // Render a dummy "normal light" so we can see the ambient color. + ambientColor.setValue(VarType.Vector4, getAmbientColor(lights, false, ambientLightColor)); + lightColor.setValue(VarType.Vector4, ColorRGBA.BlackNoAlpha); + lightPos.setValue(VarType.Vector4, NULL_DIR_LIGHT); + r.setShader(shader); + renderMeshFromGeometry(r, geometry); + } + } +} diff --git a/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java new file mode 100644 index 000000000..2b31c7869 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2009-2015 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.logic; + +import com.jme3.asset.AssetManager; +import com.jme3.light.DirectionalLight; +import com.jme3.light.Light; +import com.jme3.light.LightList; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.material.RenderState; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.material.TechniqueDef; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.math.Vector4f; +import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.scene.Geometry; +import com.jme3.shader.DefineList; +import com.jme3.shader.Shader; +import com.jme3.shader.Uniform; +import com.jme3.shader.VarType; +import com.jme3.util.TempVars; +import java.util.EnumSet; + +public final class SinglePassLightingLogic extends DefaultTechniqueDefLogic { + + private static final String DEFINE_SINGLE_PASS_LIGHTING = "SINGLE_PASS_LIGHTING"; + private static final String DEFINE_NB_LIGHTS = "NB_LIGHTS"; + private static final RenderState ADDITIVE_LIGHT = new RenderState(); + + private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1); + + static { + ADDITIVE_LIGHT.setBlendMode(BlendMode.AlphaAdditive); + ADDITIVE_LIGHT.setDepthWrite(false); + } + + private final int singlePassLightingDefineId; + private final int nbLightsDefineId; + + public SinglePassLightingLogic(TechniqueDef techniqueDef) { + super(techniqueDef); + singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_SINGLE_PASS_LIGHTING, VarType.Boolean); + nbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int); + } + + @Override + public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, + EnumSet rendererCaps, LightList lights, DefineList defines) { + defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3); + defines.set(singlePassLightingDefineId, true); + return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines); + } + + /** + * Uploads the lights in the light list as two uniform arrays.

* + *

+ * uniform vec4 g_LightColor[numLights];
// + * g_LightColor.rgb is the diffuse/specular color of the light.
// + * g_Lightcolor.a is the type of light, 0 = Directional, 1 = Point,
// + * 2 = Spot.

+ * uniform vec4 g_LightPosition[numLights];
// + * g_LightPosition.xyz is the position of the light (for point lights)
+ * // or the direction of the light (for directional lights).
// + * g_LightPosition.w is the inverse radius (1/r) of the light (for + * attenuation)

+ */ + protected int updateLightListUniforms(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex) { + if (numLights == 0) { // this shader does not do lighting, ignore. + return 0; + } + + Uniform lightData = shader.getUniform("g_LightData"); + lightData.setVector4Length(numLights * 3);//8 lights * max 3 + Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); + + + if (startIndex != 0) { + // apply additive blending for 2nd and future passes + rm.getRenderer().applyRenderState(ADDITIVE_LIGHT); + ambientColor.setValue(VarType.Vector4, ColorRGBA.Black); + } else { + ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, true, ambientLightColor)); + } + + int lightDataIndex = 0; + TempVars vars = TempVars.get(); + Vector4f tmpVec = vars.vect4f1; + int curIndex; + int endIndex = numLights + startIndex; + for (curIndex = startIndex; curIndex < endIndex && curIndex < lightList.size(); curIndex++) { + + Light l = lightList.get(curIndex); + if (l.getType() == Light.Type.Ambient) { + endIndex++; + continue; + } + ColorRGBA color = l.getColor(); + //Color + lightData.setVector4InArray(color.getRed(), + color.getGreen(), + color.getBlue(), + l.getType().getId(), + lightDataIndex); + lightDataIndex++; + + switch (l.getType()) { + case Directional: + DirectionalLight dl = (DirectionalLight) l; + Vector3f dir = dl.getDirection(); + //Data directly sent in view space to avoid a matrix mult for each pixel + tmpVec.set(dir.getX(), dir.getY(), dir.getZ(), 0.0f); + rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); +// tmpVec.divideLocal(tmpVec.w); +// tmpVec.normalizeLocal(); + lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), -1, lightDataIndex); + lightDataIndex++; + //PADDING + lightData.setVector4InArray(0, 0, 0, 0, lightDataIndex); + lightDataIndex++; + break; + case Point: + PointLight pl = (PointLight) l; + Vector3f pos = pl.getPosition(); + float invRadius = pl.getInvRadius(); + tmpVec.set(pos.getX(), pos.getY(), pos.getZ(), 1.0f); + rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); + //tmpVec.divideLocal(tmpVec.w); + lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRadius, lightDataIndex); + lightDataIndex++; + //PADDING + lightData.setVector4InArray(0, 0, 0, 0, lightDataIndex); + lightDataIndex++; + break; + case Spot: + SpotLight sl = (SpotLight) l; + Vector3f pos2 = sl.getPosition(); + Vector3f dir2 = sl.getDirection(); + float invRange = sl.getInvSpotRange(); + float spotAngleCos = sl.getPackedAngleCos(); + tmpVec.set(pos2.getX(), pos2.getY(), pos2.getZ(), 1.0f); + rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); + // tmpVec.divideLocal(tmpVec.w); + lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRange, lightDataIndex); + lightDataIndex++; + + //We transform the spot direction in view space here to save 5 varying later in the lighting shader + //one vec4 less and a vec4 that becomes a vec3 + //the downside is that spotAngleCos decoding happens now in the frag shader. + tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0.0f); + rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); + tmpVec.normalizeLocal(); + lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos, lightDataIndex); + lightDataIndex++; + break; + default: + throw new UnsupportedOperationException("Unknown type of light: " + l.getType()); + } + } + vars.release(); + //Padding of unsued buffer space + while(lightDataIndex < numLights * 3) { + lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex); + lightDataIndex++; + } + return curIndex; + } + + @Override + public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights) { + int nbRenderedLights = 0; + Renderer renderer = renderManager.getRenderer(); + int batchSize = renderManager.getSinglePassLightBatchSize(); + if (lights.size() == 0) { + updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, 0); + renderer.setShader(shader); + renderMeshFromGeometry(renderer, geometry); + } else { + while (nbRenderedLights < lights.size()) { + nbRenderedLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, nbRenderedLights); + renderer.setShader(shader); + renderMeshFromGeometry(renderer, geometry); + } + } + } +} diff --git a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java new file mode 100644 index 000000000..4193b118b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2009-2015 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.logic; + +import com.jme3.asset.AssetManager; +import com.jme3.light.DirectionalLight; +import com.jme3.light.Light; +import com.jme3.light.LightList; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.material.TechniqueDef; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Matrix4f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.scene.Geometry; +import com.jme3.shader.DefineList; +import com.jme3.shader.Shader; +import com.jme3.shader.Uniform; +import com.jme3.shader.VarType; +import java.util.ArrayList; +import java.util.EnumSet; + +/** + * Rendering logic for static pass. + * + * @author Kirill Vainer + */ +public final class StaticPassLightingLogic extends DefaultTechniqueDefLogic { + + private static final String DEFINE_NUM_DIR_LIGHTS = "NUM_DIR_LIGHTS"; + private static final String DEFINE_NUM_POINT_LIGHTS = "NUM_POINT_LIGHTS"; + private static final String DEFINE_NUM_SPOT_LIGHTS = "NUM_SPOT_LIGHTS"; + + private final int numDirLightsDefineId; + private final int numPointLightsDefineId; + private final int numSpotLightsDefineId; + + private final ArrayList tempDirLights = new ArrayList(); + private final ArrayList tempPointLights = new ArrayList(); + private final ArrayList tempSpotLights = new ArrayList(); + + private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1); + private final Vector3f tempPosition = new Vector3f(); + private final Vector3f tempDirection = new Vector3f(); + + public StaticPassLightingLogic(TechniqueDef techniqueDef) { + super(techniqueDef); + + numDirLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_DIR_LIGHTS, VarType.Int); + numPointLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_POINT_LIGHTS, VarType.Int); + numSpotLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_SPOT_LIGHTS, VarType.Int); + } + + @Override + public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, + EnumSet rendererCaps, LightList lights, DefineList defines) { + + // TODO: if it ever changes that render isn't called + // right away with the same geometry after makeCurrent, it would be + // a problem. + // Do a radix sort. + tempDirLights.clear(); + tempPointLights.clear(); + tempSpotLights.clear(); + for (Light light : lights) { + switch (light.getType()) { + case Directional: + tempDirLights.add((DirectionalLight) light); + break; + case Point: + tempPointLights.add((PointLight) light); + break; + case Spot: + tempSpotLights.add((SpotLight) light); + break; + } + } + + defines.set(numDirLightsDefineId, tempDirLights.size()); + defines.set(numPointLightsDefineId, tempPointLights.size()); + defines.set(numSpotLightsDefineId, tempSpotLights.size()); + + return techniqueDef.getShader(assetManager, rendererCaps, defines); + } + + private void transformDirection(Matrix4f viewMatrix, Vector3f direction) { + viewMatrix.multNormal(direction, direction); + } + + private void transformPosition(Matrix4f viewMatrix, Vector3f location) { + viewMatrix.mult(location, location); + } + + private void updateLightListUniforms(Matrix4f viewMatrix, Shader shader, LightList lights) { + Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); + ambientColor.setValue(VarType.Vector4, getAmbientColor(lights, true, ambientLightColor)); + + Uniform lightData = shader.getUniform("g_LightData"); + + int totalSize = tempDirLights.size() * 2 + + tempPointLights.size() * 2 + + tempSpotLights.size() * 3; + lightData.setVector4Length(totalSize); + + int index = 0; + for (DirectionalLight light : tempDirLights) { + ColorRGBA color = light.getColor(); + tempDirection.set(light.getDirection()); + transformDirection(viewMatrix, tempDirection); + lightData.setVector4InArray(color.r, color.g, color.b, 1f, index++); + lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, 1f, index++); + } + + for (PointLight light : tempPointLights) { + ColorRGBA color = light.getColor(); + tempPosition.set(light.getPosition()); + float invRadius = light.getInvRadius(); + transformPosition(viewMatrix, tempPosition); + lightData.setVector4InArray(color.r, color.g, color.b, 1f, index++); + lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRadius, index++); + } + + for (SpotLight light : tempSpotLights) { + ColorRGBA color = light.getColor(); + Vector3f pos = light.getPosition(); + Vector3f dir = light.getDirection(); + + tempPosition.set(light.getPosition()); + tempDirection.set(light.getDirection()); + transformPosition(viewMatrix, tempPosition); + transformDirection(viewMatrix, tempDirection); + + float invRange = light.getInvSpotRange(); + float spotAngleCos = light.getPackedAngleCos(); + lightData.setVector4InArray(color.r, color.g, color.b, 1f, index++); + lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRange, index++); + lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, spotAngleCos, index++); + } + } + + @Override + public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights) { + Renderer renderer = renderManager.getRenderer(); + Matrix4f viewMatrix = renderManager.getCurrentCamera().getViewMatrix(); + updateLightListUniforms(viewMatrix, shader, lights); + renderer.setShader(shader); + renderMeshFromGeometry(renderer, geometry); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java new file mode 100644 index 000000000..95ab8ccf3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2009-2015 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.logic; + +import com.jme3.asset.AssetManager; +import com.jme3.light.LightList; +import com.jme3.material.TechniqueDef.LightMode; +import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Geometry; +import com.jme3.shader.DefineList; +import com.jme3.shader.Shader; +import com.jme3.shader.Uniform; +import com.jme3.shader.UniformBinding; +import com.jme3.texture.Texture; +import java.util.EnumSet; + +/** + * TechniqueDefLogic is used to customize how + * a material should be rendered. + * + * Typically used to implement {@link LightMode lighting modes}. + * Implementations can register + * {@link TechniqueDef#addShaderUnmappedDefine(java.lang.String) unmapped defines} + * in their constructor and then later set them based on the geometry + * or light environment being rendered. + * + * @author Kirill Vainer + */ +public interface TechniqueDefLogic { + + /** + * Determine the shader to use for the given geometry / material combination. + * + * @param assetManager The asset manager to use for loading shader source code, + * shader nodes, and and lookup textures. + * @param renderManager The render manager for which rendering is to be performed. + * @param rendererCaps Renderer capabilities. The returned shader must + * support these capabilities. + * @param lights The lights with which the geometry shall be rendered. This + * list must not include culled lights. + * @param defines The define list used by the technique, any + * {@link TechniqueDef#addShaderUnmappedDefine(java.lang.String) unmapped defines} + * should be set here to change shader behavior. + * + * @return The shader to use for rendering. + */ + public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, + EnumSet rendererCaps, LightList lights, DefineList defines); + + /** + * Requests that the TechniqueDefLogic renders the given geometry. + * + * Fixed material functionality such as {@link RenderState}, + * {@link MatParam material parameters}, and + * {@link UniformBinding uniform bindings} + * have already been applied by the material, however, + * {@link RenderState}, {@link Uniform uniforms}, {@link Texture textures}, + * can still be overriden. + * + * @param renderManager The render manager to perform the rendering against. + * * @param shader The shader that was selected by this logic in + * {@link #makeCurrent(com.jme3.asset.AssetManager, com.jme3.renderer.RenderManager, java.util.EnumSet, com.jme3.shader.DefineList)}. + * @param geometry The geometry to render + * @param lights Lights which influence the geometry. + */ + public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights); +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/Camera.java b/jme3-core/src/main/java/com/jme3/renderer/Camera.java index 0ce5bafd7..2d4a61a45 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Camera.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Camera.java @@ -1005,12 +1005,12 @@ public class Camera implements Savable, Cloneable { * * NOTE: This method is used internally for culling, for public usage, * the plane state of the bounding volume must be saved and restored, e.g: - * BoundingVolume bv;
- * Camera c;
- * int planeState = bv.getPlaneState();
- * bv.setPlaneState(0);
- * c.contains(bv);
- * bv.setPlaneState(plateState);
+ * BoundingVolume bv;
+ * Camera c;
+ * int planeState = bv.getPlaneState();
+ * bv.setPlaneState(0);
+ * c.contains(bv);
+ * bv.setPlaneState(plateState);
*
* * @param bound the bound to check for culling diff --git a/jme3-core/src/main/java/com/jme3/renderer/Limits.java b/jme3-core/src/main/java/com/jme3/renderer/Limits.java index 81db88f5e..a7e737092 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Limits.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Limits.java @@ -32,51 +32,34 @@ package com.jme3.renderer; /** - * Limits allows querying the limits of certain features in + * Limits allows querying the limits of certain features in * {@link Renderer}. *

* For example, maximum texture sizes or number of samples. - * + * * @author Kirill Vainer */ public enum Limits { /** - * Maximum number of vertex texture units, or number of textures - * that can be used in the vertex shader. + * Maximum number of vertex texture units, or number of textures that can be + * used in the vertex shader. */ VertexTextureUnits, - /** - * Maximum number of fragment texture units, or number of textures - * that can be used in the fragment shader. + * Maximum number of fragment texture units, or number of textures that can + * be used in the fragment shader. */ FragmentTextureUnits, - - FragmentUniforms, - + FragmentUniformVectors, + VertexUniformVectors, VertexAttributes, - FrameBufferSamples, - FrameBufferAttachments, - FrameBufferMrtAttachments, - RenderBufferSize, - TextureSize, - CubemapSize, - - VertexCount, - - TriangleCount, - ColorTextureSamples, - DepthTextureSamples, - - VertexUniformVectors, - TextureAnisotropy, } diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java index 5be184c94..49f25240a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java @@ -55,16 +55,6 @@ public class RenderContext { */ public boolean depthTestEnabled = false; - /** - * @see RenderState#setAlphaFallOff(float) - */ - public float alphaTestFallOff = 0f; - - /** - * @see RenderState#setAlphaTest(boolean) - */ - public boolean alphaTestEnabled = false; - /** * @see RenderState#setDepthWrite(boolean) */ @@ -111,14 +101,19 @@ public class RenderContext { public RenderState.BlendMode blendMode = RenderState.BlendMode.Off; /** - * @see RenderState#setWireframe(boolean) + * @see RenderState#setBlendEquation(com.jme3.material.RenderState.BlendEquation) */ - public boolean wireframe = false; + public RenderState.BlendEquation blendEquation = RenderState.BlendEquation.Add; + + /** + * @see RenderState#setBlendEquationAlpha(com.jme3.material.RenderState.BlendEquationAlpha) + */ + public RenderState.BlendEquationAlpha blendEquationAlpha = RenderState.BlendEquationAlpha.InheritColor; /** - * @see RenderState#setPointSprite(boolean) + * @see RenderState#setWireframe(boolean) */ - public boolean pointSprite = false; + public boolean wireframe = false; /** * @see Renderer#setShader(com.jme3.shader.Shader) @@ -261,7 +256,6 @@ public class RenderContext { public void reset(){ cullMode = RenderState.FaceCullMode.Off; depthTestEnabled = false; - alphaTestFallOff = 0f; depthWriteEnabled = false; colorWriteEnabled = false; clipRectEnabled = false; @@ -270,6 +264,8 @@ public class RenderContext { polyOffsetUnits = 0; pointSize = 1; blendMode = RenderState.BlendMode.Off; + blendEquation = RenderState.BlendEquation.Add; + blendEquationAlpha = RenderState.BlendEquationAlpha.InheritColor; wireframe = false; boundShaderProgram = 0; boundShader = null; diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java index 7aac5a689..50cc207f7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -34,8 +34,13 @@ package com.jme3.renderer; import com.jme3.light.DefaultLightFilter; import com.jme3.light.LightFilter; import com.jme3.light.LightList; -import com.jme3.material.*; -import com.jme3.math.Matrix4f; +import com.jme3.material.MatParamOverride; +import com.jme3.material.Material; +import com.jme3.material.MaterialDef; +import com.jme3.material.RenderState; +import com.jme3.material.Technique; +import com.jme3.material.TechniqueDef; +import com.jme3.math.*; import com.jme3.post.SceneProcessor; import com.jme3.profile.AppProfiler; import com.jme3.profile.AppStep; @@ -45,13 +50,12 @@ import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.renderer.queue.RenderQueue.ShadowMode; import com.jme3.scene.*; -import com.jme3.shader.Uniform; +import com.jme3.shader.Shader; import com.jme3.shader.UniformBinding; import com.jme3.shader.UniformBindingManager; import com.jme3.system.NullRenderer; import com.jme3.system.Timer; import com.jme3.util.SafeArrayList; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -70,25 +74,26 @@ import java.util.logging.Logger; public class RenderManager { private static final Logger logger = Logger.getLogger(RenderManager.class.getName()); - private Renderer renderer; - private UniformBindingManager uniformBindingManager = new UniformBindingManager(); - private ArrayList preViewPorts = new ArrayList(); - private ArrayList viewPorts = new ArrayList(); - private ArrayList postViewPorts = new ArrayList(); + private final Renderer renderer; + private final UniformBindingManager uniformBindingManager = new UniformBindingManager(); + private final ArrayList preViewPorts = new ArrayList<>(); + private final ArrayList viewPorts = new ArrayList<>(); + private final ArrayList postViewPorts = new ArrayList<>(); private Camera prevCam = null; private Material forcedMaterial = null; private String forcedTechnique = null; private RenderState forcedRenderState = null; + private final List forcedOverrides = new ArrayList<>(); private int viewX, viewY, viewWidth, viewHeight; - private Matrix4f orthoMatrix = new Matrix4f(); - private LightList filteredLightList = new LightList(null); - private String tmpTech; + private final Matrix4f orthoMatrix = new Matrix4f(); + private final LightList filteredLightList = new LightList(null); private boolean handleTranlucentBucket = true; private AppProfiler prof; private LightFilter lightFilter = new DefaultLightFilter(); private TechniqueDef.LightMode preferredLightMode = TechniqueDef.LightMode.MultiPass; private int singlePassLightBatchSize = 1; + /** * Create a high-level rendering interface over the * low-level rendering interface. @@ -423,6 +428,44 @@ public class RenderManager { this.forcedTechnique = forcedTechnique; } + /** + * Adds a forced material parameter to use when rendering geometries. + *

+ * The provided parameter takes precedence over parameters set on the + * material or any overrides that exist in the scene graph that have the + * same name. + * + * @param override The override to add + * @see MatParamOverride + * @see #removeForcedMatParam(com.jme3.material.MatParamOverride) + */ + public void addForcedMatParam(MatParamOverride override) { + forcedOverrides.add(override); + } + + /** + * Remove a forced material parameter previously added. + * + * @param override The override to remove. + * @see #addForcedMatParam(com.jme3.material.MatParamOverride) + */ + public void removeForcedMatParam(MatParamOverride override) { + forcedOverrides.remove(override); + } + + /** + * Get the forced material parameters applied to rendered geometries. + *

+ * Forced parameters can be added via + * {@link #addForcedMatParam(com.jme3.material.MatParamOverride)} or removed + * via {@link #removeForcedMatParam(com.jme3.material.MatParamOverride)}. + * + * @return The forced material parameters. + */ + public List getForcedMatParams() { + return forcedOverrides; + } + /** * Enable or disable alpha-to-coverage. *

@@ -480,8 +523,8 @@ public class RenderManager { * Updates the given list of uniforms with {@link UniformBinding uniform bindings} * based on the current world state. */ - public void updateUniformBindings(List params) { - uniformBindingManager.updateUniformBindings(params); + public void updateUniformBindings(Shader shader) { + uniformBindingManager.updateUniformBindings(shader); } /** @@ -508,45 +551,54 @@ public class RenderManager { * for rendering the material, and the material's own render state is ignored. * Otherwise, the material's render state is used as intended. * - * @param g The geometry to render - * + * @param geom The geometry to render + * * @see Technique * @see RenderState * @see Material#selectTechnique(java.lang.String, com.jme3.renderer.RenderManager) * @see Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager) */ - public void renderGeometry(Geometry g) { - if (g.isIgnoreTransform()) { + public void renderGeometry(Geometry geom) { + if (geom.isIgnoreTransform()) { setWorldMatrix(Matrix4f.IDENTITY); } else { - setWorldMatrix(g.getWorldMatrix()); + setWorldMatrix(geom.getWorldMatrix()); } // Perform light filtering if we have a light filter. - LightList lightList = g.getWorldLightList(); + LightList lightList = geom.getWorldLightList(); if (lightFilter != null) { filteredLightList.clear(); - lightFilter.filterLights(g, filteredLightList); + lightFilter.filterLights(geom, filteredLightList); lightList = filteredLightList; } + Material material = geom.getMaterial(); + //if forcedTechnique we try to force it for render, //if it does not exists in the mat def, we check for forcedMaterial and render the geom if not null //else the geom is not rendered if (forcedTechnique != null) { - if (g.getMaterial().getMaterialDef().getTechniqueDef(forcedTechnique) != null) { - tmpTech = g.getMaterial().getActiveTechnique() != null ? g.getMaterial().getActiveTechnique().getDef().getName() : "Default"; - g.getMaterial().selectTechnique(forcedTechnique, this); + MaterialDef matDef = material.getMaterialDef(); + if (matDef.getTechniqueDefs(forcedTechnique) != null) { + + Technique activeTechnique = material.getActiveTechnique(); + + String previousTechniqueName = activeTechnique != null + ? activeTechnique.getDef().getName() + : TechniqueDef.DEFAULT_TECHNIQUE_NAME; + + geom.getMaterial().selectTechnique(forcedTechnique, this); //saving forcedRenderState for future calls RenderState tmpRs = forcedRenderState; - if (g.getMaterial().getActiveTechnique().getDef().getForcedRenderState() != null) { + if (geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState() != null) { //forcing forced technique renderState - forcedRenderState = g.getMaterial().getActiveTechnique().getDef().getForcedRenderState(); + forcedRenderState = geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState(); } // use geometry's material - g.getMaterial().render(g, lightList, this); - g.getMaterial().selectTechnique(tmpTech, this); + material.render(geom, lightList, this); + material.selectTechnique(previousTechniqueName, this); //restoring forcedRenderState forcedRenderState = tmpRs; @@ -555,13 +607,13 @@ public class RenderManager { //If forcedTechnique does not exists, and forcedMaterial is not set, the geom MUST NOT be rendered } else if (forcedMaterial != null) { // use forced material - forcedMaterial.render(g, lightList, this); + forcedMaterial.render(geom, lightList, this); } } else if (forcedMaterial != null) { // use forced material - forcedMaterial.render(g, lightList, this); + forcedMaterial.render(geom, lightList, this); } else { - g.getMaterial().render(g, lightList, this); + material.render(geom, lightList, this); } } @@ -612,7 +664,9 @@ public class RenderManager { gm.getMaterial().preload(this); Mesh mesh = gm.getMesh(); - if (mesh != null) { + if (mesh != null + && mesh.getVertexCount() != 0 + && mesh.getTriangleCount() != 0) { for (VertexBuffer vb : mesh.getBufferList().getArray()) { if (vb.getData() != null && vb.getUsage() != VertexBuffer.Usage.CpuOnly) { renderer.updateBufferData(vb); @@ -637,8 +691,10 @@ public class RenderManager { *

* In addition to enqueuing the visible geometries, this method * also scenes which cast or receive shadows, by putting them into the - * RenderQueue's {@link RenderQueue#renderShadowQueue(GeometryList, RenderManager, Camera, boolean) shadow queue}. - * Each Spatial which has its {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode} + * RenderQueue's + * {@link RenderQueue#addToShadowQueue(com.jme3.scene.Geometry, com.jme3.renderer.queue.RenderQueue.ShadowMode) + * shadow queue}. Each Spatial which has its + * {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode} * set to not off, will be put into the appropriate shadow queue, note that * this process does not check for frustum culling on any * {@link ShadowMode#Cast shadow casters}, as they don't have to be @@ -985,7 +1041,8 @@ public class RenderManager { * (see {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) }) *

  • If any objects remained in the render queue, they are removed * from the queue. This is generally objects added to the - * {@link RenderQueue#renderShadowQueue(GeometryList, RenderManager, Camera, boolean) shadow queue} + * {@link RenderQueue#renderShadowQueue(com.jme3.renderer.queue.RenderQueue.ShadowMode, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean) + * shadow queue} * which were not rendered because of a missing shadow renderer.
  • * * diff --git a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java index edfd380b4..d6645d24d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java @@ -43,6 +43,7 @@ import com.jme3.texture.Image; import com.jme3.texture.Texture; import com.jme3.util.NativeObject; import java.nio.ByteBuffer; +import java.util.EnumMap; import java.util.EnumSet; /** @@ -66,6 +67,13 @@ public interface Renderer { */ public EnumSet getCaps(); + /** + * Get the limits of the renderer. + * + * @return The limits of the renderer. + */ + public EnumMap getLimits(); + /** * The statistics allow tracking of how data * per frame, such as number of objects rendered, number of triangles, etc. @@ -302,7 +310,21 @@ public interface Renderer { * @see NativeObject#deleteObject(java.lang.Object) */ public void cleanup(); - + + /** + * Set the default anisotropic filter level for textures. + * + * If the + * {@link Texture#setAnisotropicFilter(int) texture anisotropic filter} is + * set to 0, then the default level is used. Otherwise if the texture level + * is 1 or greater, then the texture's value overrides the default value. + * + * @param level The default anisotropic filter level to use. Default: 1. + * + * @throws IllegalArgumentException If level is less than 1. + */ + public void setDefaultAnisotropicFilter(int level); + /** * Sets the alpha to coverage state. *

    diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java index 1b9c3f94d..a4a738152 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java @@ -45,142 +45,149 @@ import java.nio.ShortBuffer; */ public interface GL { - public static final int GL_ALPHA = 0x1906; - public static final int GL_ALWAYS = 0x207; - public static final int GL_ARRAY_BUFFER = 0x8892; - public static final int GL_BACK = 0x405; - public static final int GL_BLEND = 0xBE2; - public static final int GL_BYTE = 0x1400; - public static final int GL_CLAMP_TO_EDGE = 0x812F; - public static final int GL_COLOR_BUFFER_BIT = 0x4000; - public static final int GL_COMPILE_STATUS = 0x8B81; - public static final int GL_CULL_FACE = 0xB44; - public static final int GL_DECR = 0x1E03; - public static final int GL_DECR_WRAP = 0x8508; - public static final int GL_DEPTH_BUFFER_BIT = 0x100; - public static final int GL_DEPTH_COMPONENT = 0x1902; - public static final int GL_DEPTH_COMPONENT16 = 0x81A5; - public static final int GL_DEPTH_TEST = 0xB71; - public static final int GL_DOUBLE = 0x140A; - public static final int GL_DST_COLOR = 0x306; - public static final int GL_DYNAMIC_DRAW = 0x88E8; - public static final int GL_ELEMENT_ARRAY_BUFFER = 0x8893; - public static final int GL_EQUAL = 0x202; - public static final int GL_EXTENSIONS = 0x1F03; - public static final int GL_FALSE = 0x0; - public static final int GL_FLOAT = 0x1406; - public static final int GL_FRAGMENT_SHADER = 0x8B30; - public static final int GL_FRONT = 0x404; - public static final int GL_FRONT_AND_BACK = 0x408; - public static final int GL_GEQUAL = 0x206; - public static final int GL_GREATER = 0x204; - public static final int GL_GREEN = 0x1904; - public static final int GL_INCR = 0x1E02; - public static final int GL_INCR_WRAP = 0x8507; - public static final int GL_INFO_LOG_LENGTH = 0x8B84; - public static final int GL_INT = 0x1404; - public static final int GL_INVALID_ENUM = 0x500; - public static final int GL_INVALID_VALUE = 0x501; - public static final int GL_INVALID_OPERATION = 0x502; - public static final int GL_INVERT = 0x150A; - public static final int GL_KEEP = 0x1E00; - public static final int GL_LEQUAL = 0x203; - public static final int GL_LESS = 0x201; - public static final int GL_LINEAR = 0x2601; - public static final int GL_LINEAR_MIPMAP_LINEAR = 0x2703; - public static final int GL_LINEAR_MIPMAP_NEAREST = 0x2701; - public static final int GL_LINES = 0x1; - public static final int GL_LINE_LOOP = 0x2; - public static final int GL_LINE_STRIP = 0x3; - public static final int GL_LINK_STATUS = 0x8B82; - public static final int GL_LUMINANCE = 0x1909; - public static final int GL_LUMINANCE_ALPHA = 0x190A; - public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; - public static final int GL_MAX_TEXTURE_IMAGE_UNITS = 0x8872; - public static final int GL_MAX_TEXTURE_SIZE = 0xD33; - public static final int GL_MAX_VERTEX_ATTRIBS = 0x8869; - public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C; - public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A; - public static final int GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB; - public static final int GL_MIRRORED_REPEAT = 0x8370; - public static final int GL_NEAREST = 0x2600; - public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702; - public static final int GL_NEAREST_MIPMAP_NEAREST = 0x2700; - public static final int GL_NEVER = 0x200; - public static final int GL_NO_ERROR = 0x0; - public static final int GL_NONE = 0x0; - public static final int GL_NOTEQUAL = 0x205; - public static final int GL_ONE = 0x1; - public static final int GL_ONE_MINUS_DST_COLOR = 0x307; - public static final int GL_ONE_MINUS_SRC_ALPHA = 0x303; - public static final int GL_ONE_MINUS_SRC_COLOR = 0x301; - public static final int GL_OUT_OF_MEMORY = 0x505; - public static final int GL_POINTS = 0x0; - public static final int GL_POLYGON_OFFSET_FILL = 0x8037; - public static final int GL_RED = 0x1903; - public static final int GL_RENDERER = 0x1F01; - public static final int GL_REPEAT = 0x2901; - public static final int GL_REPLACE = 0x1E01; - public static final int GL_RGB = 0x1907; - public static final int GL_RGB565 = 0x8D62; - public static final int GL_RGB5_A1 = 0x8057; - public static final int GL_RGBA = 0x1908; - public static final int GL_RGBA4 = 0x8056; - public static final int GL_SCISSOR_TEST = 0xC11; - public static final int GL_SHADING_LANGUAGE_VERSION = 0x8B8C; - public static final int GL_SHORT = 0x1402; - public static final int GL_SRC_ALPHA = 0x302; - public static final int GL_SRC_COLOR = 0x300; - public static final int GL_STATIC_DRAW = 0x88E4; - public static final int GL_STENCIL_BUFFER_BIT = 0x400; - public static final int GL_STENCIL_TEST = 0xB90; - public static final int GL_STREAM_DRAW = 0x88E0; - public static final int GL_STREAM_READ = 0x88E1; - public static final int GL_TEXTURE = 0x1702; - public static final int GL_TEXTURE0 = 0x84C0; - public static final int GL_TEXTURE1 = 0x84C1; - public static final int GL_TEXTURE2 = 0x84C2; - public static final int GL_TEXTURE3 = 0x84C3; - public static final int GL_TEXTURE4 = 0x84C4; - public static final int GL_TEXTURE5 = 0x84C5; - public static final int GL_TEXTURE6 = 0x84C6; - public static final int GL_TEXTURE7 = 0x84C7; - public static final int GL_TEXTURE8 = 0x84C8; - public static final int GL_TEXTURE9 = 0x84C9; - public static final int GL_TEXTURE10 = 0x84CA; - public static final int GL_TEXTURE11 = 0x84CB; - public static final int GL_TEXTURE12 = 0x84CC; - public static final int GL_TEXTURE13 = 0x84CD; - public static final int GL_TEXTURE14 = 0x84CE; - public static final int GL_TEXTURE15 = 0x84CF; - public static final int GL_TEXTURE_2D = 0xDE1; - public static final int GL_TEXTURE_CUBE_MAP = 0x8513; - public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; - public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516; - public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517; - public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; - public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; - public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; - public static final int GL_TEXTURE_BASE_LEVEL = 0x813C; - public static final int GL_TEXTURE_MAG_FILTER = 0x2800; - public static final int GL_TEXTURE_MAX_LEVEL = 0x813D; - public static final int GL_TEXTURE_MIN_FILTER = 0x2801; - public static final int GL_TEXTURE_WRAP_S = 0x2802; - public static final int GL_TEXTURE_WRAP_T = 0x2803; - public static final int GL_TRIANGLES = 0x4; - public static final int GL_TRIANGLE_FAN = 0x6; - public static final int GL_TRIANGLE_STRIP = 0x5; - public static final int GL_TRUE = 0x1; - public static final int GL_UNPACK_ALIGNMENT = 0xCF5; - public static final int GL_UNSIGNED_BYTE = 0x1401; - public static final int GL_UNSIGNED_INT = 0x1405; - public static final int GL_UNSIGNED_SHORT = 0x1403; - public static final int GL_UNSIGNED_SHORT_5_6_5 = 0x8363; - public static final int GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034; - public static final int GL_VENDOR = 0x1F00; - public static final int GL_VERSION = 0x1F02; - public static final int GL_VERTEX_SHADER = 0x8B31; - public static final int GL_ZERO = 0x0; + public static final int GL_ALPHA = 0x1906; + public static final int GL_ALWAYS = 0x207; + public static final int GL_ARRAY_BUFFER = 0x8892; + public static final int GL_BACK = 0x405; + public static final int GL_BLEND = 0xBE2; + public static final int GL_BYTE = 0x1400; + public static final int GL_CLAMP_TO_EDGE = 0x812F; + public static final int GL_COLOR_BUFFER_BIT = 0x4000; + public static final int GL_COMPILE_STATUS = 0x8B81; + public static final int GL_CULL_FACE = 0xB44; + public static final int GL_DECR = 0x1E03; + public static final int GL_DECR_WRAP = 0x8508; + public static final int GL_DEPTH_BUFFER_BIT = 0x100; + public static final int GL_DEPTH_COMPONENT = 0x1902; + public static final int GL_DEPTH_COMPONENT16 = 0x81A5; + public static final int GL_DEPTH_TEST = 0xB71; + public static final int GL_DOUBLE = 0x140A; + public static final int GL_DST_COLOR = 0x306; + public static final int GL_DYNAMIC_DRAW = 0x88E8; + public static final int GL_ELEMENT_ARRAY_BUFFER = 0x8893; + public static final int GL_EQUAL = 0x202; + public static final int GL_EXTENSIONS = 0x1F03; + public static final int GL_FALSE = 0x0; + public static final int GL_FLOAT = 0x1406; + public static final int GL_FRAGMENT_SHADER = 0x8B30; + public static final int GL_FRONT = 0x404; + public static final int GL_FUNC_ADD = 0x8006; + public static final int GL_FUNC_SUBTRACT = 0x800A; + public static final int GL_FUNC_REVERSE_SUBTRACT = 0x800B; + public static final int GL_FRONT_AND_BACK = 0x408; + public static final int GL_GEQUAL = 0x206; + public static final int GL_GREATER = 0x204; + public static final int GL_GREEN = 0x1904; + public static final int GL_INCR = 0x1E02; + public static final int GL_INCR_WRAP = 0x8507; + public static final int GL_INFO_LOG_LENGTH = 0x8B84; + public static final int GL_INT = 0x1404; + public static final int GL_INVALID_ENUM = 0x500; + public static final int GL_INVALID_VALUE = 0x501; + public static final int GL_INVALID_OPERATION = 0x502; + public static final int GL_INVERT = 0x150A; + public static final int GL_KEEP = 0x1E00; + public static final int GL_LEQUAL = 0x203; + public static final int GL_LESS = 0x201; + public static final int GL_LINEAR = 0x2601; + public static final int GL_LINEAR_MIPMAP_LINEAR = 0x2703; + public static final int GL_LINEAR_MIPMAP_NEAREST = 0x2701; + public static final int GL_LINES = 0x1; + public static final int GL_LINE_LOOP = 0x2; + public static final int GL_LINE_STRIP = 0x3; + public static final int GL_LINK_STATUS = 0x8B82; + public static final int GL_LUMINANCE = 0x1909; + public static final int GL_LUMINANCE_ALPHA = 0x190A; + public static final int GL_MAX = 0x8008; + public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; + public static final int GL_MAX_FRAGMENT_UNIFORM_COMPONENTS = 0x8B49; + public static final int GL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD; + public static final int GL_MAX_TEXTURE_IMAGE_UNITS = 0x8872; + public static final int GL_MAX_TEXTURE_SIZE = 0xD33; + public static final int GL_MAX_VERTEX_ATTRIBS = 0x8869; + public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C; + public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A; + public static final int GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB; + public static final int GL_MIRRORED_REPEAT = 0x8370; + public static final int GL_MIN = 0x8007; + public static final int GL_NEAREST = 0x2600; + public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702; + public static final int GL_NEAREST_MIPMAP_NEAREST = 0x2700; + public static final int GL_NEVER = 0x200; + public static final int GL_NO_ERROR = 0x0; + public static final int GL_NONE = 0x0; + public static final int GL_NOTEQUAL = 0x205; + public static final int GL_ONE = 0x1; + public static final int GL_ONE_MINUS_DST_COLOR = 0x307; + public static final int GL_ONE_MINUS_SRC_ALPHA = 0x303; + public static final int GL_ONE_MINUS_SRC_COLOR = 0x301; + public static final int GL_OUT_OF_MEMORY = 0x505; + public static final int GL_POINTS = 0x0; + public static final int GL_POLYGON_OFFSET_FILL = 0x8037; + public static final int GL_RED = 0x1903; + public static final int GL_RENDERER = 0x1F01; + public static final int GL_REPEAT = 0x2901; + public static final int GL_REPLACE = 0x1E01; + public static final int GL_RGB = 0x1907; + public static final int GL_RGB565 = 0x8D62; + public static final int GL_RGB5_A1 = 0x8057; + public static final int GL_RGBA = 0x1908; + public static final int GL_RGBA4 = 0x8056; + public static final int GL_SCISSOR_TEST = 0xC11; + public static final int GL_SHADING_LANGUAGE_VERSION = 0x8B8C; + public static final int GL_SHORT = 0x1402; + public static final int GL_SRC_ALPHA = 0x302; + public static final int GL_SRC_COLOR = 0x300; + public static final int GL_STATIC_DRAW = 0x88E4; + public static final int GL_STENCIL_BUFFER_BIT = 0x400; + public static final int GL_STENCIL_TEST = 0xB90; + public static final int GL_STREAM_DRAW = 0x88E0; + public static final int GL_STREAM_READ = 0x88E1; + public static final int GL_TEXTURE = 0x1702; + public static final int GL_TEXTURE0 = 0x84C0; + public static final int GL_TEXTURE1 = 0x84C1; + public static final int GL_TEXTURE2 = 0x84C2; + public static final int GL_TEXTURE3 = 0x84C3; + public static final int GL_TEXTURE4 = 0x84C4; + public static final int GL_TEXTURE5 = 0x84C5; + public static final int GL_TEXTURE6 = 0x84C6; + public static final int GL_TEXTURE7 = 0x84C7; + public static final int GL_TEXTURE8 = 0x84C8; + public static final int GL_TEXTURE9 = 0x84C9; + public static final int GL_TEXTURE10 = 0x84CA; + public static final int GL_TEXTURE11 = 0x84CB; + public static final int GL_TEXTURE12 = 0x84CC; + public static final int GL_TEXTURE13 = 0x84CD; + public static final int GL_TEXTURE14 = 0x84CE; + public static final int GL_TEXTURE15 = 0x84CF; + public static final int GL_TEXTURE_2D = 0xDE1; + public static final int GL_TEXTURE_CUBE_MAP = 0x8513; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517; + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; + public static final int GL_TEXTURE_BASE_LEVEL = 0x813C; + public static final int GL_TEXTURE_MAG_FILTER = 0x2800; + public static final int GL_TEXTURE_MAX_LEVEL = 0x813D; + public static final int GL_TEXTURE_MIN_FILTER = 0x2801; + public static final int GL_TEXTURE_WRAP_S = 0x2802; + public static final int GL_TEXTURE_WRAP_T = 0x2803; + public static final int GL_TRIANGLES = 0x4; + public static final int GL_TRIANGLE_FAN = 0x6; + public static final int GL_TRIANGLE_STRIP = 0x5; + public static final int GL_TRUE = 0x1; + public static final int GL_UNPACK_ALIGNMENT = 0xCF5; + public static final int GL_UNSIGNED_BYTE = 0x1401; + public static final int GL_UNSIGNED_INT = 0x1405; + public static final int GL_UNSIGNED_SHORT = 0x1403; + public static final int GL_UNSIGNED_SHORT_5_6_5 = 0x8363; + public static final int GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034; + public static final int GL_VENDOR = 0x1F00; + public static final int GL_VERSION = 0x1F02; + public static final int GL_VERTEX_SHADER = 0x8B31; + public static final int GL_ZERO = 0x0; public void resetStats(); @@ -188,6 +195,7 @@ public interface GL { public void glAttachShader(int program, int shader); public void glBindBuffer(int target, int buffer); public void glBindTexture(int target, int texture); + public void glBlendEquationSeparate(int colorMode, int alphaMode); public void glBlendFunc(int sfactor, int dfactor); public void glBufferData(int target, long data_size, int usage); public void glBufferData(int target, FloatBuffer data, int usage); diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java index fd18cc7ff..44dc3687a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java @@ -100,4 +100,9 @@ public class GLDebugDesktop extends GLDebugES implements GL2, GL3, GL4 { gl3.glFramebufferTextureLayer(param1, param2, param3, param4, param5); checkError(); } + + public void glBlendEquationSeparate(int colorMode, int alphaMode) { + gl.glBlendEquationSeparate(colorMode, alphaMode); + checkError(); + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java index 2348bd3cd..ed6b336f8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java @@ -560,4 +560,9 @@ public class GLDebugES extends GLDebug implements GL, GLFbo, GLExt { checkError(); return sync; } + + public void glBlendEquationSeparate(int colorMode, int alphaMode) { + gl.glBlendEquationSeparate(colorMode, alphaMode); + checkError(); + } } 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 636733583..70d25ccd4 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 @@ -90,6 +90,7 @@ public final class GLRenderer implements Renderer { private final Statistics statistics = new Statistics(); private int vpX, vpY, vpW, vpH; private int clipX, clipY, clipW, clipH; + private int defaultAnisotropicFilter = 1; private boolean linearizeSrgbImages; private HashSet extensions; @@ -252,18 +253,14 @@ public final class GLRenderer implements Renderer { limits.put(Limits.FragmentTextureUnits, getInteger(GL.GL_MAX_TEXTURE_IMAGE_UNITS)); -// gl.glGetInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS, intBuf16); -// vertexUniforms = intBuf16.get(0); -// logger.log(Level.FINER, "Vertex Uniforms: {0}", vertexUniforms); -// -// gl.glGetInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16); -// fragUniforms = intBuf16.get(0); -// logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms); if (caps.contains(Caps.OpenGLES20)) { + limits.put(Limits.FragmentUniformVectors, getInteger(GL.GL_MAX_FRAGMENT_UNIFORM_VECTORS)); limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_VECTORS)); } else { + limits.put(Limits.FragmentUniformVectors, getInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS) / 4); limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS) / 4); } + limits.put(Limits.VertexAttributes, getInteger(GL.GL_MAX_VERTEX_ATTRIBS)); limits.put(Limits.TextureSize, getInteger(GL.GL_MAX_TEXTURE_SIZE)); limits.put(Limits.CubemapSize, getInteger(GL.GL_MAX_CUBE_MAP_TEXTURE_SIZE)); @@ -474,6 +471,17 @@ public final class GLRenderer implements Renderer { { sb.append("\t").append(cap.toString()).append("\n"); } + + sb.append("\nHardware limits: \n"); + for (Limits limit : Limits.values()) { + Integer value = limits.get(limit); + if (value == null) { + value = 0; + } + sb.append("\t").append(limit.name()).append(" = ") + .append(value).append("\n"); + } + logger.log(Level.FINE, sb.toString()); } @@ -522,7 +530,6 @@ public final class GLRenderer implements Renderer { gl2.glEnable(GL2.GL_VERTEX_PROGRAM_POINT_SIZE); if (!caps.contains(Caps.CoreProfile)) { gl2.glEnable(GL2.GL_POINT_SPRITE); - context.pointSprite = true; } } } @@ -594,6 +601,14 @@ public final class GLRenderer implements Renderer { } } + @Override + public void setDefaultAnisotropicFilter(int level) { + if (level < 1) { + throw new IllegalArgumentException("level cannot be less than 1"); + } + this.defaultAnisotropicFilter = level; + } + public void setAlphaToCoverage(boolean value) { if (caps.contains(Caps.Multisample)) { if (value) { @@ -735,6 +750,19 @@ public final class GLRenderer implements Renderer { throw new UnsupportedOperationException("Unrecognized blend mode: " + state.getBlendMode()); } + + if (state.getBlendEquation() != context.blendEquation || state.getBlendEquationAlpha() != context.blendEquationAlpha) { + int colorMode = convertBlendEquation(state.getBlendEquation()); + int alphaMode; + if (state.getBlendEquationAlpha() == RenderState.BlendEquationAlpha.InheritColor) { + alphaMode = colorMode; + } else { + alphaMode = convertBlendEquationAlpha(state.getBlendEquationAlpha()); + } + gl.glBlendEquationSeparate(colorMode, alphaMode); + context.blendEquation = state.getBlendEquation(); + context.blendEquationAlpha = state.getBlendEquationAlpha(); + } } context.blendMode = state.getBlendMode(); @@ -785,6 +813,41 @@ public final class GLRenderer implements Renderer { } } + private int convertBlendEquation(RenderState.BlendEquation blendEquation) { + switch (blendEquation) { + case Add: + return GL2.GL_FUNC_ADD; + case Subtract: + return GL2.GL_FUNC_SUBTRACT; + case ReverseSubtract: + return GL2.GL_FUNC_REVERSE_SUBTRACT; + case Min: + return GL2.GL_MIN; + case Max: + return GL2.GL_MAX; + default: + throw new UnsupportedOperationException("Unrecognized blend operation: " + blendEquation); + } + } + + private int convertBlendEquationAlpha(RenderState.BlendEquationAlpha blendEquationAlpha) { + //Note: InheritColor mode should already be handled, that is why it does not belong the the switch case. + switch (blendEquationAlpha) { + case Add: + return GL2.GL_FUNC_ADD; + case Subtract: + return GL2.GL_FUNC_SUBTRACT; + case ReverseSubtract: + return GL2.GL_FUNC_REVERSE_SUBTRACT; + case Min: + return GL2.GL_MIN; + case Max: + return GL2.GL_MAX; + default: + throw new UnsupportedOperationException("Unrecognized alpha blend operation: " + blendEquationAlpha); + } + } + private int convertStencilOperation(StencilOperation stencilOp) { switch (stencilOp) { case Keep: @@ -964,12 +1027,12 @@ public final class GLRenderer implements Renderer { gl.glUniform1i(loc, b.booleanValue() ? GL.GL_TRUE : GL.GL_FALSE); break; case Matrix3: - fb = (FloatBuffer) uniform.getValue(); + fb = uniform.getMultiData(); assert fb.remaining() == 9; gl.glUniformMatrix3(loc, false, fb); break; case Matrix4: - fb = (FloatBuffer) uniform.getValue(); + fb = uniform.getMultiData(); assert fb.remaining() == 16; gl.glUniformMatrix4(loc, false, fb); break; @@ -978,23 +1041,23 @@ public final class GLRenderer implements Renderer { gl.glUniform1(loc, ib); break; case FloatArray: - fb = (FloatBuffer) uniform.getValue(); + fb = uniform.getMultiData(); gl.glUniform1(loc, fb); break; case Vector2Array: - fb = (FloatBuffer) uniform.getValue(); + fb = uniform.getMultiData(); gl.glUniform2(loc, fb); break; case Vector3Array: - fb = (FloatBuffer) uniform.getValue(); + fb = uniform.getMultiData(); gl.glUniform3(loc, fb); break; case Vector4Array: - fb = (FloatBuffer) uniform.getValue(); + fb = uniform.getMultiData(); gl.glUniform4(loc, fb); break; case Matrix4Array: - fb = (FloatBuffer) uniform.getValue(); + fb = uniform.getMultiData(); gl.glUniformMatrix4(loc, false, fb); break; case Int: @@ -1872,13 +1935,18 @@ public final class GLRenderer implements Renderer { gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, convertMinFilter(tex.getMinFilter(), haveMips)); curState.minFilter = tex.getMinFilter(); } + + int desiredAnisoFilter = tex.getAnisotropicFilter() == 0 + ? defaultAnisotropicFilter + : tex.getAnisotropicFilter(); + if (caps.contains(Caps.TextureFilterAnisotropic) - && curState.anisoFilter != tex.getAnisotropicFilter()) { + && curState.anisoFilter != desiredAnisoFilter) { bindTextureAndUnit(target, image, unit); gl.glTexParameterf(target, GLExt.GL_TEXTURE_MAX_ANISOTROPY_EXT, - tex.getAnisotropicFilter()); - curState.anisoFilter = tex.getAnisotropicFilter(); + desiredAnisoFilter); + curState.anisoFilter = desiredAnisoFilter; } switch (tex.getType()) { @@ -2689,12 +2757,15 @@ public final class GLRenderer implements Renderer { } public void renderMesh(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) { - if (mesh.getVertexCount() == 0) { + if (mesh.getVertexCount() == 0 || mesh.getTriangleCount() == 0 || count == 0) { return; } - //this is kept for backward compatibility. - if (mesh.getLineWidth() != -1 && context.lineWidth != mesh.getLineWidth()) { + if (count > 1 && !caps.contains(Caps.MeshInstancing)) { + throw new RendererException("Mesh instancing is not supported by the video hardware"); + } + + if (mesh.getLineWidth() != 1f && context.lineWidth != mesh.getLineWidth()) { gl.glLineWidth(mesh.getLineWidth()); context.lineWidth = mesh.getLineWidth(); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java b/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java index 5529ac84e..09b43b9e8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java @@ -99,6 +99,16 @@ public class GeometryList implements Iterable{ return size; } + /** + * Sets the element at the given index. + * + * @param index The index to set + * @param value The value + */ + public void set(int index, Geometry value) { + geometries[index] = value; + } + /** * Returns the element at the given index. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/OpaqueComparator.java b/jme3-core/src/main/java/com/jme3/renderer/queue/OpaqueComparator.java index 6ffff5702..4b1305c60 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/queue/OpaqueComparator.java +++ b/jme3-core/src/main/java/com/jme3/renderer/queue/OpaqueComparator.java @@ -69,11 +69,12 @@ public class OpaqueComparator implements GeometryComparator { return spat.queueDistance; } + @Override public int compare(Geometry o1, Geometry o2) { Material m1 = o1.getMaterial(); Material m2 = o2.getMaterial(); - - int compareResult = m2.getSortId() - m1.getSortId(); + + int compareResult = Integer.compare(m1.getSortId(), m2.getSortId()); if (compareResult == 0){ // use the same shader. // sort front-to-back then. diff --git a/jme3-core/src/main/java/com/jme3/scene/Mesh.java b/jme3-core/src/main/java/com/jme3/scene/Mesh.java index 6a0b41c8c..84c279536 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Mesh.java +++ b/jme3-core/src/main/java/com/jme3/scene/Mesh.java @@ -175,7 +175,7 @@ public class Mesh implements Savable, Cloneable, JmeCloneable { private IntMap buffers = new IntMap(); private VertexBuffer[] lodLevels; private float pointSize = 1; - private float lineWidth = -1; + private float lineWidth = 1; private transient int vertexArrayID = -1; @@ -589,28 +589,26 @@ public class Mesh implements Savable, Cloneable, JmeCloneable { } /** - * Returns the size of points for point meshes + * @deprecated Always returns 1.0 since point size is + * determined in the vertex shader. * - * @return the size of points + * @return 1.0 * * @see #setPointSize(float) */ + @Deprecated public float getPointSize() { - return pointSize; + return 1.0f; } /** - * Set the size of points for meshes of mode {@link Mode#Points}. - * The point size is specified as on-screen pixels, the default - * value is 1.0. The point size - * does nothing if {@link RenderState#setPointSprite(boolean) point sprite} - * render state is enabled, in that case, the vertex shader must specify the - * point size by writing to gl_PointSize. + * @deprecated Does nothing, since the size of {@link Mode#Points points} is + * determined via the vertex shader's gl_PointSize output. * - * @param pointSize The size of points + * @param pointSize ignored */ + @Deprecated public void setPointSize(float pointSize) { - this.pointSize = pointSize; } /** @@ -634,6 +632,9 @@ public class Mesh implements Savable, Cloneable, JmeCloneable { */ @Deprecated public void setLineWidth(float lineWidth) { + if (lineWidth < 1f) { + throw new IllegalArgumentException("lineWidth must be greater than or equal to 1.0"); + } this.lineWidth = lineWidth; } diff --git a/jme3-core/src/main/java/com/jme3/scene/Node.java b/jme3-core/src/main/java/com/jme3/scene/Node.java index 35526c3ce..6089eda49 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Node.java +++ b/jme3-core/src/main/java/com/jme3/scene/Node.java @@ -75,7 +75,6 @@ public class Node extends Spatial { * requiresUpdate() method. */ private SafeArrayList updateList = null; - /** * False if the update list requires rebuilding. This is Node.class * specific and therefore not included as part of the Spatial update flags. @@ -100,7 +99,6 @@ public class Node extends Spatial { */ public Node(String name) { super(name); - // For backwards compatibility, only clear the "requires // update" flag if we are not a subclass of Node. // This prevents subclass from silently failing to receive @@ -141,10 +139,21 @@ public class Node extends Spatial { } } + @Override + protected void setMatParamOverrideRefresh() { + super.setMatParamOverrideRefresh(); + for (Spatial child : children.getArray()) { + if ((child.refreshFlags & RF_MATPARAM_OVERRIDE) != 0) { + continue; + } + + child.setMatParamOverrideRefresh(); + } + } + @Override protected void updateWorldBound(){ super.updateWorldBound(); - // for a node, the world bound is a combination of all it's children // bounds BoundingVolume resultBound = null; @@ -239,19 +248,19 @@ public class Node extends Spatial { // This branch has no geometric state that requires updates. return; } - if ((refreshFlags & RF_LIGHTLIST) != 0){ updateWorldLightList(); } - if ((refreshFlags & RF_TRANSFORM) != 0){ // combine with parent transforms- same for all spatial // subclasses. updateWorldTransforms(); } + if ((refreshFlags & RF_MATPARAM_OVERRIDE) != 0) { + updateMatParamOverrides(); + } refreshFlags &= ~RF_CHILD_LIGHTLIST; - if (!children.isEmpty()) { // the important part- make sure child geometric state is refreshed // first before updating own world bound. This saves @@ -287,7 +296,6 @@ public class Node extends Spatial { return count; } - /** * getVertexCount returns the number of vertices contained * in all sub-branches of this node that contain geometry. @@ -321,7 +329,6 @@ public class Node extends Spatial { public int attachChild(Spatial child) { return attachChildAt(child, children.size()); } - /** * * attachChildAt attaches a child to this node at an index. This node @@ -345,20 +352,18 @@ public class Node extends Spatial { } child.setParent(this); children.add(index, child); - // XXX: Not entirely correct? Forces bound update up the // tree stemming from the attached child. Also forces // transform update down the tree- child.setTransformRefresh(); child.setLightListRefresh(); + child.setMatParamOverrideRefresh(); if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE,"Child ({0}) attached to this node ({1})", new Object[]{child.getName(), getName()}); } - invalidateUpdateList(); } - return children.size(); } @@ -433,7 +438,8 @@ public class Node extends Spatial { child.setTransformRefresh(); // lights are also inherited from parent child.setLightListRefresh(); - + child.setMatParamOverrideRefresh(); + invalidateUpdateList(); } return child; @@ -519,7 +525,6 @@ public class Node extends Spatial { } return null; } - /** * determines if the provided Spatial is contained in the children list of * this node. @@ -567,39 +572,32 @@ public class Node extends Spatial { public int collideWith(Collidable other, CollisionResults results){ int total = 0; - // optimization: try collideWith BoundingVolume to avoid possibly redundant tests on children // number 4 in condition is somewhat arbitrary. When there is only one child, the boundingVolume test is redundant at all. // The idea is when there are few children, it can be too expensive to test boundingVolume first. /* I'm removing this change until some issues can be addressed and I really think it needs to be implemented a better way anyway. - First, it causes issues for anyone doing collideWith() with BoundingVolumes and expecting it to trickle down to the children. For example, children with BoundingSphere bounding volumes and collideWith(BoundingSphere). Doing a collision check at the parent level then has to do a BoundingSphere to BoundingBox collision which isn't resolved. (Having to come up with a collision point in that case is tricky and the first sign that this is the wrong approach.) - Second, the rippling changes this caused to 'optimize' collideWith() for this special use-case are another sign that this approach was a bit dodgy. The whole idea of calculating a full collision just to see if the two shapes collide at all is very wasteful. - A proper implementation should support a simpler boolean check that doesn't do all of that calculation. For example, if 'other' is also a BoundingVolume (ie: 99.9% of all non-Ray cases) then a direct BV to BV intersects() test can be done. So much faster. And if 'other' _is_ a Ray then the BV.intersects(Ray) call can be done. - I don't have time to do it right now but I'll at least un-break a bunch of peoples' code until it can be 'optimized' properly. Hopefully it's not too late to back out the other dodgy ripples this caused. -pspeed (hindsight-expert ;)) - Note: the code itself is relatively simple to implement but I don't have time to a) test it, and b) see if '> 4' is still a decent check for it. Could be it's fast enough to do all the time for > 1. - if (children.size() > 4) { BoundingVolume bv = this.getWorldBound(); @@ -692,7 +690,6 @@ public class Node extends Spatial { // Reset the fields of the clone that should be in a 'new' state. nodeClone.updateList = null; nodeClone.updateListValid = false; // safe because parent is nulled out in super.clone() - return nodeClone; } @@ -732,7 +729,6 @@ public class Node extends Spatial { // cloning this list is fine. this.updateList = cloner.clone(updateList); } - @Override public void write(JmeExporter e) throws IOException { super.write(e); @@ -744,7 +740,6 @@ public class Node extends Spatial { // XXX: Load children before loading itself!! // This prevents empty children list if controls query // it in Control.setSpatial(). - children = new SafeArrayList( Spatial.class, e.getCapsule(this).readSavableArrayList("children", null) ); @@ -754,7 +749,6 @@ public class Node extends Spatial { child.parent = this; } } - super.read(e); } @@ -775,7 +769,6 @@ public class Node extends Spatial { } } } - @Override public void depthFirstTraversal(SceneGraphVisitor visitor) { for (Spatial child : children.getArray()) { @@ -783,7 +776,6 @@ public class Node extends Spatial { } visitor.visit(this); } - @Override protected void breadthFirstTraversal(SceneGraphVisitor visitor, Queue queue) { queue.addAll(children); diff --git a/jme3-core/src/main/java/com/jme3/scene/Spatial.java b/jme3-core/src/main/java/com/jme3/scene/Spatial.java index 15757eee0..452ccce47 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Spatial.java +++ b/jme3-core/src/main/java/com/jme3/scene/Spatial.java @@ -38,6 +38,7 @@ import com.jme3.collision.Collidable; import com.jme3.export.*; import com.jme3.light.Light; import com.jme3.light.LightList; +import com.jme3.material.MatParamOverride; import com.jme3.material.Material; import com.jme3.math.*; import com.jme3.renderer.Camera; @@ -121,9 +122,10 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab */ protected static final int RF_TRANSFORM = 0x01, // need light resort + combine transforms RF_BOUND = 0x02, - RF_LIGHTLIST = 0x04, // changes in light lists - RF_CHILD_LIGHTLIST = 0x08; // some child need geometry update - + RF_LIGHTLIST = 0x04, // changes in light lists + RF_CHILD_LIGHTLIST = 0x08, // some child need geometry update + RF_MATPARAM_OVERRIDE = 0x10; + protected CullHint cullHint = CullHint.Inherit; protected BatchHint batchHint = BatchHint.Inherit; /** @@ -135,7 +137,11 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab */ protected LightList localLights; protected transient LightList worldLights; - /** + + protected ArrayList localOverrides; + protected ArrayList worldOverrides; + + /** * This spatial's name. */ protected String name; @@ -195,13 +201,14 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab */ protected Spatial(String name) { this.name = name; - localTransform = new Transform(); worldTransform = new Transform(); localLights = new LightList(this); worldLights = new LightList(this); + localOverrides = new ArrayList<>(); + worldOverrides = new ArrayList<>(); refreshFlags |= RF_BOUND; } @@ -222,7 +229,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab boolean requiresUpdates() { return requiresUpdates | !controls.isEmpty(); } - /** * Subclasses can call this with true to denote that they require * updateLogicalState() to be called even if they contain no controls. @@ -272,35 +278,33 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab protected void setLightListRefresh() { refreshFlags |= RF_LIGHTLIST; - // Make sure next updateGeometricState() visits this branch // to update lights. Spatial p = parent; while (p != null) { - //if (p.refreshFlags != 0) { - // any refresh flag is sufficient, - // as each propagates to the root Node - - // 2015/2/8: - // This is not true, because using e.g. getWorldBound() - // or getWorldTransform() activates a "partial refresh" - // which does not update the lights but does clear - // the refresh flags on the ancestors! - - // return; - //} - if ((p.refreshFlags & RF_CHILD_LIGHTLIST) != 0) { // The parent already has this flag, // so must all ancestors. return; } - p.refreshFlags |= RF_CHILD_LIGHTLIST; p = p.parent; } } + protected void setMatParamOverrideRefresh() { + refreshFlags |= RF_MATPARAM_OVERRIDE; + Spatial p = parent; + while (p != null) { + if ((p.refreshFlags & RF_MATPARAM_OVERRIDE) != 0) { + return; + } + + p.refreshFlags |= RF_MATPARAM_OVERRIDE; + p = p.parent; + } + } + /** * Indicate that the bounding of this spatial has changed and that * a refresh is required. @@ -318,7 +322,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab p = p.parent; } } - /** * (Internal use only) Forces a refresh of the given types of data. * @@ -424,6 +427,29 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab return worldLights; } + /** + * Get the local material parameter overrides. + * + * @return The list of local material parameter overrides. + */ + public List getLocalMatParamOverrides() { + return localOverrides; + } + + /** + * Get the world material parameter overrides. + * + * Note that this list is only updated on a call to + * {@link #updateGeometricState()}. After update, the world overrides list + * will contain the {@link #getParent() parent's} world overrides combined + * with this spatial's {@link #getLocalMatParamOverrides() local overrides}. + * + * @return The list of world material parameter overrides. + */ + public List getWorldMatParamOverrides() { + return worldOverrides; + } + /** * getWorldRotation retrieves the absolute rotation of the * Spatial. @@ -525,10 +551,8 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab TempVars vars = TempVars.get(); Vector3f compVecA = vars.vect4; - compVecA.set(position).subtractLocal(worldTranslation); getLocalRotation().lookAt(compVecA, upVector); - if ( getParent() != null ) { Quaternion rot=vars.quat1; rot = rot.set(parent.getWorldRotation()).inverseLocal().multLocal(getLocalRotation()); @@ -555,15 +579,63 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab worldLights.update(localLights, null); refreshFlags &= ~RF_LIGHTLIST; } else { - if ((parent.refreshFlags & RF_LIGHTLIST) == 0) { - worldLights.update(localLights, parent.worldLights); - refreshFlags &= ~RF_LIGHTLIST; - } else { - assert false; - } + assert (parent.refreshFlags & RF_LIGHTLIST) == 0; + worldLights.update(localLights, parent.worldLights); + refreshFlags &= ~RF_LIGHTLIST; + } + } + + protected void updateMatParamOverrides() { + refreshFlags &= ~RF_MATPARAM_OVERRIDE; + + worldOverrides.clear(); + if (parent == null) { + worldOverrides.addAll(localOverrides); + } else { + assert (parent.refreshFlags & RF_MATPARAM_OVERRIDE) == 0; + worldOverrides.addAll(parent.worldOverrides); + worldOverrides.addAll(localOverrides); + } + } + + /** + * Adds a local material parameter override. + * + * @param override The override to add. + * @see MatParamOverride + */ + public void addMatParamOverride(MatParamOverride override) { + if (override == null) { + throw new IllegalArgumentException("override cannot be null"); + } + localOverrides.add(override); + setMatParamOverrideRefresh(); + } + + /** + * Remove a local material parameter override if it exists. + * + * @param override The override to remove. + * @see MatParamOverride + */ + public void removeMatParamOverride(MatParamOverride override) { + if (localOverrides.remove(override)) { + setMatParamOverrideRefresh(); } } + /** + * Remove all local material parameter overrides. + * + * @see #addMatParamOverride(com.jme3.material.MatParamOverride) + */ + public void clearMatParamOverrides() { + if (!localOverrides.isEmpty()) { + setMatParamOverrideRefresh(); + } + localOverrides.clear(); + } + /** * Should only be called from updateGeometricState(). * In most cases should not be subclassed. @@ -696,7 +768,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab controls.add(control); control.setSpatial(this); boolean after = requiresUpdates(); - // If the requirement to be updated has changed // then we need to let the parent node know so it // can rebuild its update list. @@ -720,7 +791,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab } } boolean after = requiresUpdates(); - // If the requirement to be updated has changed // then we need to let the parent node know so it // can rebuild its update list. @@ -746,14 +816,12 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab } boolean after = requiresUpdates(); - // If the requirement to be updated has changed // then we need to let the parent node know so it // can rebuild its update list. if( parent != null && before != after ) { parent.invalidateUpdateList(); } - return result; } @@ -838,7 +906,10 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab if ((refreshFlags & RF_BOUND) != 0) { updateWorldBound(); } - + if ((refreshFlags & RF_MATPARAM_OVERRIDE) != 0) { + updateMatParamOverrides(); + } + assert refreshFlags == 0; } @@ -1292,6 +1363,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab // the transforms and stuff get refreshed. clone.setTransformRefresh(); clone.setLightListRefresh(); + clone.setMatParamOverrideRefresh(); return clone; } @@ -1312,6 +1384,13 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab clone.localLights.setOwner(clone); clone.worldLights.setOwner(clone); + clone.worldOverrides = new ArrayList(); + clone.localOverrides = new ArrayList(); + + for (MatParamOverride override : localOverrides) { + clone.localOverrides.add((MatParamOverride) override.clone()); + } + // No need to force cloned to update. // This node already has the refresh flags // set below so it will have to update anyway. @@ -1333,6 +1412,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab clone.setBoundRefresh(); clone.setTransformRefresh(); clone.setLightListRefresh(); + clone.setMatParamOverrideRefresh(); clone.controls = new SafeArrayList(Control.class); for (int i = 0; i < controls.size(); i++) { @@ -1388,6 +1468,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab // the transforms and stuff get refreshed. clone.setTransformRefresh(); clone.setLightListRefresh(); + clone.setMatParamOverrideRefresh(); return clone; } @@ -1419,6 +1500,8 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab this.localLights = cloner.clone(localLights); this.worldTransform = cloner.clone(worldTransform); this.localTransform = cloner.clone(localTransform); + this.worldOverrides = cloner.clone(worldOverrides); + this.localOverrides = cloner.clone(localOverrides); this.controls = cloner.clone(controls); // Cloner doesn't handle maps on its own just yet. @@ -1515,6 +1598,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab capsule.write(shadowMode, "shadow_mode", ShadowMode.Inherit); capsule.write(localTransform, "transform", Transform.IDENTITY); capsule.write(localLights, "lights", null); + capsule.writeSavableArrayList(localOverrides, "overrides", null); // Shallow clone the controls array to convert its type. capsule.writeSavableArrayList(new ArrayList(controls), "controlsList", null); @@ -1538,6 +1622,12 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab localLights = (LightList) ic.readSavable("lights", null); localLights.setOwner(this); + localOverrides = ic.readSavableArrayList("overrides", null); + if (localOverrides == null) { + localOverrides = new ArrayList<>(); + } + worldOverrides = new ArrayList<>(); + //changed for backward compatibility with j3o files generated before the AnimControl/SkeletonControl split //the AnimControl creates the SkeletonControl for old files and add it to the spatial. //The SkeletonControl must be the last in the stack so we add the list of all other control before it. diff --git a/jme3-core/src/main/java/com/jme3/scene/VertexBuffer.java b/jme3-core/src/main/java/com/jme3/scene/VertexBuffer.java index c67435b78..70d40a64c 100644 --- a/jme3-core/src/main/java/com/jme3/scene/VertexBuffer.java +++ b/jme3-core/src/main/java/com/jme3/scene/VertexBuffer.java @@ -108,8 +108,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable { * Do not use. */ @Deprecated - MiscAttrib, - + Reserved0, /** * Specifies the index buffer, must contain integer data * (ubyte, ushort, or uint). @@ -522,6 +521,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable { // throw new UnsupportedOperationException("Data has already been sent. Cannot set usage."); this.usage = usage; + this.setUpdateNeeded(); } /** diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/WireBox.java b/jme3-core/src/main/java/com/jme3/scene/debug/WireBox.java index 5d0577c5a..d4e4e1d58 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/WireBox.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/WireBox.java @@ -101,14 +101,6 @@ public class WireBox extends Mesh { ); updateBound(); } - - /** - * Old method retained for compatibility: use makeGeometry instead. - */ - @Deprecated - public void fromBoundingBox(BoundingBox bbox) { - updatePositions(bbox.getXExtent(), bbox.getYExtent(), bbox.getZExtent()); - } /** * Create a geometry suitable for visualizing the specified bounding box. diff --git a/jme3-core/src/main/java/com/jme3/shader/DefineList.java b/jme3-core/src/main/java/com/jme3/shader/DefineList.java index dd605fc7e..d9b5782aa 100644 --- a/jme3-core/src/main/java/com/jme3/shader/DefineList.java +++ b/jme3-core/src/main/java/com/jme3/shader/DefineList.java @@ -1,286 +1,179 @@ -/* - * Copyright (c) 2009-2012 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.shader; - -import com.jme3.export.*; -import com.jme3.material.MatParam; -import com.jme3.material.TechniqueDef; -import com.jme3.util.ListMap; - -import java.io.IOException; -import java.util.Map; -import java.util.TreeMap; - -public final class DefineList implements Savable, Cloneable { - - private static final String ONE = "1"; - - private TreeMap defines = new TreeMap(); - private String compiled = null; - private int cachedHashCode = 0; - - public void write(JmeExporter ex) throws IOException{ - OutputCapsule oc = ex.getCapsule(this); - - String[] keys = new String[defines.size()]; - String[] vals = new String[defines.size()]; - - int i = 0; - for (Map.Entry define : defines.entrySet()){ - keys[i] = define.getKey(); - vals[i] = define.getValue(); - i++; - } - - oc.write(keys, "keys", null); - oc.write(vals, "vals", null); - } - - public void read(JmeImporter im) throws IOException{ - InputCapsule ic = im.getCapsule(this); - - String[] keys = ic.readStringArray("keys", null); - String[] vals = ic.readStringArray("vals", null); - for (int i = 0; i < keys.length; i++){ - defines.put(keys[i], vals[i]); - } - } - - public void clear() { - defines.clear(); - compiled = ""; - cachedHashCode = 0; - } - - public String get(String key){ - return defines.get(key); - } - - @Override - public DefineList clone() { - try { - DefineList clone = (DefineList) super.clone(); - clone.cachedHashCode = 0; - clone.compiled = null; - clone.defines = (TreeMap) defines.clone(); - return clone; - } catch (CloneNotSupportedException ex) { - throw new AssertionError(); - } - } - - public boolean set(String key, VarType type, Object val){ - if (val == null){ - defines.remove(key); - compiled = null; - cachedHashCode = 0; - return true; - } - - switch (type){ - case Boolean: - if (((Boolean) val).booleanValue()) { - // same literal, != will work - if (defines.put(key, ONE) != ONE) { - compiled = null; - cachedHashCode = 0; - return true; - } - } else if (defines.containsKey(key)) { - defines.remove(key); - compiled = null; - cachedHashCode = 0; - return true; - } - - break; - case Float: - case Int: - String newValue = val.toString(); - String original = defines.put(key, newValue); - if (!val.equals(original)) { - compiled = null; - cachedHashCode = 0; - return true; - } - break; - default: - // same literal, != will work - if (defines.put(key, ONE) != ONE) { - compiled = null; - cachedHashCode = 0; - return true; - } - break; - } - - return false; - } - - public boolean remove(String key){ - if (defines.remove(key) != null) { - compiled = null; - cachedHashCode = 0; - return true; - } - return false; - } - - public void addFrom(DefineList other){ - if (other == null) { - return; - } - compiled = null; - cachedHashCode = 0; - defines.putAll(other.defines); - } - - public String getCompiled(){ - if (compiled == null){ - StringBuilder sb = new StringBuilder(); - for (Map.Entry entry : defines.entrySet()){ - sb.append("#define ").append(entry.getKey()).append(" "); - sb.append(entry.getValue()).append('\n'); - } - compiled = sb.toString(); - } - return compiled; - } - - @Override - public boolean equals(Object obj) { - final DefineList other = (DefineList) obj; - return defines.equals(other.defines); - } - - /** - * Update defines if the define list changed based on material parameters. - * @param params - * @param def - * @return true if defines was updated - */ - public boolean update(ListMap params, TechniqueDef def){ - if(equalsParams(params, def)){ - return false; - } - // Defines were changed, update define list - clear(); - for(int i=0;i entry : defines.entrySet()) { - sb.append(entry.getKey()).append("=").append(entry.getValue()); - if (i != defines.size() - 1) { - sb.append(", "); - } - i++; - } - return sb.toString(); - } - -} +/* + * Copyright (c) 2009-2015 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.shader; + +import java.util.Arrays; +import java.util.List; + +/** + * The new define list. + * + * @author Kirill Vainer + */ +public final class DefineList { + + public static final int MAX_DEFINES = 64; + + private long hash; + private final int[] vals; + + public DefineList(int numValues) { + if (numValues < 0 || numValues > MAX_DEFINES) { + throw new IllegalArgumentException("numValues must be between 0 and 64"); + } + vals = new int[numValues]; + } + + private DefineList(DefineList original) { + this.hash = original.hash; + this.vals = new int[original.vals.length]; + System.arraycopy(original.vals, 0, vals, 0, vals.length); + } + + public void set(int id, int val) { + assert 0 <= id && id < 64; + if (val != 0) { + hash |= (1L << id); + } else { + hash &= ~(1L << id); + } + vals[id] = val; + } + + public void set(int id, float val) { + set(id, Float.floatToIntBits(val)); + } + + public void set(int id, boolean val) { + set(id, val ? 1 : 0); + } + + public void set(int id, VarType type, Object value) { + if (value == null) { + set(id, 0); + return; + } + + switch (type) { + case Int: + set(id, (Integer) value); + break; + case Float: + set(id, (Float) value); + break; + case Boolean: + set(id, ((Boolean) value)); + break; + default: + set(id, 1); + break; + } + } + + public void setAll(DefineList other) { + for (int i = 0; i < other.vals.length; i++) { + if (other.vals[i] != 0) { + vals[i] = other.vals[i]; + } + } + } + + public void clear() { + hash = 0; + Arrays.fill(vals, 0); + } + + public boolean getBoolean(int id) { + return vals[id] != 0; + } + + public float getFloat(int id) { + return Float.intBitsToFloat(vals[id]); + } + + public int getInt(int id) { + return vals[id]; + } + + @Override + public int hashCode() { + return (int)((hash >> 32) ^ hash); + } + + @Override + public boolean equals(Object other) { + DefineList o = (DefineList) other; + if (hash == o.hash) { + for (int i = 0; i < vals.length; i++) { + if (vals[i] != o.vals[i]) return false; + } + return true; + } + return false; + } + + public DefineList deepClone() { + return new DefineList(this); + } + + public void generateSource(StringBuilder sb, List defineNames, List defineTypes) { + for (int i = 0; i < vals.length; i++) { + if (vals[i] != 0) { + String defineName = defineNames.get(i); + + sb.append("#define "); + sb.append(defineName); + sb.append(" "); + + if (defineTypes != null && defineTypes.get(i) == VarType.Float) { + float val = Float.intBitsToFloat(vals[i]); + if (Float.isInfinite(val) || Float.isNaN(val)) { + throw new IllegalArgumentException( + "GLSL does not support NaN " + + "or Infinite float literals"); + } + sb.append(val); + } else { + sb.append(vals[i]); + } + + sb.append("\n"); + } + } + } + + public String generateSource(List defineNames, List defineTypes) { + StringBuilder sb = new StringBuilder(); + generateSource(sb, defineNames, defineTypes); + return sb.toString(); + } +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/shader/Shader.java b/jme3-core/src/main/java/com/jme3/shader/Shader.java index eb084f178..d6fc495f2 100644 --- a/jme3-core/src/main/java/com/jme3/shader/Shader.java +++ b/jme3-core/src/main/java/com/jme3/shader/Shader.java @@ -45,44 +45,63 @@ public final class Shader extends NativeObject { /** * A list of all shader sources currently attached. */ - private ArrayList shaderSourceList; + private final ArrayList shaderSourceList; /** * Maps uniform name to the uniform variable. */ - private ListMap uniforms; + private final ListMap uniforms; + + /** + * Uniforms bound to {@link UniformBinding}s. + * + * Managed by the {@link UniformBindingManager}. + */ + private final ArrayList boundUniforms; /** * Maps attribute name to the location of the attribute in the shader. */ - private IntMap attribs; + private final IntMap attribs; /** * Type of shader. The shader will control the pipeline of it's type. */ public static enum ShaderType { + /** * Control fragment rasterization. (e.g color of pixel). */ - Fragment, - + Fragment("frag"), /** * Control vertex processing. (e.g transform of model to clip space) */ - Vertex, - + Vertex("vert"), /** - * Control geometry assembly. (e.g compile a triangle list from input data) + * Control geometry assembly. (e.g compile a triangle list from input + * data) */ - Geometry, + Geometry("geom"), /** - * Controls tesselation factor (e.g how often a input patch should be subdivided) + * Controls tesselation factor (e.g how often a input patch should be + * subdivided) */ - TessellationControl, + TessellationControl("tsctrl"), /** - * Controls tesselation transform (e.g similar to the vertex shader, but required to mix inputs manual) + * Controls tesselation transform (e.g similar to the vertex shader, but + * required to mix inputs manual) */ - TessellationEvaluation; + TessellationEvaluation("tseval"); + + private String extension; + + public String getExtension() { + return extension; + } + + private ShaderType(String extension) { + this.extension = extension; + } } /** @@ -195,22 +214,16 @@ public final class Shader extends NativeObject { } } - /** - * Initializes the shader for use, must be called after the - * constructor without arguments is used. - */ - public void initialize() { - shaderSourceList = new ArrayList(); - uniforms = new ListMap(); - attribs = new IntMap(); - } - /** * Creates a new shader, {@link #initialize() } must be called * after this constructor for the shader to be usable. */ public Shader(){ super(); + shaderSourceList = new ArrayList(); + uniforms = new ListMap(); + attribs = new IntMap(); + boundUniforms = new ArrayList(); } /** @@ -225,6 +238,10 @@ public final class Shader extends NativeObject { for (ShaderSource source : s.shaderSourceList){ shaderSourceList.add( (ShaderSource)source.createDestructableClone() ); } + + uniforms = null; + boundUniforms = null; + attribs = null; } /** @@ -248,6 +265,18 @@ public final class Shader extends NativeObject { setUpdateNeeded(); } + public void addUniformBinding(UniformBinding binding){ + String uniformName = "g_" + binding.name(); + Uniform uniform = uniforms.get(uniformName); + if (uniform == null) { + uniform = new Uniform(); + uniform.name = uniformName; + uniform.binding = binding; + uniforms.put(uniformName, uniform); + boundUniforms.add(uniform); + } + } + public Uniform getUniform(String name){ assert name.startsWith("m_") || name.startsWith("g_"); Uniform uniform = uniforms.get(name); @@ -277,6 +306,10 @@ public final class Shader extends NativeObject { public ListMap getUniformMap(){ return uniforms; } + + public ArrayList getBoundUniforms() { + return boundUniforms; + } public Collection getSources(){ return shaderSourceList; diff --git a/jme3-core/src/main/java/com/jme3/shader/ShaderGenerator.java b/jme3-core/src/main/java/com/jme3/shader/ShaderGenerator.java index f5aeca2ed..d42dccf17 100644 --- a/jme3-core/src/main/java/com/jme3/shader/ShaderGenerator.java +++ b/jme3-core/src/main/java/com/jme3/shader/ShaderGenerator.java @@ -57,9 +57,9 @@ public abstract class ShaderGenerator { */ protected int indent; /** - * the technique to use for the shader generation + * the technique def to use for the shader generation */ - protected Technique technique = null; + protected TechniqueDef techniqueDef = null; /** * Build a shaderGenerator @@ -70,8 +70,8 @@ public abstract class ShaderGenerator { this.assetManager = assetManager; } - public void initialize(Technique technique){ - this.technique = technique; + public void initialize(TechniqueDef techniqueDef){ + this.techniqueDef = techniqueDef; } /** @@ -79,24 +79,29 @@ public abstract class ShaderGenerator { * * @return a Shader program */ - public Shader generateShader() { - if(technique == null){ - throw new UnsupportedOperationException("The shaderGenerator was not properly initialized, call initialize(Technique) before any generation"); + public Shader generateShader(String definesSourceCode) { + if (techniqueDef == null) { + throw new UnsupportedOperationException("The shaderGenerator was not " + + "properly initialized, call " + + "initialize(TechniqueDef) before any generation"); } - DefineList defines = technique.getAllDefines(); - TechniqueDef def = technique.getDef(); - ShaderGenerationInfo info = def.getShaderGenerationInfo(); - - String vertexSource = buildShader(def.getShaderNodes(), info, ShaderType.Vertex); - String fragmentSource = buildShader(def.getShaderNodes(), info, ShaderType.Fragment); + String techniqueName = techniqueDef.getName(); + ShaderGenerationInfo info = techniqueDef.getShaderGenerationInfo(); Shader shader = new Shader(); - shader.initialize(); - shader.addSource(Shader.ShaderType.Vertex, technique.getDef().getName() + ".vert", vertexSource, defines.getCompiled(), getLanguageAndVersion(ShaderType.Vertex)); - shader.addSource(Shader.ShaderType.Fragment, technique.getDef().getName() + ".frag", fragmentSource, defines.getCompiled(), getLanguageAndVersion(ShaderType.Fragment)); + for (ShaderType type : ShaderType.values()) { + String extension = type.getExtension(); + String language = getLanguageAndVersion(type); + String shaderSourceCode = buildShader(techniqueDef.getShaderNodes(), info, type); + + if (shaderSourceCode != null) { + String shaderSourceAssetName = techniqueName + "." + extension; + shader.addSource(type, shaderSourceAssetName, shaderSourceCode, definesSourceCode, language); + } + } - technique = null; + techniqueDef = null; return shader; } @@ -109,6 +114,14 @@ public abstract class ShaderGenerator { * @return the code of the generated vertex shader */ protected String buildShader(List shaderNodes, ShaderGenerationInfo info, ShaderType type) { + if (type == ShaderType.TessellationControl || + type == ShaderType.TessellationEvaluation || + type == ShaderType.Geometry) { + // TODO: Those are not supported. + // Too much code assumes that type is either Vertex or Fragment + return null; + } + indent = 0; StringBuilder sourceDeclaration = new StringBuilder(); diff --git a/jme3-core/src/main/java/com/jme3/shader/ShaderKey.java b/jme3-core/src/main/java/com/jme3/shader/ShaderKey.java deleted file mode 100644 index 23a187250..000000000 --- a/jme3-core/src/main/java/com/jme3/shader/ShaderKey.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2009-2012 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.shader; - -import com.jme3.asset.AssetKey; -import com.jme3.export.InputCapsule; -import com.jme3.export.JmeExporter; -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 { - - protected EnumMap shaderLanguage; - protected EnumMap shaderName; - protected DefineList defines; - protected int cachedHashedCode = 0; - protected boolean usesShaderNodes = false; - - public ShaderKey(){ - shaderLanguage=new EnumMap(Shader.ShaderType.class); - shaderName=new EnumMap(Shader.ShaderType.class); - } - - public ShaderKey(DefineList defines, EnumMap shaderLanguage,EnumMap shaderName){ - super(""); - this.name = reducePath(getShaderName(Shader.ShaderType.Vertex)); - this.shaderLanguage=new EnumMap(Shader.ShaderType.class); - this.shaderName=new EnumMap(Shader.ShaderType.class); - this.defines = defines; - for (Shader.ShaderType shaderType : shaderName.keySet()) { - this.shaderName.put(shaderType,shaderName.get(shaderType)); - this.shaderLanguage.put(shaderType,shaderLanguage.get(shaderType)); - } - } - - @Override - public ShaderKey clone() { - ShaderKey clone = (ShaderKey) super.clone(); - clone.cachedHashedCode = 0; - clone.defines = defines.clone(); - return clone; - } - - @Override - public String toString(){ - //todo: - return "V="+name+";"; - } - - private final String getShaderName(Shader.ShaderType type) { - if (shaderName == null) { - return ""; - } - String shName = shaderName.get(type); - return shName != null ? shName : ""; - } - - //todo: make equals and hashCode work - @Override - public boolean equals(Object obj) { - final ShaderKey other = (ShaderKey) obj; - if (name.equals(other.name) && getShaderName(Shader.ShaderType.Fragment).equals(other.getShaderName(Shader.ShaderType.Fragment))){ - if (defines != null && other.defines != null) { - return defines.equals(other.defines); - } else if (defines != null || other.defines != null) { - return false; - } else { - return true; - } - } - return false; - } - - @Override - public int hashCode() { - if (cachedHashedCode == 0) { - int hash = 7; - hash = 41 * hash + name.hashCode(); - hash = 41 * hash + getShaderName(Shader.ShaderType.Fragment).hashCode(); - hash = getShaderName(Shader.ShaderType.Geometry) == null ? hash : 41 * hash + getShaderName(Shader.ShaderType.Geometry).hashCode(); - hash = getShaderName(Shader.ShaderType.TessellationControl) == null ? hash : 41 * hash + getShaderName(Shader.ShaderType.TessellationControl).hashCode(); - hash = getShaderName(Shader.ShaderType.TessellationEvaluation) == null ? hash : 41 * hash + getShaderName(Shader.ShaderType.TessellationEvaluation).hashCode(); - hash = 41 * hash + (defines != null ? defines.hashCode() : 0); - cachedHashedCode = hash; - } - return cachedHashedCode; - } - - public DefineList getDefines() { - return defines; - } - - public String getVertName(){ - return getShaderName(Shader.ShaderType.Vertex); - } - - public String getFragName() { - return getShaderName(Shader.ShaderType.Fragment); - } - - /** - * @deprecated Use {@link #getVertexShaderLanguage() } instead. - */ - @Deprecated - public String getLanguage() { - return shaderLanguage.get(Shader.ShaderType.Vertex); - } - - public String getVertexShaderLanguage() { - return shaderLanguage.get(Shader.ShaderType.Vertex); - } - - public String getFragmentShaderLanguage() { - return shaderLanguage.get(Shader.ShaderType.Vertex); - } - - public boolean isUsesShaderNodes() { - return usesShaderNodes; - } - - public void setUsesShaderNodes(boolean usesShaderNodes) { - 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 getShaderName(shaderType); - } - - @Override - public void write(JmeExporter ex) throws IOException{ - super.write(ex); - OutputCapsule oc = ex.getCapsule(this); - oc.write(shaderName.get(Shader.ShaderType.Fragment), "fragment_name", null); - oc.write(shaderName.get(Shader.ShaderType.Geometry), "geometry_name", null); - oc.write(shaderName.get(Shader.ShaderType.TessellationControl), "tessControl_name", null); - oc.write(shaderName.get(Shader.ShaderType.TessellationEvaluation), "tessEval_name", null); - oc.write(shaderLanguage.get(Shader.ShaderType.Vertex), "language", null); - oc.write(shaderLanguage.get(Shader.ShaderType.Fragment), "frag_language", null); - oc.write(shaderLanguage.get(Shader.ShaderType.Geometry), "geom_language", null); - oc.write(shaderLanguage.get(Shader.ShaderType.TessellationControl), "tsctrl_language", null); - oc.write(shaderLanguage.get(Shader.ShaderType.TessellationEvaluation), "tseval_language", null); - - } - - @Override - public void read(JmeImporter im) throws IOException{ - super.read(im); - InputCapsule ic = im.getCapsule(this); - shaderName.put(Shader.ShaderType.Vertex,name); - shaderName.put(Shader.ShaderType.Fragment,ic.readString("fragment_name", null)); - shaderName.put(Shader.ShaderType.Geometry,ic.readString("geometry_name", null)); - shaderName.put(Shader.ShaderType.TessellationControl,ic.readString("tessControl_name", null)); - shaderName.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tessEval_name", null)); - shaderLanguage.put(Shader.ShaderType.Vertex,ic.readString("language", null)); - shaderLanguage.put(Shader.ShaderType.Fragment,ic.readString("frag_language", null)); - shaderLanguage.put(Shader.ShaderType.Geometry,ic.readString("geom_language", null)); - shaderLanguage.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrl_language", null)); - shaderLanguage.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tseval_language", null)); - } - -} diff --git a/jme3-core/src/main/java/com/jme3/shader/Uniform.java b/jme3-core/src/main/java/com/jme3/shader/Uniform.java index 5d5fd2fe3..7ed468528 100644 --- a/jme3-core/src/main/java/com/jme3/shader/Uniform.java +++ b/jme3-core/src/main/java/com/jme3/shader/Uniform.java @@ -70,6 +70,30 @@ public class Uniform extends ShaderVariable { */ protected boolean setByCurrentMaterial = false; + @Override + public int hashCode() { + int hash = 5; + hash = 31 * hash + (this.value != null ? this.value.hashCode() : 0); + hash = 31 * hash + (this.varType != null ? this.varType.hashCode() : 0); + hash = 31 * hash + (this.binding != null ? this.binding.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + final Uniform other = (Uniform) obj; + if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) { + return false; + } + return this.binding == other.binding && this.varType == other.varType; + } + @Override public String toString(){ StringBuilder sb = new StringBuilder(); @@ -102,6 +126,10 @@ public class Uniform extends ShaderVariable { public Object getValue(){ return value; } + + public FloatBuffer getMultiData() { + return multiData; + } public boolean isSetByCurrentMaterial() { return setByCurrentMaterial; @@ -111,21 +139,6 @@ public class Uniform extends ShaderVariable { setByCurrentMaterial = false; } - private static void setVector4(Vector4f vec, Object value) { - if (value instanceof ColorRGBA) { - ColorRGBA color = (ColorRGBA) value; - vec.set(color.r, color.g, color.b, color.a); - } else if (value instanceof Quaternion) { - Quaternion quat = (Quaternion) value; - vec.set(quat.getX(), quat.getY(), quat.getZ(), quat.getW()); - } else if (value instanceof Vector4f) { - Vector4f vec4 = (Vector4f) value; - vec.set(vec4); - } else{ - throw new IllegalArgumentException(); - } - } - public void clearValue(){ updateNeeded = true; @@ -182,27 +195,43 @@ public class Uniform extends ShaderVariable { } if (value == null) { - throw new NullPointerException(); + throw new IllegalArgumentException("for uniform " + name + ": value cannot be null"); } setByCurrentMaterial = true; switch (type){ case Matrix3: + if (value.equals(this.value)) { + return; + } Matrix3f m3 = (Matrix3f) value; if (multiData == null) { multiData = BufferUtils.createFloatBuffer(9); } m3.fillFloatBuffer(multiData, true); multiData.clear(); + if (this.value == null) { + this.value = new Matrix3f(m3); + } else { + ((Matrix3f)this.value).set(m3); + } break; case Matrix4: + if (value.equals(this.value)) { + return; + } Matrix4f m4 = (Matrix4f) value; if (multiData == null) { multiData = BufferUtils.createFloatBuffer(16); } m4.fillFloatBuffer(multiData, true); multiData.clear(); + if (this.value == null) { + this.value = new Matrix4f(m4); + } else { + ((Matrix4f)this.value).copy(m4); + } break; case IntArray: int[] ia = (int[]) value; @@ -283,11 +312,32 @@ public class Uniform extends ShaderVariable { } multiData.clear(); break; + case Vector4: + if (value.equals(this.value)) { + return; + } + if (value instanceof ColorRGBA) { + if (this.value == null) { + this.value = new ColorRGBA(); + } + ((ColorRGBA) this.value).set((ColorRGBA) value); + } else if (value instanceof Vector4f) { + if (this.value == null) { + this.value = new Vector4f(); + } + ((Vector4f) this.value).set((Vector4f) value); + } else { + if (this.value == null) { + this.value = new Quaternion(); + } + ((Quaternion) this.value).set((Quaternion) value); + } + break; // Only use check if equals optimization for primitive values case Int: case Float: case Boolean: - if (this.value != null && this.value.equals(value)) { + if (value.equals(this.value)) { return; } this.value = value; @@ -297,39 +347,38 @@ public class Uniform extends ShaderVariable { break; } - if (multiData != null) { - this.value = multiData; - } +// if (multiData != null) { +// this.value = multiData; +// } varType = type; updateNeeded = true; } public void setVector4Length(int length){ - if (location == -1) + if (location == -1) { return; - - FloatBuffer fb = (FloatBuffer) value; - if (fb == null || fb.capacity() < length * 4) { - value = BufferUtils.createFloatBuffer(length * 4); } - + + multiData = BufferUtils.ensureLargeEnough(multiData, length * 4); + value = multiData; varType = VarType.Vector4Array; updateNeeded = true; setByCurrentMaterial = true; } public void setVector4InArray(float x, float y, float z, float w, int index){ - if (location == -1) + if (location == -1) { return; + } - if (varType != null && varType != VarType.Vector4Array) - throw new IllegalArgumentException("Expected a "+varType.name()+" value!"); + if (varType != null && varType != VarType.Vector4Array) { + throw new IllegalArgumentException("Expected a " + varType.name() + " value!"); + } - FloatBuffer fb = (FloatBuffer) value; - fb.position(index * 4); - fb.put(x).put(y).put(z).put(w); - fb.rewind(); + multiData.position(index * 4); + multiData.put(x).put(y).put(z).put(w); + multiData.rewind(); updateNeeded = true; setByCurrentMaterial = true; } diff --git a/jme3-core/src/main/java/com/jme3/shader/UniformBindingManager.java b/jme3-core/src/main/java/com/jme3/shader/UniformBindingManager.java index af2df5a94..f9ead8979 100644 --- a/jme3-core/src/main/java/com/jme3/shader/UniformBindingManager.java +++ b/jme3-core/src/main/java/com/jme3/shader/UniformBindingManager.java @@ -36,7 +36,7 @@ import com.jme3.math.*; import com.jme3.renderer.Camera; import com.jme3.renderer.RenderManager; import com.jme3.system.Timer; -import java.util.List; +import java.util.ArrayList; /** * UniformBindingManager helps {@link RenderManager} to manage @@ -84,7 +84,8 @@ public class UniformBindingManager { * Updates the given list of uniforms with {@link UniformBinding uniform bindings} * based on the current world state. */ - public void updateUniformBindings(List params) { + public void updateUniformBindings(Shader shader) { + ArrayList params = shader.getBoundUniforms(); for (int i = 0; i < params.size(); i++) { Uniform u = params.get(i); switch (u.getBinding()) { diff --git a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java index b55c6b2d2..d1b4586b3 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java @@ -330,12 +330,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable public void initialize(RenderManager rm, ViewPort vp) { renderManager = rm; viewPort = vp; - //checking for caps to chosse the appropriate post material technique - if (renderManager.getRenderer().getCaps().contains(Caps.GLSL150)) { - postTechniqueName = "PostShadow15"; - } else { - postTechniqueName = "PostShadow"; - } + postTechniqueName = "PostShadow"; if(zFarOverride>0 && frustumCam == null){ initFrustumCam(); } @@ -587,7 +582,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable for (int i = 0; i < l.size(); i++) { Material mat = l.get(i).getMaterial(); //checking if the material has the post technique and adding it to the material cache - if (mat.getMaterialDef().getTechniqueDef(postTechniqueName) != null) { + if (mat.getMaterialDef().getTechniqueDefs(postTechniqueName) != null) { if (!matCache.contains(mat)) { matCache.add(mat); } diff --git a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java index e06b5c337..a4f06df41 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java @@ -355,12 +355,7 @@ public class PssmShadowRenderer implements SceneProcessor { public void initialize(RenderManager rm, ViewPort vp) { renderManager = rm; viewPort = vp; - //checking for caps to chosse the appropriate post material technique - if (renderManager.getRenderer().getCaps().contains(Caps.GLSL150)) { - postTechniqueName = "PostShadow15"; - } else { - postTechniqueName = "PostShadow"; - } + postTechniqueName = "PostShadow"; } public boolean isInitialized() { @@ -533,7 +528,7 @@ public class PssmShadowRenderer implements SceneProcessor { for (int i = 0; i < l.size(); i++) { Material mat = l.get(i).getMaterial(); //checking if the material has the post technique and adding it to the material cache - if (mat.getMaterialDef().getTechniqueDef(postTechniqueName) != null) { + if (mat.getMaterialDef().getTechniqueDefs(postTechniqueName) != null) { if (!matCache.contains(mat)) { matCache.add(mat); } diff --git a/jme3-core/src/main/java/com/jme3/system/NullContext.java b/jme3-core/src/main/java/com/jme3/system/NullContext.java index 41204e6c9..54ee59c42 100644 --- a/jme3-core/src/main/java/com/jme3/system/NullContext.java +++ b/jme3-core/src/main/java/com/jme3/system/NullContext.java @@ -128,12 +128,13 @@ public class NullContext implements JmeContext, Runnable { public void run(){ initInThread(); - while (!needClose.get()){ + do { listener.update(); - if (frameRate > 0) + if (frameRate > 0) { sync(frameRate); - } + } + } while (!needClose.get()); deinitInThread(); diff --git a/jme3-core/src/main/java/com/jme3/system/NullRenderer.java b/jme3-core/src/main/java/com/jme3/system/NullRenderer.java index f2e029af4..293c5e2c7 100644 --- a/jme3-core/src/main/java/com/jme3/system/NullRenderer.java +++ b/jme3-core/src/main/java/com/jme3/system/NullRenderer.java @@ -39,6 +39,7 @@ import com.jme3.material.RenderState; import com.jme3.math.ColorRGBA; import com.jme3.math.Matrix4f; import com.jme3.renderer.Caps; +import com.jme3.renderer.Limits; import com.jme3.renderer.Renderer; import com.jme3.renderer.Statistics; import com.jme3.scene.Mesh; @@ -48,15 +49,25 @@ import com.jme3.shader.Shader.ShaderSource; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture; +import java.util.EnumMap; public class NullRenderer implements Renderer { - private static final EnumSet caps = EnumSet.noneOf(Caps.class); - private static final Statistics stats = new Statistics(); + private final EnumSet caps = EnumSet.allOf(Caps.class); + private final EnumMap limits = new EnumMap<>(Limits.class); + private final Statistics stats = new Statistics(); public void initialize() { + for (Limits limit : Limits.values()) { + limits.put(limit, Integer.MAX_VALUE); + } } - + + @Override + public EnumMap getLimits() { + return limits; + } + public EnumSet getCaps() { return caps; } @@ -164,4 +175,7 @@ public class NullRenderer implements Renderer { public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { } + @Override + public void setDefaultAnisotropicFilter(int level) { + } } diff --git a/jme3-core/src/main/java/com/jme3/texture/image/LastTextureState.java b/jme3-core/src/main/java/com/jme3/texture/image/LastTextureState.java index 32c1b718b..4df767b0b 100644 --- a/jme3-core/src/main/java/com/jme3/texture/image/LastTextureState.java +++ b/jme3-core/src/main/java/com/jme3/texture/image/LastTextureState.java @@ -58,7 +58,7 @@ public final class LastTextureState { rWrap = null; magFilter = null; minFilter = null; - anisoFilter = 0; + anisoFilter = 1; // The default in OpenGL is OFF, so we avoid setting this per texture // if its not used. diff --git a/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java b/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java index 4b812006f..3cc2b5576 100644 --- a/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java +++ b/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java @@ -207,10 +207,10 @@ public class Cloner { // Check the index to see if we already have it Object clone = index.get(object); - if( clone != null ) { + if( clone != null || index.containsKey(object) ) { if( log.isLoggable(Level.FINER) ) { log.finer("cloned:" + object.getClass() + "@" + System.identityHashCode(object) - + " as cached:" + clone.getClass() + "@" + System.identityHashCode(clone)); + + " as cached:" + (clone == null ? "null" : (clone.getClass() + "@" + System.identityHashCode(clone)))); } return type.cast(clone); } diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md index a0f31aeb0..4d5c36046 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md @@ -114,10 +114,10 @@ MaterialDef Phong Lighting { //For instancing Boolean UseInstancing - Boolean BackfaceShadows: false + Boolean BackfaceShadows : false } - Technique { + Technique { LightMode SinglePass VertexShader GLSL100: Common/MatDefs/Light/SPLighting.vert @@ -149,7 +149,7 @@ MaterialDef Phong Lighting { SEPARATE_TEXCOORD : SeparateTexCoord DISCARD_ALPHA : AlphaDiscardThreshold USE_REFLECTION : EnvMap - SPHERE_MAP : SphereMap + SPHERE_MAP : EnvMapAsSphereMap NUM_BONES : NumberOfBones INSTANCING : UseInstancing } @@ -188,7 +188,7 @@ MaterialDef Phong Lighting { SEPARATE_TEXCOORD : SeparateTexCoord DISCARD_ALPHA : AlphaDiscardThreshold USE_REFLECTION : EnvMap - SPHERE_MAP : SphereMap + SPHERE_MAP : EnvMapAsSphereMap NUM_BONES : NumberOfBones INSTANCING : UseInstancing } @@ -209,7 +209,6 @@ MaterialDef Phong Lighting { } Defines { - COLOR_MAP : ColorMap DISCARD_ALPHA : AlphaDiscardThreshold NUM_BONES : NumberOfBones INSTANCING : UseInstancing @@ -218,7 +217,7 @@ MaterialDef Phong Lighting { } - Technique PostShadow15{ + Technique PostShadow { VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow.vert FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow.frag @@ -234,8 +233,7 @@ MaterialDef Phong Lighting { HARDWARE_SHADOWS : HardwareShadows FILTER_MODE : FilterMode PCFEDGE : PCFEdge - DISCARD_ALPHA : AlphaDiscardThreshold - COLOR_MAP : ColorMap + DISCARD_ALPHA : AlphaDiscardThreshold SHADOWMAP_SIZE : ShadowMapSize FADE : FadeInfo PSSM : Splits @@ -268,8 +266,7 @@ MaterialDef Phong Lighting { HARDWARE_SHADOWS : HardwareShadows FILTER_MODE : FilterMode PCFEDGE : PCFEdge - DISCARD_ALPHA : AlphaDiscardThreshold - COLOR_MAP : ColorMap + DISCARD_ALPHA : AlphaDiscardThreshold SHADOWMAP_SIZE : ShadowMapSize FADE : FadeInfo PSSM : Splits @@ -343,10 +340,6 @@ MaterialDef Phong Lighting { Defines { VERTEX_COLOR : UseVertexColor MATERIAL_COLORS : UseMaterialColors - V_TANGENT : VTangent - MINNAERT : Minnaert - WARDISO : WardIso - DIFFUSEMAP : DiffuseMap NORMALMAP : NormalMap SPECULARMAP : SpecularMap diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md b/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md index 68f07f98d..f02348a06 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md @@ -148,7 +148,7 @@ MaterialDef Unshaded { } - Technique PostShadow15{ + Technique PostShadow { VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow.vert FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow.frag @@ -181,7 +181,7 @@ MaterialDef Unshaded { } } - Technique PostShadow{ + Technique PostShadow { VertexShader GLSL100: Common/MatDefs/Shadow/PostShadow.vert FragmentShader GLSL100: Common/MatDefs/Shadow/PostShadow.frag diff --git a/jme3-core/src/main/resources/com/jme3/asset/General.cfg b/jme3-core/src/main/resources/com/jme3/asset/General.cfg index c56b62146..66ed68e49 100644 --- a/jme3-core/src/main/resources/com/jme3/asset/General.cfg +++ b/jme3-core/src/main/resources/com/jme3/asset/General.cfg @@ -22,5 +22,4 @@ LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, geom, tsctrl, tseval, glsl, glsllib -LOADER com.jme3.scene.plugins.fbx.SceneLoader : fbx -LOADER com.jme3.scene.plugins.fbx.SceneWithAnimationLoader : fba +LOADER com.jme3.scene.plugins.fbx.FbxLoader : fbx 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 402ce6d47..509642e4c 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 @@ -31,8 +31,12 @@ */ package com.jme3.material.plugins; +import com.jme3.material.logic.MultiPassLightingLogic; +import com.jme3.material.logic.SinglePassLightingLogic; +import com.jme3.material.logic.DefaultTechniqueDefLogic; import com.jme3.asset.*; import com.jme3.material.*; +import com.jme3.material.RenderState.BlendEquation; import com.jme3.material.RenderState.BlendMode; import com.jme3.material.RenderState.FaceCullMode; import com.jme3.material.TechniqueDef.LightMode; @@ -40,6 +44,7 @@ import com.jme3.material.TechniqueDef.ShadowMode; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; +import com.jme3.shader.DefineList; import com.jme3.shader.Shader; import com.jme3.shader.VarType; import com.jme3.texture.Texture; @@ -73,15 +78,16 @@ public class J3MLoader implements AssetLoader { private Material material; private TechniqueDef technique; private RenderState renderState; + private ArrayList presetDefines = new ArrayList(); - private EnumMap shaderLanguage; - private EnumMap shaderName; + private EnumMap shaderLanguages; + private EnumMap shaderNames; private static final String whitespacePattern = "\\p{javaWhitespace}+"; public J3MLoader() { - shaderLanguage = new EnumMap(Shader.ShaderType.class); - shaderName = new EnumMap(Shader.ShaderType.class); + shaderLanguages = new EnumMap<>(Shader.ShaderType.class); + shaderNames = new EnumMap<>(Shader.ShaderType.class); } @@ -104,8 +110,8 @@ public class J3MLoader implements AssetLoader { } private void readShaderDefinition(Shader.ShaderType shaderType, String name, String language) { - shaderName.put(shaderType, name); - shaderLanguage.put(shaderType, language); + shaderNames.put(shaderType, name); + shaderLanguages.put(shaderType, language); } // LightMode @@ -443,9 +449,12 @@ public class J3MLoader implements AssetLoader { renderState.setDepthTest(parseBoolean(split[1])); }else if (split[0].equals("Blend")){ renderState.setBlendMode(BlendMode.valueOf(split[1])); + }else if (split[0].equals("BlendEquation")){ + renderState.setBlendEquation(BlendEquation.valueOf(split[1])); + }else if (split[0].equals("BlendEquationAlpha")){ + renderState.setBlendEquationAlpha(RenderState.BlendEquationAlpha.valueOf(split[1])); }else if (split[0].equals("AlphaTestFalloff")){ - renderState.setAlphaTest(true); - renderState.setAlphaFallOff(Float.parseFloat(split[1])); + // Ignore for backwards compatbility }else if (split[0].equals("PolyOffset")){ float factor = Float.parseFloat(split[1]); float units = Float.parseFloat(split[2]); @@ -453,7 +462,7 @@ public class J3MLoader implements AssetLoader { }else if (split[0].equals("ColorWrite")){ renderState.setColorWrite(parseBoolean(split[1])); }else if (split[0].equals("PointSprite")){ - renderState.setPointSprite(parseBoolean(split[1])); + // Ignore for backwards compatbility }else if (split[0].equals("DepthFunc")){ renderState.setDepthFunc(RenderState.TestFunction.valueOf(split[1])); }else if (split[0].equals("AlphaFunc")){ @@ -495,10 +504,22 @@ public class J3MLoader implements AssetLoader { private void readDefine(String statement) throws IOException{ String[] split = statement.split(":"); if (split.length == 1){ - // add preset define - technique.addShaderPresetDefine(split[0].trim(), VarType.Boolean, true); + String defineName = split[0].trim(); + presetDefines.add(defineName); }else if (split.length == 2){ - technique.addShaderParamDefine(split[1].trim(), split[0].trim()); + String defineName = split[0].trim(); + String paramName = split[1].trim(); + MatParam param = materialDef.getMaterialParam(paramName); + if (param == null) { + logger.log(Level.WARNING, "In technique ''{0}'':\n" + + "Define ''{1}'' mapped to non-existent" + + " material parameter ''{2}'', ignoring.", + new Object[]{technique.getName(), defineName, paramName}); + return; + } + + VarType paramType = param.getVarType(); + technique.addShaderParamDefine(paramName, paramType, defineName); }else{ throw new IOException("Define syntax incorrect"); } @@ -560,37 +581,80 @@ public class J3MLoader implements AssetLoader { } material.setTransparent(parseBoolean(split[1])); } + + private static String createShaderPrologue(List presetDefines) { + DefineList dl = new DefineList(presetDefines.size()); + for (int i = 0; i < presetDefines.size(); i++) { + dl.set(i, 1); + } + StringBuilder sb = new StringBuilder(); + dl.generateSource(sb, presetDefines, null); + return sb.toString(); + } private void readTechnique(Statement techStat) throws IOException{ isUseNodes = false; String[] split = techStat.getLine().split(whitespacePattern); + + String name; if (split.length == 1) { - technique = new TechniqueDef(null); + name = TechniqueDef.DEFAULT_TECHNIQUE_NAME; } else if (split.length == 2) { - String techName = split[1]; - technique = new TechniqueDef(techName); + name = split[1]; } else { throw new IOException("Technique statement syntax incorrect"); } + String techniqueUniqueName = materialDef.getAssetName() + "@" + name; + technique = new TechniqueDef(name, techniqueUniqueName.hashCode()); + for (Statement statement : techStat.getContents()){ readTechniqueStatement(statement); } if(isUseNodes){ nodesLoaderDelegate.computeConditions(); + //used for caching later, the shader here is not a file. + + // KIRILL 9/19/2015 + // Not sure if this is needed anymore, since shader caching + // is now done by TechniqueDef. technique.setShaderFile(technique.hashCode() + "", technique.hashCode() + "", "GLSL100", "GLSL100"); - } - - if (shaderName.containsKey(Shader.ShaderType.Vertex) && shaderName.containsKey(Shader.ShaderType.Fragment)) { - technique.setShaderFile(shaderName, shaderLanguage); + }else if (shaderNames.containsKey(Shader.ShaderType.Vertex) && shaderNames.containsKey(Shader.ShaderType.Fragment)) { + technique.setShaderFile(shaderNames, shaderLanguages); + } else { + technique = null; + shaderLanguages.clear(); + shaderNames.clear(); + presetDefines.clear(); + logger.log(Level.WARNING, "Fixed function technique was ignored"); + logger.log(Level.WARNING, "Fixed function technique ''{0}'' was ignored for material {1}", + new Object[]{name, key}); + return; + } + + technique.setShaderPrologue(createShaderPrologue(presetDefines)); + + switch (technique.getLightMode()) { + case Disable: + technique.setLogic(new DefaultTechniqueDefLogic(technique)); + break; + case MultiPass: + technique.setLogic(new MultiPassLightingLogic(technique)); + break; + case SinglePass: + technique.setLogic(new SinglePassLightingLogic(technique)); + break; + default: + throw new UnsupportedOperationException(); } materialDef.addTechniqueDef(technique); technique = null; - shaderLanguage.clear(); - shaderName.clear(); + shaderLanguages.clear(); + shaderNames.clear(); + presetDefines.clear(); } private void loadFromRoot(List roots) throws IOException{ @@ -711,7 +775,7 @@ public class J3MLoader implements AssetLoader { protected void initNodesLoader() { if (!isUseNodes) { - isUseNodes = shaderName.get(Shader.ShaderType.Vertex) == null && shaderName.get(Shader.ShaderType.Fragment) == null; + isUseNodes = shaderNames.get(Shader.ShaderType.Vertex) == null && shaderNames.get(Shader.ShaderType.Fragment) == null; if (isUseNodes) { if (nodesLoaderDelegate == null) { nodesLoaderDelegate = new ShaderNodeLoaderDelegate(); diff --git a/jme3-core/src/plugins/java/com/jme3/material/plugins/ShaderNodeLoaderDelegate.java b/jme3-core/src/plugins/java/com/jme3/material/plugins/ShaderNodeLoaderDelegate.java index 7cc902f95..efdf28f4b 100644 --- a/jme3-core/src/plugins/java/com/jme3/material/plugins/ShaderNodeLoaderDelegate.java +++ b/jme3-core/src/plugins/java/com/jme3/material/plugins/ShaderNodeLoaderDelegate.java @@ -44,6 +44,7 @@ import com.jme3.shader.ShaderNodeDefinition; import com.jme3.shader.ShaderNodeVariable; import com.jme3.shader.ShaderUtils; import com.jme3.shader.UniformBinding; +import com.jme3.shader.VarType; import com.jme3.shader.VariableMapping; import com.jme3.util.blockparser.Statement; import java.io.IOException; @@ -583,7 +584,7 @@ public class ShaderNodeLoaderDelegate { //multiplicity is not an int attempting to find for a material parameter. MatParam mp = findMatParam(multiplicity); if (mp != null) { - addDefine(multiplicity); + addDefine(multiplicity, VarType.Int); multiplicity = multiplicity.toUpperCase(); } else { throw new MatParseException("Wrong multiplicity for variable" + mapping.getLeftVariable().getName() + ". " + multiplicity + " should be an int or a declared material parameter.", statement); @@ -625,9 +626,9 @@ public class ShaderNodeLoaderDelegate { * * @param paramName */ - public void addDefine(String paramName) { + public void addDefine(String paramName, VarType paramType) { if (techniqueDef.getShaderParamDefine(paramName) == null) { - techniqueDef.addShaderParamDefine(paramName, paramName.toUpperCase()); + techniqueDef.addShaderParamDefine(paramName, paramType, paramName.toUpperCase()); } } @@ -660,7 +661,7 @@ public class ShaderNodeLoaderDelegate { for (String string : defines) { MatParam param = findMatParam(string); if (param != null) { - addDefine(param.getName()); + addDefine(param.getName(), param.getVarType()); } else { throw new MatParseException("Invalid condition, condition must match a Material Parameter named " + cond, statement); } diff --git a/jme3-core/src/plugins/java/com/jme3/scene/plugins/MTLLoader.java b/jme3-core/src/plugins/java/com/jme3/scene/plugins/MTLLoader.java index f09eae150..cdc3655d6 100644 --- a/jme3-core/src/plugins/java/com/jme3/scene/plugins/MTLLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/scene/plugins/MTLLoader.java @@ -149,8 +149,7 @@ public class MTLLoader implements AssetLoader { if (transparent){ material.setTransparent(true); material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); - material.getAdditionalRenderState().setAlphaTest(true); - material.getAdditionalRenderState().setAlphaFallOff(0.01f); + material.setFloat("AlphaDiscardThreshold", 0.01f); } matList.put(matName, material); diff --git a/jme3-core/src/main/java/com/jme3/animation/BoneAnimation.java b/jme3-core/src/test/java/com/jme3/asset/LoadShaderSourceTest.java similarity index 67% rename from jme3-core/src/main/java/com/jme3/animation/BoneAnimation.java rename to jme3-core/src/test/java/com/jme3/asset/LoadShaderSourceTest.java index 735ee05a5..4e9999b20 100644 --- a/jme3-core/src/main/java/com/jme3/animation/BoneAnimation.java +++ b/jme3-core/src/test/java/com/jme3/asset/LoadShaderSourceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2012 jMonkeyEngine + * Copyright (c) 2009-2015 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,16 +29,24 @@ * 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.animation; +package com.jme3.asset; -/** - * @deprecated use Animation instead with tracks of selected type (ie. BoneTrack, SpatialTrack, MeshTrack) - */ -@Deprecated -public final class BoneAnimation extends Animation { +import com.jme3.asset.plugins.ClasspathLocator; +import com.jme3.shader.plugins.GLSLLoader; +import com.jme3.system.JmeSystem; +import com.jme3.system.MockJmeSystemDelegate; +import org.junit.Test; + +public class LoadShaderSourceTest { - @Deprecated - public BoneAnimation(String name, float length) { - super(name, length); + @Test + public void testLoadShaderSource() { + JmeSystem.setSystemDelegate(new MockJmeSystemDelegate()); + AssetManager assetManager = new DesktopAssetManager(); + assetManager.registerLocator(null, ClasspathLocator.class); + assetManager.registerLoader(GLSLLoader.class, "frag"); + String showNormals = (String) assetManager.loadAsset("Common/MatDefs/Misc/ShowNormals.frag"); + System.out.println(showNormals); } + } diff --git a/jme3-core/src/test/java/com/jme3/material/MaterialMatParamOverrideTest.java b/jme3-core/src/test/java/com/jme3/material/MaterialMatParamOverrideTest.java new file mode 100644 index 000000000..defd850ba --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/material/MaterialMatParamOverrideTest.java @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2009-2016 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.asset.AssetManager; +import com.jme3.light.LightList; +import com.jme3.math.Matrix4f; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.shader.Shader; +import com.jme3.shader.Uniform; +import com.jme3.shader.VarType; +import java.util.Arrays; +import java.util.HashSet; +import org.junit.Assert; +import org.junit.Test; + +import static com.jme3.scene.MPOTestUtils.*; +import com.jme3.scene.Node; +import com.jme3.shader.DefineList; +import com.jme3.system.NullRenderer; +import com.jme3.system.TestUtil; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import org.junit.Before; + +/** + * Validates how {@link MatParamOverride MPOs} work on the material level. + * + * @author Kirill Vainer + */ +public class MaterialMatParamOverrideTest { + + private static final HashSet IGNORED_UNIFORMS = new HashSet( + Arrays.asList(new String[]{"m_ParallaxHeight", "m_Shininess", "m_BackfaceShadows"})); + + @Test + public void testBoolMpoOnly() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMpo(mpoBool("UseMaterialColors", true)); + outDefines(def("MATERIAL_COLORS", VarType.Boolean, true)); + outUniforms(uniform("UseMaterialColors", VarType.Boolean, true)); + } + + @Test + public void testBoolMpOnly() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMp(mpoBool("UseMaterialColors", true)); + outDefines(def("MATERIAL_COLORS", VarType.Boolean, true)); + outUniforms(uniform("UseMaterialColors", VarType.Boolean, true)); + } + + @Test + public void testBoolOverrideFalse() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMp(mpoBool("UseMaterialColors", true)); + inputMpo(mpoBool("UseMaterialColors", false)); + outDefines(); + outUniforms(uniform("UseMaterialColors", VarType.Boolean, false)); + } + + @Test + public void testBoolOverrideTrue() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMp(mpoBool("UseMaterialColors", false)); + inputMpo(mpoBool("UseMaterialColors", true)); + outDefines(def("MATERIAL_COLORS", VarType.Boolean, true)); + outUniforms(uniform("UseMaterialColors", VarType.Boolean, true)); + } + + @Test + public void testFloatMpoOnly() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMpo(mpoFloat("AlphaDiscardThreshold", 3.12f)); + outDefines(def("DISCARD_ALPHA", VarType.Float, 3.12f)); + outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 3.12f)); + } + + @Test + public void testFloatMpOnly() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMp(mpoFloat("AlphaDiscardThreshold", 3.12f)); + outDefines(def("DISCARD_ALPHA", VarType.Float, 3.12f)); + outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 3.12f)); + } + + @Test + public void testFloatOverride() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMp(mpoFloat("AlphaDiscardThreshold", 3.12f)); + inputMpo(mpoFloat("AlphaDiscardThreshold", 2.79f)); + outDefines(def("DISCARD_ALPHA", VarType.Float, 2.79f)); + outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 2.79f)); + } + + @Test + public void testForcedOverride() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMp(mpoFloat("AlphaDiscardThreshold", 3.12f)); + inputMpo(mpoFloat("AlphaDiscardThreshold", 2.79f)); + inputFpo(mpoFloat("AlphaDiscardThreshold", 1.23f)); + outDefines(def("DISCARD_ALPHA", VarType.Float, 1.23f)); + outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 1.23f)); + + reset(); + root.clearMatParamOverrides(); + root.updateGeometricState(); + outDefines(def("DISCARD_ALPHA", VarType.Float, 2.79f)); + outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 2.79f)); + } + + @Test + public void testChildOverridesParent() { + material("Common/MatDefs/Light/Lighting.j3md"); + + inputParentMpo(mpoFloat("AlphaDiscardThreshold", 3.12f)); + inputMpo(mpoFloat("AlphaDiscardThreshold", 2.79f)); + + outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 2.79f)); + outDefines(def("DISCARD_ALPHA", VarType.Float, 2.79f)); + } + + @Test + public void testMpoDisable() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMp(mpoFloat("AlphaDiscardThreshold", 3.12f)); + + MatParamOverride override = mpoFloat("AlphaDiscardThreshold", 2.79f); + inputMpo(override); + outDefines(def("DISCARD_ALPHA", VarType.Float, 2.79f)); + outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 2.79f)); + + reset(); + override.setEnabled(false); + outDefines(def("DISCARD_ALPHA", VarType.Float, 3.12f)); + outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 3.12f)); + + reset(); + override.setEnabled(true); + outDefines(def("DISCARD_ALPHA", VarType.Float, 2.79f)); + outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 2.79f)); + } + + @Test + public void testIntMpoOnly() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMpo(mpoInt("NumberOfBones", 1234)); + outDefines(def("NUM_BONES", VarType.Int, 1234)); + outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); + } + + @Test + public void testIntMpOnly() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMp(mpoInt("NumberOfBones", 1234)); + outDefines(def("NUM_BONES", VarType.Int, 1234)); + outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); + } + + @Test + public void testIntOverride() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMp(mpoInt("NumberOfBones", 1234)); + inputMpo(mpoInt("NumberOfBones", 4321)); + outDefines(def("NUM_BONES", VarType.Int, 4321)); + outUniforms(uniform("NumberOfBones", VarType.Int, 4321)); + } + + @Test + public void testMatrixArray() { + Matrix4f[] matrices = new Matrix4f[]{ + new Matrix4f() + }; + + material("Common/MatDefs/Light/Lighting.j3md"); + inputMpo(mpoMatrix4Array("BoneMatrices", matrices)); + outDefines(); + outUniforms(uniform("BoneMatrices", VarType.Matrix4Array, matrices)); + } + + @Test + public void testNonExistentParameter() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMpo(mpoInt("NonExistent", 4321)); + outDefines(); + outUniforms(); + } + + @Test + public void testWrongType() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMpo(mpoInt("UseMaterialColors", 4321)); + outDefines(); + outUniforms(); + } + + @Test + public void testParamOnly() { + material("Common/MatDefs/Light/Lighting.j3md"); + inputMpo(mpoFloat("ShadowMapSize", 3.12f)); + outDefines(); + outUniforms(uniform("ShadowMapSize", VarType.Float, 3.12f)); + } + + @Test + public void testRemove() { + material("Common/MatDefs/Light/Lighting.j3md"); + + reset(); + inputMp(mpoInt("NumberOfBones", 1234)); + outDefines(def("NUM_BONES", VarType.Int, 1234)); + outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); + + reset(); + inputMpo(mpoInt("NumberOfBones", 4321)); + outDefines(def("NUM_BONES", VarType.Int, 4321)); + outUniforms(uniform("NumberOfBones", VarType.Int, 4321)); + + reset(); + geometry.clearMatParamOverrides(); + root.updateGeometricState(); + outDefines(def("NUM_BONES", VarType.Int, 1234)); + outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); + + reset(); + geometry.getMaterial().clearParam("NumberOfBones"); + outDefines(); + outUniforms(); + + reset(); + inputMpo(mpoInt("NumberOfBones", 4321)); + outDefines(def("NUM_BONES", VarType.Int, 4321)); + outUniforms(uniform("NumberOfBones", VarType.Int, 4321)); + + reset(); + inputMp(mpoInt("NumberOfBones", 1234)); + outDefines(def("NUM_BONES", VarType.Int, 4321)); + outUniforms(uniform("NumberOfBones", VarType.Int, 4321)); + } + + public void testRemoveOverride() { + material("Common/MatDefs/Light/Lighting.j3md"); + + reset(); + inputMp(mpoInt("NumberOfBones", 1234)); + outDefines(def("NUM_BONES", VarType.Int, 1234)); + outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); + + reset(); + inputMpo(mpoInt("NumberOfBones", 4321)); + outDefines(def("NUM_BONES", VarType.Int, 4321)); + outUniforms(uniform("NumberOfBones", VarType.Int, 4321)); + + reset(); + geometry.clearMatParamOverrides(); + outDefines(def("NUM_BONES", VarType.Int, 1234)); + outUniforms(uniform("NumberOfBones", VarType.Int, 1234)); + } + + @Test + public void testRemoveMpoOnly() { + material("Common/MatDefs/Light/Lighting.j3md"); + + reset(); + inputMpo(mpoInt("NumberOfBones", 4321)); + outDefines(def("NUM_BONES", VarType.Int, 4321)); + outUniforms(uniform("NumberOfBones", VarType.Int, 4321)); + + reset(); + geometry.clearMatParamOverrides(); + root.updateGeometricState(); + outDefines(); + outUniforms(); + } + + @Test + public void testTextureMpoOnly() { + material("Common/MatDefs/Light/Lighting.j3md"); + Texture2D tex = new Texture2D(128, 128, Format.RGBA8); + + inputMpo(mpoTexture2D("DiffuseMap", tex)); + outDefines(def("DIFFUSEMAP", VarType.Texture2D, tex)); + outUniforms(uniform("DiffuseMap", VarType.Int, 0)); + outTextures(tex); + } + + @Test + public void testTextureOverride() { + material("Common/MatDefs/Light/Lighting.j3md"); + Texture2D tex1 = new Texture2D(128, 128, Format.RGBA8); + Texture2D tex2 = new Texture2D(128, 128, Format.RGBA8); + + inputMp(mpoTexture2D("DiffuseMap", tex1)); + inputMpo(mpoTexture2D("DiffuseMap", tex2)); + + outDefines(def("DIFFUSEMAP", VarType.Texture2D, tex2)); + outUniforms(uniform("DiffuseMap", VarType.Int, 0)); + outTextures(tex2); + } + + @Test + public void testRemoveTexture() { + material("Common/MatDefs/Light/Lighting.j3md"); + Texture2D tex = new Texture2D(128, 128, Format.RGBA8); + + reset(); + inputMpo(mpoTexture2D("DiffuseMap", tex)); + outDefines(def("DIFFUSEMAP", VarType.Texture2D, tex)); + outUniforms(uniform("DiffuseMap", VarType.Int, 0)); + outTextures(tex); + + reset(); + geometry.clearMatParamOverrides(); + root.updateGeometricState(); + outDefines(); + outUniforms(); + outTextures(); + } + + @Test + public void testRemoveTextureOverride() { + material("Common/MatDefs/Light/Lighting.j3md"); + Texture2D tex1 = new Texture2D(128, 128, Format.RGBA8); + Texture2D tex2 = new Texture2D(128, 128, Format.RGBA8); + + reset(); + inputMp(mpoTexture2D("DiffuseMap", tex1)); + outDefines(def("DIFFUSEMAP", VarType.Texture2D, tex1)); + outUniforms(uniform("DiffuseMap", VarType.Int, 0)); + outTextures(tex1); + + reset(); + inputMpo(mpoTexture2D("DiffuseMap", tex2)); + outDefines(def("DIFFUSEMAP", VarType.Texture2D, tex2)); + outUniforms(uniform("DiffuseMap", VarType.Int, 0)); + outTextures(tex2); + + reset(); + geometry.clearMatParamOverrides(); + root.updateGeometricState(); + outDefines(def("DIFFUSEMAP", VarType.Texture2D, tex1)); + outUniforms(uniform("DiffuseMap", VarType.Int, 0)); + outTextures(tex1); + } + + private static final class Define { + + public String name; + public VarType type; + public Object value; + + @Override + public int hashCode() { + int hash = 3; + hash = 89 * hash + this.name.hashCode(); + hash = 89 * hash + this.type.hashCode(); + hash = 89 * hash + this.value.hashCode(); + return hash; + } + + @Override + public boolean equals(Object obj) { + final Define other = (Define) obj; + return this.name.equals(other.name) && this.type.equals(other.type) && this.value.equals(other.value); + } + } + + private final Geometry geometry = new Geometry("Geometry", new Box(1, 1, 1)); + private final Node root = new Node("Root Node"); + private final LightList lightList = new LightList(geometry); + + @Before + public void setUp() { + root.attachChild(geometry); + } + + private final NullRenderer renderer = new NullRenderer() { + @Override + public void setShader(Shader shader) { + MaterialMatParamOverrideTest.this.usedShader = shader; + evaluated = true; + } + + @Override + public void setTexture(int unit, Texture texture) { + MaterialMatParamOverrideTest.this.usedTextures[unit] = texture; + } + }; + private final RenderManager renderManager = new RenderManager(renderer); + + private boolean evaluated = false; + private Shader usedShader = null; + private final Texture[] usedTextures = new Texture[32]; + + private void inputMp(MatParam... params) { + if (evaluated) { + throw new IllegalStateException(); + } + Material mat = geometry.getMaterial(); + for (MatParam param : params) { + mat.setParam(param.getName(), param.getVarType(), param.getValue()); + } + } + + private void inputMpo(MatParamOverride... overrides) { + if (evaluated) { + throw new IllegalStateException(); + } + for (MatParamOverride override : overrides) { + geometry.addMatParamOverride(override); + } + root.updateGeometricState(); + } + + private void inputParentMpo(MatParamOverride... overrides) { + if (evaluated) { + throw new IllegalStateException(); + } + for (MatParamOverride override : overrides) { + root.addMatParamOverride(override); + } + root.updateGeometricState(); + } + + private void inputFpo(MatParamOverride... overrides) { + if (evaluated) { + throw new IllegalStateException(); + } + for (MatParamOverride override : overrides) { + renderManager.addForcedMatParam(override); + } + } + + private void reset() { + evaluated = false; + usedShader = null; + Arrays.fill(usedTextures, null); + for (MatParamOverride override : new ArrayList<>(renderManager.getForcedMatParams())) { + renderManager.removeForcedMatParam(override); + } + } + + private Define def(String name, VarType type, Object value) { + Define d = new Define(); + d.name = name; + d.type = type; + d.value = value; + return d; + } + + private Uniform uniform(String name, VarType type, Object value) { + Uniform u = new Uniform(); + u.setName("m_" + name); + u.setValue(type, value); + return u; + } + + private void material(String path) { + AssetManager assetManager = TestUtil.createAssetManager(); + geometry.setMaterial(new Material(assetManager, path)); + } + + private void evaluateTechniqueDef() { + Assert.assertFalse(evaluated); + Material mat = geometry.getMaterial(); + mat.render(geometry, lightList, renderManager); + Assert.assertTrue(evaluated); + } + + private void outTextures(Texture... textures) { + for (int i = 0; i < usedTextures.length; i++) { + if (i < textures.length) { + Assert.assertSame(textures[i], usedTextures[i]); + } else { + Assert.assertNull(usedTextures[i]); + } + } + } + + private void outDefines(Define... expectedDefinesArray) { + Map nameToDefineMap = new HashMap(); + for (Define define : expectedDefinesArray) { + nameToDefineMap.put(define.name, define); + } + + if (!evaluated) { + evaluateTechniqueDef(); + } + + Material mat = geometry.getMaterial(); + Technique tech = mat.getActiveTechnique(); + TechniqueDef def = tech.getDef(); + DefineList actualDefines = tech.getDynamicDefines(); + + String[] defineNames = def.getDefineNames(); + VarType[] defineTypes = def.getDefineTypes(); + + Assert.assertEquals(defineNames.length, defineTypes.length); + + for (int index = 0; index < defineNames.length; index++) { + String name = defineNames[index]; + VarType type = defineTypes[index]; + Define expectedDefine = nameToDefineMap.remove(name); + Object expectedValue = null; + + if (expectedDefine != null) { + Assert.assertEquals(expectedDefine.type, type); + expectedValue = expectedDefine.value; + } + + switch (type) { + case Boolean: + if (expectedValue != null) { + Assert.assertEquals((boolean) (Boolean) expectedValue, actualDefines.getBoolean(index)); + } else { + Assert.assertEquals(false, actualDefines.getBoolean(index)); + } + break; + case Int: + if (expectedValue != null) { + Assert.assertEquals((int) (Integer) expectedValue, actualDefines.getInt(index)); + } else { + Assert.assertEquals(0, actualDefines.getInt(index)); + } + break; + case Float: + if (expectedValue != null) { + Assert.assertEquals((float) (Float) expectedValue, actualDefines.getFloat(index), 0f); + } else { + Assert.assertEquals(0f, actualDefines.getFloat(index), 0f); + } + break; + default: + if (expectedValue != null) { + Assert.assertEquals(1, actualDefines.getInt(index)); + } else { + Assert.assertEquals(0, actualDefines.getInt(index)); + } + break; + } + } + + Assert.assertTrue(nameToDefineMap.isEmpty()); + } + + private void outUniforms(Uniform... uniforms) { + if (!evaluated) { + evaluateTechniqueDef(); + } + + HashSet actualUniforms = new HashSet<>(); + + for (Uniform uniform : usedShader.getUniformMap().values()) { + if (uniform.getName().startsWith("m_") + && !IGNORED_UNIFORMS.contains(uniform.getName())) { + actualUniforms.add(uniform); + } + } + + HashSet expectedUniforms = new HashSet<>(Arrays.asList(uniforms)); + + if (!expectedUniforms.equals(actualUniforms)) { + Assert.fail("Uniform lists must match: " + expectedUniforms + " != " + actualUniforms); + } + } +} diff --git a/jme3-core/src/test/java/com/jme3/material/MaterialTest.java b/jme3-core/src/test/java/com/jme3/material/MaterialTest.java new file mode 100644 index 000000000..e186f5e65 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/material/MaterialTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2009-2016 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.asset.AssetManager; +import com.jme3.light.LightList; +import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.system.NullRenderer; +import com.jme3.system.TestUtil; +import java.util.Arrays; +import java.util.EnumSet; +import static org.junit.Assert.*; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class MaterialTest { + + private Material material; + private final Geometry geometry = new Geometry("Geometry", new Box(1, 1, 1)); + private final EnumSet myCaps = EnumSet.noneOf(Caps.class); + private final RenderManager renderManager = new RenderManager(new NullRenderer() { + @Override + public EnumSet getCaps() { + return MaterialTest.this.myCaps; + } + }); + + @Test(expected = IllegalArgumentException.class) + public void testSelectNonExistentTechnique() { + material("Common/MatDefs/Gui/Gui.j3md"); + material.selectTechnique("Doesn't Exist", renderManager); + } + + @Test(expected = UnsupportedOperationException.class) + public void testSelectDefaultTechnique_NoCaps() { + material("Common/MatDefs/Gui/Gui.j3md"); + material.selectTechnique("Default", renderManager); + } + + @Test + public void testSelectDefaultTechnique_GLSL100Cap() { + supportGlsl(100); + material("Common/MatDefs/Gui/Gui.j3md"); + + material.selectTechnique("Default", renderManager); + + checkRequiredCaps(Caps.GLSL100); + } + + @Test + public void testSelectDefaultTechnique_GLSL150Cap() { + supportGlsl(150); + material("Common/MatDefs/Gui/Gui.j3md"); + + material.selectTechnique("Default", renderManager); + + checkRequiredCaps(Caps.GLSL150); + } + + @Test + public void testSelectDefaultTechnique_GLSL120Cap_MultipleLangs() { + supportGlsl(120); + material("Common/MatDefs/Misc/Particle.j3md"); + + material.selectTechnique("Default", renderManager); + + checkRequiredCaps(Caps.GLSL100, Caps.GLSL120); + } + + @Test + public void testSelectDefaultTechnique_GLSL100Cap_MultipleLangs() { + supportGlsl(100); + material("Common/MatDefs/Misc/Particle.j3md"); + + material.selectTechnique("Default", renderManager); + + checkRequiredCaps(Caps.GLSL100); + } + + @Test + public void testSelectNamedTechnique_GLSL150Cap() { + supportGlsl(150); + material("Common/MatDefs/Light/Lighting.j3md"); + + material.selectTechnique("PostShadow", renderManager); + + checkRequiredCaps(Caps.GLSL150); + } + + @Test + public void testSelectNamedTechnique_GLSL100Cap() { + supportGlsl(100); + material("Common/MatDefs/Light/Lighting.j3md"); + + material.selectTechnique("PostShadow", renderManager); + + checkRequiredCaps(Caps.GLSL100); + } + + private void checkRequiredCaps(Caps... caps) { + EnumSet expected = EnumSet.noneOf(Caps.class); + expected.addAll(Arrays.asList(caps)); + + Technique tech = material.getActiveTechnique(); + + assertEquals(expected, tech.getDef().getRequiredCaps()); + } + + private void supportGlsl(int version) { + switch (version) { + case 150: + myCaps.add(Caps.GLSL150); + case 140: + myCaps.add(Caps.GLSL140); + case 130: + myCaps.add(Caps.GLSL130); + case 120: + myCaps.add(Caps.GLSL120); + case 110: + myCaps.add(Caps.GLSL110); + case 100: + myCaps.add(Caps.GLSL100); + break; + } + } + + private void caps(Caps... caps) { + myCaps.addAll(Arrays.asList(caps)); + } + + private void material(String path) { + AssetManager assetManager = TestUtil.createAssetManager(); + material = new Material(assetManager, path); + geometry.setMaterial(material); + } + +} diff --git a/jme3-core/src/test/java/com/jme3/material/plugins/J3MLoaderTest.java b/jme3-core/src/test/java/com/jme3/material/plugins/J3MLoaderTest.java index f45eb9bdf..b60e82c64 100644 --- a/jme3-core/src/test/java/com/jme3/material/plugins/J3MLoaderTest.java +++ b/jme3-core/src/test/java/com/jme3/material/plugins/J3MLoaderTest.java @@ -7,8 +7,11 @@ import com.jme3.asset.TextureKey; import com.jme3.material.MatParamTexture; import com.jme3.material.Material; import com.jme3.material.MaterialDef; +import com.jme3.renderer.Caps; import com.jme3.shader.VarType; import com.jme3.texture.Texture; +import java.io.IOException; +import java.util.EnumSet; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -18,6 +21,7 @@ import org.mockito.runners.MockitoJUnitRunner; import static org.mockito.Matchers.any; import static org.mockito.Mockito.verify; +import static org.junit.Assert.*; import static org.mockito.Mockito.when; /** @@ -51,6 +55,30 @@ public class J3MLoaderTest { j3MLoader = new J3MLoader(); } + @Test + public void noDefaultTechnique_shouldBeSupported() throws IOException { + when(assetInfo.openStream()).thenReturn(J3MLoader.class.getResourceAsStream("/no-default-technique.j3md")); + MaterialDef def = (MaterialDef) j3MLoader.load(assetInfo); + assertEquals(1, def.getTechniqueDefs("Test").size()); + } + + @Test + public void fixedPipelineTechnique_shouldBeIgnored() throws IOException { + when(assetInfo.openStream()).thenReturn(J3MLoader.class.getResourceAsStream("/no-shader-specified.j3md")); + MaterialDef def = (MaterialDef) j3MLoader.load(assetInfo); + assertEquals(null, def.getTechniqueDefs("A")); + assertEquals(1, def.getTechniqueDefs("B").size()); + } + + @Test + public void multipleSameNamedTechniques_shouldBeSupported() throws IOException { + when(assetInfo.openStream()).thenReturn(J3MLoader.class.getResourceAsStream("/same-name-technique.j3md")); + MaterialDef def = (MaterialDef) j3MLoader.load(assetInfo); + assertEquals(2, def.getTechniqueDefs("Test").size()); + assertEquals(EnumSet.of(Caps.GLSL150), def.getTechniqueDefs("Test").get(0).getRequiredCaps()); + assertEquals(EnumSet.of(Caps.GLSL100), def.getTechniqueDefs("Test").get(1).getRequiredCaps()); + } + @Test public void oldStyleTextureParameters_shouldBeSupported() throws Exception { when(assetInfo.openStream()).thenReturn(J3MLoader.class.getResourceAsStream("/texture-parameters-oldstyle.j3m")); @@ -107,7 +135,7 @@ public class J3MLoaderTest { } private TextureKey setupMockForTexture(final String paramName, final String path, final boolean flipY, final Texture texture) { - when(materialDef.getMaterialParam(paramName)).thenReturn(new MatParamTexture(VarType.Texture2D, paramName, texture, 0, null)); + when(materialDef.getMaterialParam(paramName)).thenReturn(new MatParamTexture(VarType.Texture2D, paramName, texture, null)); final TextureKey textureKey = new TextureKey(path, flipY); textureKey.setGenerateMips(true); diff --git a/jme3-core/src/test/java/com/jme3/material/plugins/LoadJ3mdTest.java b/jme3-core/src/test/java/com/jme3/material/plugins/LoadJ3mdTest.java new file mode 100644 index 000000000..ea47129a7 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/material/plugins/LoadJ3mdTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2009-2016 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.plugins; + +import com.jme3.asset.AssetManager; +import com.jme3.material.*; +import com.jme3.renderer.*; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.shader.Shader; +import com.jme3.system.*; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +@RunWith(MockitoJUnitRunner.class) +public class LoadJ3mdTest { + + private Material material; + private final Geometry geometry = new Geometry("Geometry", new Box(1, 1, 1)); + private final EnumSet myCaps = EnumSet.noneOf(Caps.class); + private final RenderManager renderManager = new RenderManager(new NullRenderer() { + @Override + public EnumSet getCaps() { + return LoadJ3mdTest.this.myCaps; + } + }); + + @Test + public void testShaderNodesMaterialDefLoading() { + supportGlsl(100); + material("testMatDef.j3md"); + material.selectTechnique("Default", renderManager); + + assertEquals(material.getActiveTechnique().getDef().getShaderNodes().size(), 2); + Shader s = material.getActiveTechnique().getDef().getShader(TestUtil.createAssetManager(), myCaps, material.getActiveTechnique().getDynamicDefines()); + assertEquals(s.getSources().size(), 2); + } + + private void supportGlsl(int version) { + switch (version) { + case 150: + myCaps.add(Caps.GLSL150); + case 140: + myCaps.add(Caps.GLSL140); + case 130: + myCaps.add(Caps.GLSL130); + case 120: + myCaps.add(Caps.GLSL120); + case 110: + myCaps.add(Caps.GLSL110); + case 100: + myCaps.add(Caps.GLSL100); + break; + } + } + private void caps(Caps... caps) { + myCaps.addAll(Arrays.asList(caps)); + } + + private void material(String path) { + AssetManager assetManager = TestUtil.createAssetManager(); + material = new Material(assetManager, path); + geometry.setMaterial(material); + } + +} diff --git a/jme3-core/src/test/java/com/jme3/math/FastMathTest.java b/jme3-core/src/test/java/com/jme3/math/FastMathTest.java index a74390d42..709f0829c 100644 --- a/jme3-core/src/test/java/com/jme3/math/FastMathTest.java +++ b/jme3-core/src/test/java/com/jme3/math/FastMathTest.java @@ -33,6 +33,9 @@ package com.jme3.math; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import org.junit.Ignore; + /** * Verifies that algorithms in {@link FastMath} are working correctly. * @@ -56,4 +59,39 @@ public class FastMathTest { assert nextPowerOf2 == nearestPowerOfTwoSlow(i); } } + + private static int fastCounterClockwise(Vector2f p0, Vector2f p1, Vector2f p2) { + float result = (p1.x - p0.x) * (p2.y - p1.y) - (p1.y - p0.y) * (p2.x - p1.x); + return (int) Math.signum(result); + } + + private static Vector2f randomVector() { + return new Vector2f(FastMath.nextRandomFloat(), + FastMath.nextRandomFloat()); + } + + @Ignore + @Test + public void testCounterClockwise() { + for (int i = 0; i < 100; i++) { + Vector2f p0 = randomVector(); + Vector2f p1 = randomVector(); + Vector2f p2 = randomVector(); + + int fastResult = fastCounterClockwise(p0, p1, p2); + int slowResult = FastMath.counterClockwise(p0, p1, p2); + + assert fastResult == slowResult; + } + + // duplicate test + Vector2f p0 = new Vector2f(0,0); + Vector2f p1 = new Vector2f(0,0); + Vector2f p2 = new Vector2f(0,1); + + int fastResult = fastCounterClockwise(p0, p1, p2); + int slowResult = FastMath.counterClockwise(p0, p1, p2); + + assertEquals(slowResult, fastResult); + } } diff --git a/jme3-core/src/test/java/com/jme3/renderer/OpaqueComparatorTest.java b/jme3-core/src/test/java/com/jme3/renderer/OpaqueComparatorTest.java new file mode 100644 index 000000000..ee4d279fd --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/renderer/OpaqueComparatorTest.java @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2009-2015 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.renderer; + +import com.jme3.asset.AssetManager; +import com.jme3.material.Material; +import com.jme3.material.TechniqueDef; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.queue.GeometryList; +import com.jme3.renderer.queue.OpaqueComparator; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.shape.Box; +import com.jme3.system.TestUtil; +import com.jme3.texture.Image; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; +import com.jme3.texture.image.ColorSpace; +import com.jme3.util.BufferUtils; +import java.nio.ByteBuffer; +import java.util.HashSet; +import java.util.Set; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +public class OpaqueComparatorTest { + + private final Mesh mesh = new Box(1,1,1); + private Camera cam = new Camera(1, 1); + private RenderManager renderManager; + private AssetManager assetManager; + private OpaqueComparator comparator = new OpaqueComparator(); + + @Before + public void setUp() { + assetManager = TestUtil.createAssetManager(); + renderManager = TestUtil.createRenderManager(); + comparator.setCamera(cam); + } + + /** + * Given a correctly sorted list of materials, check if the + * opaque comparator can sort a reversed list of them. + * + * Each material will be cloned so that none of them will be equal to each other + * in reference, forcing the comparator to compare the material sort ID. + * + * E.g. for a list of materials A, B, C, the following list will be generated: + *

    C, B, A, C, B, A, C, B, A
    , it should result in + *
    A, A, A, B, B, B, C, C, C
    . + * + * @param materials The pre-sorted list of materials to check sorting for. + */ + private void testSort(Material ... materials) { + GeometryList gl = new GeometryList(comparator); + for (int g = 0; g < 5; g++) { + for (int i = materials.length - 1; i >= 0; i--) { + Geometry geom = new Geometry("geom", mesh); + Material clonedMaterial = materials[i].clone(); + + if (materials[i].getActiveTechnique() != null) { + String techniqueName = materials[i].getActiveTechnique().getDef().getName(); + clonedMaterial.selectTechnique(techniqueName, renderManager); + } else { + clonedMaterial.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); + } + + geom.setMaterial(clonedMaterial); + gl.add(geom); + } + } + gl.sort(); + + for (int i = 0; i < gl.size(); i++) { + Material mat = gl.get(i).getMaterial(); + String sortId = Integer.toHexString(mat.getSortId()).toUpperCase(); + System.out.print(sortId + "\t"); + System.out.println(mat); + } + + Set alreadySeen = new HashSet(); + Material current = null; + for (int i = 0; i < gl.size(); i++) { + Material mat = gl.get(i).getMaterial(); + if (current == null) { + current = mat; + } else if (!current.getName().equals(mat.getName())) { + assert !alreadySeen.contains(mat.getName()); + alreadySeen.add(current.getName()); + current = mat; + } + } + + for (int i = 0; i < materials.length; i++) { + for (int g = 0; g < 5; g++) { + int index = i * 5 + g; + Material mat1 = gl.get(index).getMaterial(); + Material mat2 = materials[i]; + assert mat1.getName().equals(mat2.getName()) : + mat1.getName() + " != " + mat2.getName() + " for index " + index; + } + } + } + + @Test + public void testSortByMaterialDef() { + Material lightingMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material particleMat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + Material unshadedMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + Material skyMat = new Material(assetManager, "Common/MatDefs/Misc/Sky.j3md"); + + lightingMat.setName("MatLight"); + particleMat.setName("MatParticle"); + unshadedMat.setName("MatUnshaded"); + skyMat.setName("MatSky"); + testSort(skyMat, lightingMat, particleMat, unshadedMat); + } + + @Test + public void testSortByTechnique() { + Material lightingMatDefault = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material lightingPreShadow = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material lightingPostShadow = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material lightingMatPreNormalPass = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material lightingMatGBuf = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material lightingMatGlow = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + + lightingMatDefault.setName("TechDefault"); + lightingMatDefault.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); + + lightingPostShadow.setName("TechPostShad"); + lightingPostShadow.selectTechnique("PostShadow", renderManager); + + lightingPreShadow.setName("TechPreShad"); + lightingPreShadow.selectTechnique("PreShadow", renderManager); + + lightingMatPreNormalPass.setName("TechNorm"); + lightingMatPreNormalPass.selectTechnique("PreNormalPass", renderManager); + + lightingMatGBuf.setName("TechGBuf"); + lightingMatGBuf.selectTechnique("GBuf", renderManager); + + lightingMatGlow.setName("TechGlow"); + lightingMatGlow.selectTechnique("Glow", renderManager); + + testSort(lightingMatGlow, lightingPreShadow, lightingMatPreNormalPass, + lightingMatDefault, lightingPostShadow, lightingMatGBuf); + } + + @Test(expected = AssertionError.class) + public void testNoSortByParam() { + Material sameMat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + Material sameMat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + + sameMat1.setName("MatRed"); + sameMat1.setColor("Color", ColorRGBA.Red); + + sameMat2.setName("MatBlue"); + sameMat2.setColor("Color", ColorRGBA.Blue); + + testSort(sameMat1, sameMat2); + } + + private Texture createTexture(String name) { + ByteBuffer bb = BufferUtils.createByteBuffer(3); + Image image = new Image(Format.RGB8, 1, 1, bb, ColorSpace.sRGB); + Texture2D texture = new Texture2D(image); + texture.setName(name); + return texture; + } + + @Test + public void testSortByTexture() { + Material texture1Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + Material texture2Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + Material texture3Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + + Texture tex1 = createTexture("A"); + tex1.getImage().setId(1); + + Texture tex2 = createTexture("B"); + tex2.getImage().setId(2); + + Texture tex3 = createTexture("C"); + tex3.getImage().setId(3); + + texture1Mat.setName("TexA"); + texture1Mat.setTexture("ColorMap", tex1); + + texture2Mat.setName("TexB"); + texture2Mat.setTexture("ColorMap", tex2); + + texture3Mat.setName("TexC"); + texture3Mat.setTexture("ColorMap", tex3); + + testSort(texture1Mat, texture2Mat, texture3Mat); + } + + @Test + public void testSortByShaderDefines() { + Material lightingMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material lightingMatVColor = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material lightingMatVLight = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material lightingMatTC = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material lightingMatVColorLight = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material lightingMatTCVColorLight = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + + lightingMat.setName("DefNone"); + + lightingMatVColor.setName("DefVC"); + lightingMatVColor.setBoolean("UseVertexColor", true); + + lightingMatVLight.setName("DefVL"); + lightingMatVLight.setBoolean("VertexLighting", true); + + lightingMatTC.setName("DefTC"); + lightingMatTC.setBoolean("SeparateTexCoord", true); + + lightingMatVColorLight.setName("DefVCVL"); + lightingMatVColorLight.setBoolean("UseVertexColor", true); + lightingMatVColorLight.setBoolean("VertexLighting", true); + + lightingMatTCVColorLight.setName("DefVCVLTC"); + lightingMatTCVColorLight.setBoolean("UseVertexColor", true); + lightingMatTCVColorLight.setBoolean("VertexLighting", true); + lightingMatTCVColorLight.setBoolean("SeparateTexCoord", true); + + testSort(lightingMat, lightingMatVColor, lightingMatVLight, + lightingMatVColorLight, lightingMatTC, lightingMatTCVColorLight); + } + + @Test + public void testSortByAll() { + Material matBase1 = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material matBase2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + + Texture texBase = createTexture("BASE"); + texBase.getImage().setId(1); + Texture tex1 = createTexture("1"); + tex1.getImage().setId(2); + Texture tex2 = createTexture("2"); + tex2.getImage().setId(3); + + matBase1.setName("BASE"); + matBase1.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); + matBase1.setBoolean("UseVertexColor", true); + matBase1.setTexture("DiffuseMap", texBase); + + Material mat1100 = matBase1.clone(); + mat1100.setName("1100"); + mat1100.selectTechnique("PreShadow", renderManager); + + Material mat1101 = matBase1.clone(); + mat1101.setName("1101"); + mat1101.selectTechnique("PreShadow", renderManager); + mat1101.setTexture("DiffuseMap", tex1); + + Material mat1102 = matBase1.clone(); + mat1102.setName("1102"); + mat1102.selectTechnique("PreShadow", renderManager); + mat1102.setTexture("DiffuseMap", tex2); + + Material mat1110 = matBase1.clone(); + mat1110.setName("1110"); + mat1110.selectTechnique("PreShadow", renderManager); + mat1110.setFloat("AlphaDiscardThreshold", 2f); + + Material mat1120 = matBase1.clone(); + mat1120.setName("1120"); + mat1120.selectTechnique("PreShadow", renderManager); + mat1120.setBoolean("UseInstancing", true); + + Material mat1121 = matBase1.clone(); + mat1121.setName("1121"); + mat1121.selectTechnique("PreShadow", renderManager); + mat1121.setBoolean("UseInstancing", true); + mat1121.setTexture("DiffuseMap", tex1); + + Material mat1122 = matBase1.clone(); + mat1122.setName("1122"); + mat1122.selectTechnique("PreShadow", renderManager); + mat1122.setBoolean("UseInstancing", true); + mat1122.setTexture("DiffuseMap", tex2); + + Material mat1140 = matBase1.clone(); + mat1140.setName("1140"); + mat1140.selectTechnique("PreShadow", renderManager); + mat1140.setFloat("AlphaDiscardThreshold", 2f); + mat1140.setBoolean("UseInstancing", true); + + Material mat1200 = matBase1.clone(); + mat1200.setName("1200"); + mat1200.selectTechnique("PostShadow", renderManager); + + Material mat1210 = matBase1.clone(); + mat1210.setName("1210"); + mat1210.selectTechnique("PostShadow", renderManager); + mat1210.setFloat("AlphaDiscardThreshold", 2f); + + Material mat1220 = matBase1.clone(); + mat1220.setName("1220"); + mat1220.selectTechnique("PostShadow", renderManager); + mat1220.setBoolean("UseInstancing", true); + + Material mat2000 = matBase2.clone(); + mat2000.setName("2000"); + + testSort(mat1100, mat1101, mat1102, mat1110, + mat1120, mat1121, mat1122, mat1140, + mat1200, mat1210, mat1220, mat2000); + } +} diff --git a/jme3-core/src/test/java/com/jme3/scene/MPOTestUtils.java b/jme3-core/src/test/java/com/jme3/scene/MPOTestUtils.java new file mode 100644 index 000000000..183dece70 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/scene/MPOTestUtils.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2009-2016 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.scene; + +import com.jme3.material.MatParamOverride; +import com.jme3.math.Matrix4f; +import com.jme3.renderer.Camera; +import com.jme3.shader.VarType; +import com.jme3.texture.Texture2D; +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.Set; +import static org.junit.Assert.assertEquals; + +public class MPOTestUtils { + + private static final Camera DUMMY_CAM = new Camera(640, 480); + + private static final SceneGraphVisitor VISITOR = new SceneGraphVisitor() { + @Override + public void visit(Spatial spatial) { + validateSubScene(spatial); + } + }; + + private static void validateSubScene(Spatial scene) { + scene.checkCulling(DUMMY_CAM); + + Set actualOverrides = new HashSet(); + for (MatParamOverride override : scene.getWorldMatParamOverrides()) { + actualOverrides.add(override); + } + + Set expectedOverrides = new HashSet(); + Spatial current = scene; + while (current != null) { + for (MatParamOverride override : current.getLocalMatParamOverrides()) { + expectedOverrides.add(override); + } + current = current.getParent(); + } + + assertEquals("For " + scene, expectedOverrides, actualOverrides); + } + + public static void validateScene(Spatial scene) { + scene.updateGeometricState(); + scene.depthFirstTraversal(VISITOR); + } + + public static MatParamOverride mpoInt(String name, int value) { + return new MatParamOverride(VarType.Int, name, value); + } + + public static MatParamOverride mpoBool(String name, boolean value) { + return new MatParamOverride(VarType.Boolean, name, value); + } + + public static MatParamOverride mpoFloat(String name, float value) { + return new MatParamOverride(VarType.Float, name, value); + } + + public static MatParamOverride mpoMatrix4Array(String name, Matrix4f[] value) { + return new MatParamOverride(VarType.Matrix4Array, name, value); + } + + public static MatParamOverride mpoTexture2D(String name, Texture2D texture) { + return new MatParamOverride(VarType.Texture2D, name, texture); + } + + private static int getRefreshFlags(Spatial scene) { + try { + Field refreshFlagsField = Spatial.class.getDeclaredField("refreshFlags"); + refreshFlagsField.setAccessible(true); + return (Integer) refreshFlagsField.get(scene); + } catch (NoSuchFieldException ex) { + throw new AssertionError(ex); + } catch (SecurityException ex) { + throw new AssertionError(ex); + } catch (IllegalArgumentException ex) { + throw new AssertionError(ex); + } catch (IllegalAccessException ex) { + throw new AssertionError(ex); + } + } + + private static void dumpSceneRF(Spatial scene, String indent, boolean last, int refreshFlagsMask) { + StringBuilder sb = new StringBuilder(); + + sb.append(indent); + if (last) { + if (!indent.isEmpty()) { + sb.append("└─"); + } else { + sb.append(" "); + } + indent += " "; + } else { + sb.append("├─"); + indent += "│ "; + } + sb.append(scene.getName()); + int rf = getRefreshFlags(scene) & refreshFlagsMask; + if (rf != 0) { + sb.append("("); + if ((rf & 0x1) != 0) { + sb.append("T"); + } + if ((rf & 0x2) != 0) { + sb.append("B"); + } + if ((rf & 0x4) != 0) { + sb.append("L"); + } + if ((rf & 0x8) != 0) { + sb.append("l"); + } + if ((rf & 0x10) != 0) { + sb.append("O"); + } + sb.append(")"); + } + + if (!scene.getLocalMatParamOverrides().isEmpty()) { + sb.append(" [MPO]"); + } + + System.out.println(sb); + + if (scene instanceof Node) { + Node node = (Node) scene; + int childIndex = 0; + for (Spatial child : node.getChildren()) { + boolean childLast = childIndex == node.getQuantity() - 1; + dumpSceneRF(child, indent, childLast, refreshFlagsMask); + childIndex++; + } + } + } + + public static void dumpSceneRF(Spatial scene, int refreshFlagsMask) { + dumpSceneRF(scene, "", true, refreshFlagsMask); + } +} diff --git a/jme3-core/src/test/java/com/jme3/scene/SceneMatParamOverrideTest.java b/jme3-core/src/test/java/com/jme3/scene/SceneMatParamOverrideTest.java new file mode 100644 index 000000000..a615d5c92 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/scene/SceneMatParamOverrideTest.java @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2009-2016 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.scene; + +import com.jme3.asset.AssetManager; +import com.jme3.export.binary.BinaryExporter; +import com.jme3.material.MatParamOverride; +import org.junit.Test; + +import static com.jme3.scene.MPOTestUtils.*; +import static org.junit.Assert.*; + +import com.jme3.system.TestUtil; +import java.util.ArrayList; +import java.util.List; + +/** + * Validates how {@link MatParamOverride MPOs} work on the scene level. + * + * @author Kirill Vainer + */ +public class SceneMatParamOverrideTest { + + private static Node createDummyScene() { + Node scene = new Node("Scene Node"); + + Node a = new Node("A"); + Node b = new Node("B"); + + Node c = new Node("C"); + Node d = new Node("D"); + + Node e = new Node("E"); + Node f = new Node("F"); + + Node g = new Node("G"); + Node h = new Node("H"); + Node j = new Node("J"); + + scene.attachChild(a); + scene.attachChild(b); + + a.attachChild(c); + a.attachChild(d); + + b.attachChild(e); + b.attachChild(f); + + c.attachChild(g); + c.attachChild(h); + c.attachChild(j); + + return scene; + } + + @Test + public void testOverrides_Empty() { + Node n = new Node("Node"); + assertTrue(n.getLocalMatParamOverrides().isEmpty()); + assertTrue(n.getWorldMatParamOverrides().isEmpty()); + + n.updateGeometricState(); + assertTrue(n.getLocalMatParamOverrides().isEmpty()); + assertTrue(n.getWorldMatParamOverrides().isEmpty()); + } + + @Test + public void testOverrides_AddRemove() { + MatParamOverride override = mpoBool("Test", true); + Node n = new Node("Node"); + + n.removeMatParamOverride(override); + assertTrue(n.getLocalMatParamOverrides().isEmpty()); + assertTrue(n.getWorldMatParamOverrides().isEmpty()); + + n.addMatParamOverride(override); + + assertSame(n.getLocalMatParamOverrides().get(0), override); + assertTrue(n.getWorldMatParamOverrides().isEmpty()); + n.updateGeometricState(); + + assertSame(n.getLocalMatParamOverrides().get(0), override); + assertSame(n.getWorldMatParamOverrides().get(0), override); + + n.removeMatParamOverride(override); + assertTrue(n.getLocalMatParamOverrides().isEmpty()); + assertSame(n.getWorldMatParamOverrides().get(0), override); + + n.updateGeometricState(); + assertTrue(n.getLocalMatParamOverrides().isEmpty()); + assertTrue(n.getWorldMatParamOverrides().isEmpty()); + } + + @Test + public void testOverrides_Clear() { + MatParamOverride override = mpoBool("Test", true); + Node n = new Node("Node"); + + n.clearMatParamOverrides(); + assertTrue(n.getLocalMatParamOverrides().isEmpty()); + assertTrue(n.getWorldMatParamOverrides().isEmpty()); + + n.addMatParamOverride(override); + n.clearMatParamOverrides(); + assertTrue(n.getLocalMatParamOverrides().isEmpty()); + assertTrue(n.getWorldMatParamOverrides().isEmpty()); + + n.addMatParamOverride(override); + n.updateGeometricState(); + n.clearMatParamOverrides(); + assertTrue(n.getLocalMatParamOverrides().isEmpty()); + assertSame(n.getWorldMatParamOverrides().get(0), override); + + n.updateGeometricState(); + assertTrue(n.getLocalMatParamOverrides().isEmpty()); + assertTrue(n.getWorldMatParamOverrides().isEmpty()); + + n.addMatParamOverride(override); + n.clearMatParamOverrides(); + n.updateGeometricState(); + assertTrue(n.getLocalMatParamOverrides().isEmpty()); + assertTrue(n.getWorldMatParamOverrides().isEmpty()); + } + + @Test + public void testOverrides_AddAfterAttach() { + Node scene = createDummyScene(); + scene.updateGeometricState(); + + Node root = new Node("Root Node"); + root.updateGeometricState(); + + root.attachChild(scene); + scene.getChild("A").addMatParamOverride(mpoInt("val", 5)); + + validateScene(root); + } + + @Test + public void testOverrides_AddBeforeAttach() { + Node scene = createDummyScene(); + scene.getChild("A").addMatParamOverride(mpoInt("val", 5)); + scene.updateGeometricState(); + + Node root = new Node("Root Node"); + root.updateGeometricState(); + + root.attachChild(scene); + + validateScene(root); + } + + @Test + public void testOverrides_RemoveBeforeAttach() { + Node scene = createDummyScene(); + scene.updateGeometricState(); + + Node root = new Node("Root Node"); + root.updateGeometricState(); + + scene.getChild("A").addMatParamOverride(mpoInt("val", 5)); + validateScene(scene); + + scene.getChild("A").clearMatParamOverrides(); + validateScene(scene); + + root.attachChild(scene); + validateScene(root); + } + + @Test + public void testOverrides_RemoveAfterAttach() { + Node scene = createDummyScene(); + scene.updateGeometricState(); + + Node root = new Node("Root Node"); + root.updateGeometricState(); + + scene.getChild("A").addMatParamOverride(mpoInt("val", 5)); + + root.attachChild(scene); + validateScene(root); + + scene.getChild("A").clearMatParamOverrides(); + validateScene(root); + } + + @Test + public void testOverrides_IdenticalNames() { + Node scene = createDummyScene(); + + scene.getChild("A").addMatParamOverride(mpoInt("val", 5)); + scene.getChild("C").addMatParamOverride(mpoInt("val", 7)); + + validateScene(scene); + } + + @Test + public void testOverrides_CloningScene_DoesntCloneMPO() { + Node originalScene = createDummyScene(); + + originalScene.getChild("A").addMatParamOverride(mpoInt("int", 5)); + originalScene.getChild("A").addMatParamOverride(mpoBool("bool", true)); + originalScene.getChild("A").addMatParamOverride(mpoFloat("float", 3.12f)); + + Node clonedScene = originalScene.clone(false); + + validateScene(clonedScene); + validateScene(originalScene); + + List clonedOverrides = clonedScene.getChild("A").getLocalMatParamOverrides(); + List originalOverrides = originalScene.getChild("A").getLocalMatParamOverrides(); + + assertNotSame(clonedOverrides, originalOverrides); + assertEquals(clonedOverrides, originalOverrides); + + for (int i = 0; i < clonedOverrides.size(); i++) { + assertNotSame(clonedOverrides.get(i), originalOverrides.get(i)); + assertEquals(clonedOverrides.get(i), originalOverrides.get(i)); + } + } + + @Test + public void testOverrides_SaveAndLoad_KeepsMPOs() { + MatParamOverride override = mpoInt("val", 5); + Node scene = createDummyScene(); + scene.getChild("A").addMatParamOverride(override); + + AssetManager assetManager = TestUtil.createAssetManager(); + Node loadedScene = BinaryExporter.saveAndLoad(assetManager, scene); + + Node root = new Node("Root Node"); + root.attachChild(loadedScene); + validateScene(root); + validateScene(scene); + + assertNotSame(override, loadedScene.getChild("A").getLocalMatParamOverrides().get(0)); + assertEquals(override, loadedScene.getChild("A").getLocalMatParamOverrides().get(0)); + } + + @Test + public void testEquals() { + assertEquals(mpoInt("val", 5), mpoInt("val", 5)); + assertEquals(mpoBool("val", true), mpoBool("val", true)); + assertNotEquals(mpoInt("val", 5), mpoInt("val", 6)); + assertNotEquals(mpoInt("val1", 5), mpoInt("val2", 5)); + assertNotEquals(mpoBool("val", true), mpoInt("val", 1)); + } +} diff --git a/jme3-core/src/test/java/com/jme3/shader/DefineListTest.java b/jme3-core/src/test/java/com/jme3/shader/DefineListTest.java new file mode 100644 index 000000000..35812b7c3 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/shader/DefineListTest.java @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2009-2015 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.shader; + +import com.jme3.math.FastMath; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class DefineListTest { + + private static final List DEFINE_NAMES = Arrays.asList("BOOL_VAR", "INT_VAR", "FLOAT_VAR"); + private static final List DEFINE_TYPES = Arrays.asList(VarType.Boolean, VarType.Int, VarType.Float); + private static final int NUM_DEFINES = DEFINE_NAMES.size(); + private static final int BOOL_VAR = 0; + private static final int INT_VAR = 1; + private static final int FLOAT_VAR = 2; + private static final DefineList EMPTY = new DefineList(NUM_DEFINES); + + @Test + public void testHashCollision() { + DefineList dl1 = new DefineList(64); + DefineList dl2 = new DefineList(64); + + // Try to cause a hash collision + // (since bit #32 is aliased to bit #1 in 32-bit ints) + dl1.set(0, 123); + dl1.set(32, 0); + + dl2.set(32, 0); + dl2.set(0, 123); + + assert dl1.hashCode() == dl2.hashCode(); + assert dl1.equals(dl2); + } + + @Test + public void testGetSet() { + DefineList dl = new DefineList(NUM_DEFINES); + + assertFalse(dl.getBoolean(BOOL_VAR)); + assertEquals(dl.getInt(INT_VAR), 0); + assertEquals(dl.getFloat(FLOAT_VAR), 0f, 0f); + + dl.set(BOOL_VAR, true); + dl.set(INT_VAR, -1); + dl.set(FLOAT_VAR, Float.NaN); + + assertTrue(dl.getBoolean(BOOL_VAR)); + assertEquals(dl.getInt(INT_VAR), -1); + assertTrue(Float.isNaN(dl.getFloat(FLOAT_VAR))); + } + + private String generateSource(DefineList dl) { + StringBuilder sb = new StringBuilder(); + dl.generateSource(sb, DEFINE_NAMES, DEFINE_TYPES); + return sb.toString(); + } + + @Test + public void testSourceInitial() { + DefineList dl = new DefineList(NUM_DEFINES); + assert dl.hashCode() == 0; + assert generateSource(dl).equals(""); + } + + @Test + public void testSourceBooleanDefine() { + DefineList dl = new DefineList(NUM_DEFINES); + + dl.set(BOOL_VAR, true); + assert dl.hashCode() == 1; + assert generateSource(dl).equals("#define BOOL_VAR 1\n"); + + dl.set(BOOL_VAR, false); + assert dl.hashCode() == 0; + assert generateSource(dl).equals(""); + } + + @Test + public void testSourceIntDefine() { + DefineList dl = new DefineList(NUM_DEFINES); + + int hashCodeWithInt = 1 << INT_VAR; + + dl.set(INT_VAR, 123); + assert dl.hashCode() == hashCodeWithInt; + assert generateSource(dl).equals("#define INT_VAR 123\n"); + + dl.set(INT_VAR, 0); + assert dl.hashCode() == 0; + assert generateSource(dl).equals(""); + + dl.set(INT_VAR, -99); + assert dl.hashCode() == hashCodeWithInt; + assert generateSource(dl).equals("#define INT_VAR -99\n"); + + dl.set(INT_VAR, Integer.MAX_VALUE); + assert dl.hashCode() == hashCodeWithInt; + assert generateSource(dl).equals("#define INT_VAR 2147483647\n"); + } + + @Test + public void testSourceFloatDefine() { + DefineList dl = new DefineList(NUM_DEFINES); + + dl.set(FLOAT_VAR, 1f); + assert dl.hashCode() == (1 << FLOAT_VAR); + assert generateSource(dl).equals("#define FLOAT_VAR 1.0\n"); + + dl.set(FLOAT_VAR, 0f); + assert dl.hashCode() == 0; + assert generateSource(dl).equals(""); + + dl.set(FLOAT_VAR, -1f); + assert generateSource(dl).equals("#define FLOAT_VAR -1.0\n"); + + dl.set(FLOAT_VAR, FastMath.FLT_EPSILON); + assert generateSource(dl).equals("#define FLOAT_VAR 1.1920929E-7\n"); + + dl.set(FLOAT_VAR, FastMath.PI); + assert generateSource(dl).equals("#define FLOAT_VAR 3.1415927\n"); + + try { + dl.set(FLOAT_VAR, Float.NaN); + generateSource(dl); + assert false; + } catch (IllegalArgumentException ex) { } + + try { + dl.set(FLOAT_VAR, Float.POSITIVE_INFINITY); + generateSource(dl); + assert false; + } catch (IllegalArgumentException ex) { } + + try { + dl.set(FLOAT_VAR, Float.NEGATIVE_INFINITY); + generateSource(dl); + assert false; + } catch (IllegalArgumentException ex) { } + } + + @Test + public void testEqualsAndHashCode() { + DefineList dl1 = new DefineList(NUM_DEFINES); + DefineList dl2 = new DefineList(NUM_DEFINES); + + assertTrue(dl1.hashCode() == 0); + assertEquals(dl1, dl2); + + dl1.set(BOOL_VAR, true); + + assertTrue(dl1.hashCode() == 1); + assertNotSame(dl1, dl2); + + dl2.set(BOOL_VAR, true); + + assertEquals(dl1, dl2); + + dl1.set(INT_VAR, 2); + + assertTrue(dl1.hashCode() == (1|2)); + assertNotSame(dl1, dl2); + + dl2.set(INT_VAR, 2); + + assertEquals(dl1, dl2); + + dl1.set(BOOL_VAR, false); + + assertTrue(dl1.hashCode() == 2); + assertNotSame(dl1, dl2); + } + + @Test + public void testDeepClone() { + DefineList dl1 = new DefineList(NUM_DEFINES); + DefineList dl2 = dl1.deepClone(); + + assertFalse(dl1 == dl2); + assertTrue(dl1.equals(dl2)); + assertTrue(dl1.hashCode() == dl2.hashCode()); + + dl1.set(BOOL_VAR, true); + dl2 = dl1.deepClone(); + + assertTrue(dl1.equals(dl2)); + assertTrue(dl1.hashCode() == dl2.hashCode()); + + dl1.set(INT_VAR, 123); + + assertFalse(dl1.equals(dl2)); + assertFalse(dl1.hashCode() == dl2.hashCode()); + + dl2 = dl1.deepClone(); + + assertTrue(dl1.equals(dl2)); + assertTrue(dl1.hashCode() == dl2.hashCode()); + } + + @Test + public void testGenerateSource() { + DefineList dl = new DefineList(NUM_DEFINES); + + assertEquals("", generateSource(dl)); + + dl.set(BOOL_VAR, true); + + assertEquals("#define BOOL_VAR 1\n", generateSource(dl)); + + dl.set(INT_VAR, 123); + + assertEquals("#define BOOL_VAR 1\n" + + "#define INT_VAR 123\n", generateSource(dl)); + + dl.set(BOOL_VAR, false); + + assertEquals("#define INT_VAR 123\n", generateSource(dl)); + + dl.set(BOOL_VAR, true); + + // should have predictable ordering based on defineId + assertEquals("#define BOOL_VAR 1\n" + + "#define INT_VAR 123\n", generateSource(dl)); + } + + private static String doLookup(HashMap map, boolean boolVal, int intVal, float floatVal) { + DefineList dl = new DefineList(NUM_DEFINES); + dl.set(BOOL_VAR, boolVal); + dl.set(INT_VAR, intVal); + dl.set(FLOAT_VAR, floatVal); + return map.get(dl); + } + + @Test + public void testHashLookup() { + String STR_EMPTY = "This is an empty define list"; + String STR_INT = "This define list has an int value"; + String STR_BOOL = "This define list just has boolean value set"; + String STR_BOOL_INT = "This define list has both a boolean and int value"; + String STR_BOOL_INT_FLOAT = "This define list has a boolean, int, and float value"; + + HashMap map = new HashMap(); + + DefineList lookup = new DefineList(NUM_DEFINES); + + map.put(lookup.deepClone(), STR_EMPTY); + + lookup.set(BOOL_VAR, true); + map.put(lookup.deepClone(), STR_BOOL); + + lookup.set(BOOL_VAR, false); + lookup.set(INT_VAR, 123); + map.put(lookup.deepClone(), STR_INT); + + lookup.set(BOOL_VAR, true); + map.put(lookup.deepClone(), STR_BOOL_INT); + + lookup.set(FLOAT_VAR, FastMath.PI); + map.put(lookup.deepClone(), STR_BOOL_INT_FLOAT); + + assertEquals(doLookup(map, false, 0, 0f), STR_EMPTY); + assertEquals(doLookup(map, false, 123, 0f), STR_INT); + assertEquals(doLookup(map, true, 0, 0f), STR_BOOL); + assertEquals(doLookup(map, true, 123, 0f), STR_BOOL_INT); + assertEquals(doLookup(map, true, 123, FastMath.PI), STR_BOOL_INT_FLOAT); + } +} diff --git a/jme3-core/src/main/java/com/jme3/effect/ParticleComparator.java b/jme3-core/src/test/java/com/jme3/system/MockJmeSystemDelegate.java similarity index 57% rename from jme3-core/src/main/java/com/jme3/effect/ParticleComparator.java rename to jme3-core/src/test/java/com/jme3/system/MockJmeSystemDelegate.java index 78ee034d7..b9beac7f6 100644 --- a/jme3-core/src/main/java/com/jme3/effect/ParticleComparator.java +++ b/jme3-core/src/test/java/com/jme3/system/MockJmeSystemDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2012 jMonkeyEngine + * Copyright (c) 2009-2015 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,48 +29,50 @@ * 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.effect; +package com.jme3.system; -import com.jme3.renderer.Camera; -import java.util.Comparator; +import com.jme3.audio.AudioRenderer; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URL; +import java.nio.ByteBuffer; -@Deprecated -class ParticleComparator implements Comparator { +public class MockJmeSystemDelegate extends JmeSystemDelegate { - private Camera cam; + @Override + public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException { + } - public void setCamera(Camera cam){ - this.cam = cam; + @Override + public void showErrorDialog(String message) { } - public int compare(Particle p1, Particle p2) { - return 0; // unused - /* - if (p1.life <= 0 || p2.life <= 0) - return 0; + @Override + public boolean showSettingsDialog(AppSettings sourceSettings, boolean loadFromRegistry) { + return false; + } -// if (p1.life <= 0) -// return 1; -// else if (p2.life <= 0) -// return -1; + @Override + public URL getPlatformAssetConfigURL() { + return Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/General.cfg"); + } - float d1 = p1.distToCam, d2 = p2.distToCam; + @Override + public JmeContext newContext(AppSettings settings, JmeContext.Type contextType) { + return null; + } - if (d1 == -1){ - d1 = cam.distanceToNearPlane(p1.position); - p1.distToCam = d1; - } - if (d2 == -1){ - d2 = cam.distanceToNearPlane(p2.position); - p2.distToCam = d2; - } + @Override + public AudioRenderer newAudioRenderer(AppSettings settings) { + return null; + } + + @Override + public void initialize(AppSettings settings) { + } - if (d1 < d2) - return 1; - else if (d1 > d2) - return -1; - else - return 0; - */ + @Override + public void showSoftKeyboard(boolean show) { } -} \ No newline at end of file + +} diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageHeightmap.java b/jme3-core/src/test/java/com/jme3/system/TestUtil.java similarity index 69% rename from jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageHeightmap.java rename to jme3-core/src/test/java/com/jme3/system/TestUtil.java index a61000e84..124b59ba7 100644 --- a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageHeightmap.java +++ b/jme3-core/src/test/java/com/jme3/system/TestUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2012 jMonkeyEngine + * Copyright (c) 2009-2015 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,27 +29,27 @@ * 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.terrain.heightmap; +package com.jme3.system; -/** - * A heightmap that is built off an image. - * If you want to be able to supply different Image types to - * ImageBaseHeightMapGrid, you need to implement this interface, - * and have that class extend Abstract heightmap. - * - * @author bowens - * @deprecated - */ -public interface ImageHeightmap { +import com.jme3.asset.AssetConfig; +import com.jme3.asset.AssetManager; +import com.jme3.asset.DesktopAssetManager; +import com.jme3.renderer.RenderManager; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class TestUtil { + + static { + JmeSystem.setSystemDelegate(new MockJmeSystemDelegate()); + } - /** - * Set the image to use for this heightmap - */ - //public void setImage(Image image); + public static AssetManager createAssetManager() { + Logger.getLogger(AssetConfig.class.getName()).setLevel(Level.OFF); + return new DesktopAssetManager(true); + } - /** - * The BufferedImage.TYPE_ that is supported - * by this ImageHeightmap - */ - //public int getSupportedImageType(); + public static RenderManager createRenderManager() { + return new RenderManager(new NullRenderer()); + } } diff --git a/jme3-core/src/test/resources/no-default-technique.j3md b/jme3-core/src/test/resources/no-default-technique.j3md new file mode 100644 index 000000000..03a7405ac --- /dev/null +++ b/jme3-core/src/test/resources/no-default-technique.j3md @@ -0,0 +1,6 @@ +MaterialDef Test Material { + Technique Test { + VertexShader GLSL100 : test.vert + FragmentShader GLSL100 : test.frag + } +} diff --git a/jme3-core/src/test/resources/no-shader-specified.j3md b/jme3-core/src/test/resources/no-shader-specified.j3md new file mode 100644 index 000000000..a81893c69 --- /dev/null +++ b/jme3-core/src/test/resources/no-shader-specified.j3md @@ -0,0 +1,8 @@ +MaterialDef Test Material { + Technique A { + } + Technique B { + VertexShader GLSL100 : test.vert + FragmentShader GLSL100 : test.frag + } +} diff --git a/jme3-core/src/test/resources/same-name-technique.j3md b/jme3-core/src/test/resources/same-name-technique.j3md new file mode 100644 index 000000000..f3fde1876 --- /dev/null +++ b/jme3-core/src/test/resources/same-name-technique.j3md @@ -0,0 +1,10 @@ +MaterialDef Test Material { + Technique Test { + VertexShader GLSL150 : test150.vert + FragmentShader GLSL150 : test150.frag + } + Technique Test { + VertexShader GLSL100 : test.vert + FragmentShader GLSL100 : test.frag + } +} diff --git a/jme3-core/src/test/resources/testMatDef.j3md b/jme3-core/src/test/resources/testMatDef.j3md new file mode 100644 index 000000000..bf70b1e2a --- /dev/null +++ b/jme3-core/src/test/resources/testMatDef.j3md @@ -0,0 +1,34 @@ +MaterialDef Simple { + MaterialParameters { + Color Color + } + Technique { + WorldParameters { + WorldViewProjectionMatrix + } + VertexShaderNodes { + ShaderNode CommonVert { + Definition : CommonVert : Common/MatDefs/ShaderNodes/Common/CommonVert.j3sn + InputMappings { + worldViewProjectionMatrix = WorldParam.WorldViewProjectionMatrix + modelPosition = Global.position.xyz + } + OutputMappings { + Global.position = projPosition + } + } + } + FragmentShaderNodes { + ShaderNode ColorMult { + Definition : ColorMult : Common/MatDefs/ShaderNodes/Basic/ColorMult.j3sn + InputMappings { + color1 = MatParam.Color + color2 = Global.color + } + OutputMappings { + Global.color = outColor + } + } + } + } +} \ No newline at end of file diff --git a/jme3-core/src/tools/java/jme3tools/optimize/TextureAtlas.java b/jme3-core/src/tools/java/jme3tools/optimize/TextureAtlas.java index 98347067c..9ca739014 100644 --- a/jme3-core/src/tools/java/jme3tools/optimize/TextureAtlas.java +++ b/jme3-core/src/tools/java/jme3tools/optimize/TextureAtlas.java @@ -504,7 +504,6 @@ public class TextureAtlas { geom.setMesh(mesh); Material mat = new Material(mgr, "Common/MatDefs/Light/Lighting.j3md"); - mat.getAdditionalRenderState().setAlphaTest(true); Texture diffuseMap = atlas.getAtlasTexture("DiffuseMap"); Texture normalMap = atlas.getAtlasTexture("NormalMap"); Texture specularMap = atlas.getAtlasTexture("SpecularMap"); diff --git a/jme3-core/src/tools/java/jme3tools/shadercheck/ShaderCheck.java b/jme3-core/src/tools/java/jme3tools/shadercheck/ShaderCheck.java index c77fa2b2e..98d379b38 100644 --- a/jme3-core/src/tools/java/jme3tools/shadercheck/ShaderCheck.java +++ b/jme3-core/src/tools/java/jme3tools/shadercheck/ShaderCheck.java @@ -6,11 +6,12 @@ import com.jme3.asset.plugins.FileLocator; import com.jme3.material.MaterialDef; import com.jme3.material.TechniqueDef; import com.jme3.material.plugins.J3MLoader; +import com.jme3.renderer.Caps; import com.jme3.shader.DefineList; import com.jme3.shader.Shader; -import com.jme3.shader.ShaderKey; import com.jme3.shader.plugins.GLSLLoader; import com.jme3.system.JmeSystem; +import java.util.EnumSet; import java.util.logging.Level; import java.util.logging.Logger; @@ -33,23 +34,22 @@ public class ShaderCheck { assetManager.registerLoader(GLSLLoader.class, "vert", "frag","geom","tsctrl","tseval","glsllib"); } - private static void checkMatDef(String matdefName){ + private static void checkMatDef(String matdefName) { MaterialDef def = (MaterialDef) assetManager.loadAsset(matdefName); - for (TechniqueDef techDef : def.getDefaultTechniques()){ - DefineList dl = new DefineList(); - dl.addFrom(techDef.getShaderPresetDefines()); - ShaderKey shaderKey = new ShaderKey(dl,techDef.getShaderProgramLanguages(),techDef.getShaderProgramNames()); - - Shader shader = assetManager.loadShader(shaderKey); - - for (Validator validator : validators){ + EnumSet rendererCaps = EnumSet.noneOf(Caps.class); + rendererCaps.add(Caps.GLSL100); + for (TechniqueDef techDef : def.getTechniqueDefs(TechniqueDef.DEFAULT_TECHNIQUE_NAME)) { + DefineList defines = techDef.createDefineList(); + Shader shader = techDef.getShader(assetManager, rendererCaps, defines); + for (Validator validator : validators) { StringBuilder sb = new StringBuilder(); validator.validate(shader, sb); - System.out.println("==== Validator: " + validator.getName() + " " + - validator.getInstalledVersion() + " ===="); + System.out.println("==== Validator: " + validator.getName() + " " + + validator.getInstalledVersion() + " ===="); System.out.println(sb.toString()); } } + throw new UnsupportedOperationException(); } public static void main(String[] args){ diff --git a/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java b/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java index 37a01e8ed..d02b5d21c 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java +++ b/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java @@ -43,6 +43,7 @@ import com.jme3.system.JmeContext.Type; import com.jme3.util.Screenshots; import java.awt.EventQueue; import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; @@ -116,12 +117,16 @@ public class JmeDesktopSystem extends JmeSystemDelegate { @Override public void showErrorDialog(String message) { - final String msg = message; - EventQueue.invokeLater(new Runnable() { - public void run() { - ErrorDialog.showDialog(msg); - } - }); + if (!GraphicsEnvironment.isHeadless()) { + final String msg = message; + EventQueue.invokeLater(new Runnable() { + public void run() { + ErrorDialog.showDialog(msg); + } + }); + } else { + System.err.println("[JME ERROR] " + message); + } } @Override @@ -129,6 +134,9 @@ public class JmeDesktopSystem extends JmeSystemDelegate { if (SwingUtilities.isEventDispatchThread()) { throw new IllegalStateException("Cannot run from EDT"); } + if (GraphicsEnvironment.isHeadless()) { + throw new IllegalStateException("Cannot show dialog in headless environment"); + } final AppSettings settings = new AppSettings(false); settings.copyFrom(sourceSettings); @@ -333,27 +341,13 @@ public class JmeDesktopSystem extends JmeSystemDelegate { if (initialized) { return; } - initialized = true; - try { - if (!lowPermissions) { - // can only modify logging settings - // if permissions are available -// JmeFormatter formatter = new JmeFormatter(); -// Handler fileHandler = new FileHandler("jme.log"); -// fileHandler.setFormatter(formatter); -// Logger.getLogger("").addHandler(fileHandler); -// Handler consoleHandler = new ConsoleHandler(); -// consoleHandler.setFormatter(formatter); -// Logger.getLogger("").removeHandler(Logger.getLogger("").getHandlers()[0]); -// Logger.getLogger("").addHandler(consoleHandler); + logger.log(Level.INFO, getBuildInfo()); + if (!lowPermissions) { + if (NativeLibraryLoader.isUsingNativeBullet()) { + NativeLibraryLoader.loadNativeLibrary("bulletjme", true); } -// } catch (IOException ex){ -// logger.log(Level.SEVERE, "I/O Error while creating log file", ex); - } catch (SecurityException ex) { - logger.log(Level.SEVERE, "Security error in creating log file", ex); } - logger.log(Level.INFO, getBuildInfo()); } @Override diff --git a/jme3-desktop/src/main/java/com/jme3/system/Natives.java b/jme3-desktop/src/main/java/com/jme3/system/Natives.java deleted file mode 100644 index 423fda882..000000000 --- a/jme3-desktop/src/main/java/com/jme3/system/Natives.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright (c) 2009-2012 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.system; - -import java.io.*; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Helper class for extracting the natives (dll, so) from the jars. - * This class should only be used internally. - * - * @deprecated Use {@link NativeLibraryLoader} instead. - */ -@Deprecated -public final class Natives { - - private static final Logger logger = Logger.getLogger(Natives.class.getName()); - private static final byte[] buf = new byte[1024 * 100]; - private static File extractionDirOverride = null; - private static File extractionDir = null; - - public static void setExtractionDir(String name) { - extractionDirOverride = new File(name).getAbsoluteFile(); - } - - public static File getExtractionDir() { - if (extractionDirOverride != null) { - return extractionDirOverride; - } - if (extractionDir == null) { - File workingFolder = new File("").getAbsoluteFile(); - if (!workingFolder.canWrite()) { - setStorageExtractionDir(); - } else { - try { - File file = new File(workingFolder.getAbsolutePath() + File.separator + ".jmetestwrite"); - file.createNewFile(); - file.delete(); - extractionDir = workingFolder; - } catch (Exception e) { - setStorageExtractionDir(); - } - } - } - return extractionDir; - } - - private static void setStorageExtractionDir() { - logger.log(Level.WARNING, "Working directory is not writable. Using home directory instead."); - extractionDir = new File(JmeSystem.getStorageFolder(), - "natives_" + Integer.toHexString(computeNativesHash())); - if (!extractionDir.exists()) { - extractionDir.mkdir(); - } - } - - private static int computeNativesHash() { - URLConnection conn = null; - try { - String classpath = System.getProperty("java.class.path"); - URL url = Thread.currentThread().getContextClassLoader().getResource("com/jme3/system/Natives.class"); - - StringBuilder sb = new StringBuilder(url.toString()); - if (sb.indexOf("jar:") == 0) { - sb.delete(0, 4); - sb.delete(sb.indexOf("!"), sb.length()); - sb.delete(sb.lastIndexOf("/") + 1, sb.length()); - } - try { - url = new URL(sb.toString()); - } catch (MalformedURLException ex) { - throw new UnsupportedOperationException(ex); - } - - conn = url.openConnection(); - int hash = classpath.hashCode() ^ (int) conn.getLastModified(); - return hash; - } catch (IOException ex) { - throw new UnsupportedOperationException(ex); - } finally { - if (conn != null) { - try { - conn.getInputStream().close(); - conn.getOutputStream().close(); - } catch (IOException ex) { } - } - } - } - - public static void extractNativeLib(String sysName, String name) throws IOException { - extractNativeLib(sysName, name, false, true); - } - - public static void extractNativeLib(String sysName, String name, boolean load) throws IOException { - extractNativeLib(sysName, name, load, true); - } - - public static void extractNativeLib(String sysName, String name, boolean load, boolean warning) throws IOException { - String fullname; - String path; - //XXX: hack to allow specifying the extension via supplying an extension in the name (e.g. "blah.dylib") - // this is needed on osx where the openal.dylib always needs to be extracted as dylib - // and never as jnilib, even if that is the platform JNI lib suffix (OpenAL is no JNI library) - if(!name.contains(".")){ - // automatic name mapping - fullname = System.mapLibraryName(name); - path = "native/" + sysName + "/" + fullname; - //XXX: Hack to extract jnilib to dylib on OSX Java 1.7+ - // This assumes all jni libs for osx are stored as "jnilib" in the jar file. - // It will be extracted with the name required for the platform. - // At a later stage this should probably inverted so that dylib is the default name. - if(sysName.equals("macosx")){ - path = path.replaceAll("dylib","jnilib"); - } - } else{ - fullname = name; - path = "native/" + sysName + "/" + fullname; - } - - URL url = Thread.currentThread().getContextClassLoader().getResource(path); - - // Also check for binaries that are not packed in folders by jme team, e.g. maven artifacts - if(url == null){ - path = fullname; - if(sysName.equals("macosx") && !name.contains(".")){ - path = path.replaceAll("dylib","jnilib"); - } - url = Thread.currentThread().getContextClassLoader().getResource(path); - } - - if(url == null){ - if (!warning) { - logger.log(Level.WARNING, "Cannot locate native library in classpath: {0}/{1}", - new String[]{sysName, fullname}); - } - // Still try loading the library without a filename, maybe it is - // accessible otherwise - try{ - System.loadLibrary(name); - } catch(UnsatisfiedLinkError e){ - if (!warning) { - logger.log(Level.WARNING, "Cannot load native library: {0}/{1}", - new String[]{sysName, fullname}); - } - } - return; - } - - URLConnection conn = url.openConnection(); - InputStream in = conn.getInputStream(); - File targetFile = new File(getExtractionDir(), fullname); - OutputStream out = null; - try { - if (targetFile.exists()) { - // OK, compare last modified date of this file to - // file in jar - long targetLastModified = targetFile.lastModified(); - long sourceLastModified = conn.getLastModified(); - - // Allow ~1 second range for OSes that only support low precision - if (targetLastModified + 1000 > sourceLastModified) { - logger.log(Level.FINE, "Not copying library {0}. Latest already extracted.", fullname); - return; - } - } - - out = new FileOutputStream(targetFile); - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } - in.close(); - in = null; - out.close(); - out = null; - - // NOTE: On OSes that support "Date Created" property, - // this will cause the last modified date to be lower than - // date created which makes no sense - targetFile.setLastModified(conn.getLastModified()); - } catch (FileNotFoundException ex) { - if (ex.getMessage().contains("used by another process")) { - return; - } - - throw ex; - } finally { - if (load) { - System.load(targetFile.getAbsolutePath()); - } - if(in != null){ - in.close(); - } - if(out != null){ - out.close(); - } - } - logger.log(Level.FINE, "Copied {0} to {1}", new Object[]{fullname, targetFile}); - } - - protected static boolean isUsingNativeBullet() { - try { - Class clazz = Class.forName("com.jme3.bullet.util.NativeMeshUtil"); - return clazz != null; - } catch (ClassNotFoundException ex) { - return false; - } - } - - public static void extractNativeLibs(Platform platform, AppSettings settings) throws IOException { - if (true) { - throw new UnsupportedEncodingException("Now, why would you EVER want to do that?"); - } - - String renderer = settings.getRenderer(); - String audioRenderer = settings.getAudioRenderer(); - boolean needLWJGL = false; - boolean needOAL = false; - boolean needJInput = false; - boolean needNativeBullet = isUsingNativeBullet(); - - if (renderer != null) { - if (renderer.startsWith("LWJGL")) { - needLWJGL = true; - } - } - if (audioRenderer != null) { - if (audioRenderer.equals("LWJGL")) { - needLWJGL = true; - needOAL = true; - } - } - needJInput = settings.useJoysticks(); - - String libraryPath = getExtractionDir().toString(); - if (needLWJGL) { - logger.log(Level.INFO, "Extraction Directory: {0}", getExtractionDir().toString()); - - // LWJGL supports this feature where - // it can load libraries from this path. - System.setProperty("org.lwjgl.librarypath", libraryPath); - } - if (needJInput) { - // AND Luckily enough JInput supports the same feature. - System.setProperty("net.java.games.input.librarypath", libraryPath); - } - - switch (platform) { - case Windows64: - if (needLWJGL) { - extractNativeLib("windows", "lwjgl64"); - } - if (needOAL) { - extractNativeLib("windows", "OpenAL64", true, false); - } - if (needJInput) { - extractNativeLib("windows", "jinput-dx8_64"); - extractNativeLib("windows", "jinput-raw_64"); - } - if (needNativeBullet) { - extractNativeLib("windows", "bulletjme64", true, false); - } - break; - case Windows32: - if (needLWJGL) { - extractNativeLib("windows", "lwjgl"); - } - if (needOAL) { - extractNativeLib("windows", "OpenAL32", true, false); - } - if (needJInput) { - extractNativeLib("windows", "jinput-dx8"); - extractNativeLib("windows", "jinput-raw"); - } - if (needNativeBullet) { - extractNativeLib("windows", "bulletjme", true, false); - } - break; - case Linux64: - if (needLWJGL) { - extractNativeLib("linux", "lwjgl64"); - } - if (needJInput) { - extractNativeLib("linux", "jinput-linux64"); - } - if (needOAL) { - extractNativeLib("linux", "openal64"); - } - if (needNativeBullet) { - extractNativeLib("linux", "bulletjme64", true, false); - } - break; - case Linux32: - if (needLWJGL) { - extractNativeLib("linux", "lwjgl"); - } - if (needJInput) { - extractNativeLib("linux", "jinput-linux"); - } - if (needOAL) { - extractNativeLib("linux", "openal"); - } - if (needNativeBullet) { - extractNativeLib("linux", "bulletjme", true, false); - } - break; - case MacOSX_PPC32: - case MacOSX32: - case MacOSX_PPC64: - case MacOSX64: - if (needLWJGL) { - extractNativeLib("macosx", "lwjgl"); - } - if (needOAL){ - extractNativeLib("macosx", "openal.dylib"); - } - if (needJInput) { - extractNativeLib("macosx", "jinput-osx"); - } - if (needNativeBullet) { - extractNativeLib("macosx", "bulletjme", true, false); - } - break; - } - } -} diff --git a/jme3-examples/build.gradle b/jme3-examples/build.gradle index ce7a7cbd6..be2e106a6 100644 --- a/jme3-examples/build.gradle +++ b/jme3-examples/build.gradle @@ -12,7 +12,9 @@ task run(dependsOn: 'build', type:JavaExec) { jvmArgs "-Djava.awt.headless=true" } - systemProperty "java.util.logging.config.file", System.getProperty("java.util.logging.config.file") + if (System.properties['java.util.logging.config.file'] != null) { + systemProperty "java.util.logging.config.file", System.properties['java.util.logging.config.file'] + } if( assertions == "true" ){ enableAssertions = true; diff --git a/jme3-examples/src/main/java/jme3test/animation/TestCameraMotionPath.java b/jme3-examples/src/main/java/jme3test/animation/TestCameraMotionPath.java index ffe65a888..baeb41a31 100644 --- a/jme3-examples/src/main/java/jme3test/animation/TestCameraMotionPath.java +++ b/jme3-examples/src/main/java/jme3test/animation/TestCameraMotionPath.java @@ -139,7 +139,8 @@ public class TestCameraMotionPath extends SimpleApplication { rootNode.attachChild(teapot); - Geometry soil = new Geometry("soil", new Box(new Vector3f(0, -1.0f, 0), 50, 1, 50)); + Geometry soil = new Geometry("soil", new Box(50, 1, 50)); + soil.setLocalTranslation(0, -1, 0); soil.setMaterial(matSoil); rootNode.attachChild(soil); DirectionalLight light = new DirectionalLight(); diff --git a/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java b/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java index f0200bc91..a066426e4 100644 --- a/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java +++ b/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java @@ -222,7 +222,8 @@ public class TestCinematic extends SimpleApplication { matSoil.setColor("Diffuse", ColorRGBA.Green); matSoil.setColor("Specular", ColorRGBA.Black); - Geometry soil = new Geometry("soil", new Box(new Vector3f(0, -6.0f, 0), 50, 1, 50)); + Geometry soil = new Geometry("soil", new Box(50, 1, 50)); + soil.setLocalTranslation(0, -6, 0); soil.setMaterial(matSoil); soil.setShadowMode(ShadowMode.Receive); rootNode.attachChild(soil); diff --git a/jme3-examples/src/main/java/jme3test/animation/TestMotionPath.java b/jme3-examples/src/main/java/jme3test/animation/TestMotionPath.java index 57584f7c5..51268b6bc 100644 --- a/jme3-examples/src/main/java/jme3test/animation/TestMotionPath.java +++ b/jme3-examples/src/main/java/jme3test/animation/TestMotionPath.java @@ -136,7 +136,8 @@ public class TestMotionPath extends SimpleApplication { rootNode.attachChild(teapot); - Geometry soil = new Geometry("soil", new Box(new Vector3f(0, -1.0f, 0), 50, 1, 50)); + Geometry soil = new Geometry("soil", new Box(50, 1, 50)); + soil.setLocalTranslation(0, -1, 0); soil.setMaterial(matSoil); rootNode.attachChild(soil); diff --git a/jme3-examples/src/main/java/jme3test/app/TestAppStateLifeCycle.java b/jme3-examples/src/main/java/jme3test/app/TestAppStateLifeCycle.java index f22424252..ebca77683 100644 --- a/jme3-examples/src/main/java/jme3test/app/TestAppStateLifeCycle.java +++ b/jme3-examples/src/main/java/jme3test/app/TestAppStateLifeCycle.java @@ -57,7 +57,7 @@ public class TestAppStateLifeCycle extends SimpleApplication { @Override public void simpleInitApp() { - Box b = new Box(Vector3f.ZERO, 1, 1, 1); + Box b = new Box(1, 1, 1); Geometry geom = new Geometry("Box", b); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); diff --git a/jme3-examples/src/main/java/jme3test/app/TestBareBonesApp.java b/jme3-examples/src/main/java/jme3test/app/TestBareBonesApp.java index 5d3298279..491f4817b 100644 --- a/jme3-examples/src/main/java/jme3test/app/TestBareBonesApp.java +++ b/jme3-examples/src/main/java/jme3test/app/TestBareBonesApp.java @@ -56,7 +56,7 @@ public class TestBareBonesApp extends LegacyApplication { System.out.println("Initialize"); // create a box - boxGeom = new Geometry("Box", new Box(Vector3f.ZERO, 2, 2, 2)); + boxGeom = new Geometry("Box", new Box(2, 2, 2)); // load some default material boxGeom.setMaterial(assetManager.loadMaterial("Interface/Logo/Logo.j3m")); diff --git a/jme3-examples/src/main/java/jme3test/app/TestNativeLoader.java b/jme3-examples/src/main/java/jme3test/app/TestNativeLoader.java deleted file mode 100644 index 2854fd217..000000000 --- a/jme3-examples/src/main/java/jme3test/app/TestNativeLoader.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2009-2012 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 jme3test.app; - -import com.jme3.system.NativeLibraryLoader; -import java.io.File; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Try to load some natives. - * - * @author Kirill Vainer - */ -public class TestNativeLoader { - - private static final File WORKING_FOLDER = new File(System.getProperty("user.dir")); - - private static void tryLoadLwjgl() { - NativeLibraryLoader.loadNativeLibrary("lwjgl", true); - System.out.println("Succeeded in loading LWJGL.\n\tVersion: " + - org.lwjgl.Sys.getVersion()); - } - - private static void tryLoadJinput() { - NativeLibraryLoader.loadNativeLibrary("jinput", true); - NativeLibraryLoader.loadNativeLibrary("jinput-dx8", true); - - net.java.games.input.ControllerEnvironment ce = - net.java.games.input.ControllerEnvironment.getDefaultEnvironment(); - if (ce.isSupported()) { - net.java.games.input.Controller[] c = - ce.getControllers(); - - System.out.println("Succeeded in loading JInput.\n\tVersion: " + - net.java.games.util.Version.getVersion()); - } - } - - private static void tryLoadOpenAL() { - NativeLibraryLoader.loadNativeLibrary("openal", true); - - try { - org.lwjgl.openal.AL.create(); - String renderer = org.lwjgl.openal.AL10.alGetString(org.lwjgl.openal.AL10.AL_RENDERER); - String vendor = org.lwjgl.openal.AL10.alGetString(org.lwjgl.openal.AL10.AL_VENDOR); - String version = org.lwjgl.openal.AL10.alGetString(org.lwjgl.openal.AL10.AL_VERSION); - System.out.println("Succeeded in loading OpenAL."); - System.out.println("\tVersion: " + version); - } catch (org.lwjgl.LWJGLException ex) { - throw new RuntimeException(ex); - } finally { - if (org.lwjgl.openal.AL.isCreated()) { - org.lwjgl.openal.AL.destroy(); - } - } - } - - private static void tryLoadOpenGL() { - org.lwjgl.opengl.Pbuffer pb = null; - try { - pb = new org.lwjgl.opengl.Pbuffer(1, 1, new org.lwjgl.opengl.PixelFormat(0, 0, 0), null); - pb.makeCurrent(); - String version = org.lwjgl.opengl.GL11.glGetString(org.lwjgl.opengl.GL11.GL_VERSION); - System.out.println("Succeeded in loading OpenGL.\n\tVersion: " + version); - } catch (org.lwjgl.LWJGLException ex) { - throw new RuntimeException(ex); - } finally { - if (pb != null) { - pb.destroy(); - } - } - } - - private static void tryLoadBulletJme() { - if (NativeLibraryLoader.isUsingNativeBullet()) { - NativeLibraryLoader.loadNativeLibrary("bulletjme", true); - - com.jme3.bullet.PhysicsSpace physSpace = new com.jme3.bullet.PhysicsSpace(); - - System.out.println("Succeeded in loading BulletJme."); - } else { - System.out.println("Native bullet not included. Cannot test loading."); - } - } - - private static void cleanupNativesFolder(File folder) { - for (File file : folder.listFiles()) { - String lowerCaseName = file.getName().toLowerCase(); - if (lowerCaseName.contains("lwjgl") || - lowerCaseName.contains("jinput") || - lowerCaseName.contains("openal") || - lowerCaseName.contains("bulletjme")) { - file.delete(); - } - } - } - - public static void main(String[] args) { - Logger.getLogger("").getHandlers()[0].setLevel(Level.WARNING); - Logger.getLogger(NativeLibraryLoader.class.getName()).setLevel(Level.ALL); - - // Get a bit more output from LWJGL about issues. - // System.setProperty("org.lwjgl.util.Debug", "true"); - - // Extracting to working folder is no brainer. - // Choose some random path, then load LWJGL. - File customNativesFolder = new File("CustomNativesFolder"); - customNativesFolder.mkdirs(); - - if (!customNativesFolder.isDirectory()) { - throw new IllegalStateException("Failed to make custom natives folder"); - } - - // Let's cleanup our folders first. - cleanupNativesFolder(WORKING_FOLDER); - cleanupNativesFolder(customNativesFolder); - - NativeLibraryLoader.setCustomExtractionFolder(customNativesFolder.getAbsolutePath()); - - tryLoadLwjgl(); - tryLoadOpenGL(); - tryLoadOpenAL(); - tryLoadJinput(); - tryLoadBulletJme(); - } -} diff --git a/jme3-examples/src/main/java/jme3test/app/TestReleaseDirectMemory.java b/jme3-examples/src/main/java/jme3test/app/TestReleaseDirectMemory.java index 280212b71..28947c400 100644 --- a/jme3-examples/src/main/java/jme3test/app/TestReleaseDirectMemory.java +++ b/jme3-examples/src/main/java/jme3test/app/TestReleaseDirectMemory.java @@ -50,7 +50,7 @@ public class TestReleaseDirectMemory extends SimpleApplication { @Override public void simpleInitApp() { - Box b = new Box(Vector3f.ZERO, 1, 1, 1); + Box b = new Box(1, 1, 1); Geometry geom = new Geometry("Box", b); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); diff --git a/jme3-examples/src/main/java/jme3test/audio/TestAmbient.java b/jme3-examples/src/main/java/jme3test/audio/TestAmbient.java index cf90cc96a..2703d53da 100644 --- a/jme3-examples/src/main/java/jme3test/audio/TestAmbient.java +++ b/jme3-examples/src/main/java/jme3test/audio/TestAmbient.java @@ -69,7 +69,7 @@ public class TestAmbient extends SimpleApplication { nature.play(); // just a blue box to mark the spot - Box box1 = new Box(Vector3f.ZERO, .5f, .5f, .5f); + Box box1 = new Box(.5f, .5f, .5f); Geometry player = new Geometry("Player", box1); Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); diff --git a/jme3-examples/src/main/java/jme3test/audio/TestDoppler.java b/jme3-examples/src/main/java/jme3test/audio/TestDoppler.java index 60136bcff..1065e1cee 100644 --- a/jme3-examples/src/main/java/jme3test/audio/TestDoppler.java +++ b/jme3-examples/src/main/java/jme3test/audio/TestDoppler.java @@ -33,72 +33,62 @@ package jme3test.audio; import com.jme3.app.SimpleApplication; +import com.jme3.audio.AudioData; import com.jme3.audio.AudioNode; -import com.jme3.audio.Environment; import com.jme3.math.FastMath; import com.jme3.math.Vector3f; -import org.lwjgl.openal.AL10; -import org.lwjgl.openal.AL11; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Torus; /** * Test Doppler Effect */ public class TestDoppler extends SimpleApplication { - private AudioNode ufo; + private float pos = -5; + private float vel = 5; + private AudioNode ufoNode; - private float x = 20, z = 0; - private float rate = -0.05f; - private float xDist = 20; - private float zDist = 5; - private float angle = FastMath.TWO_PI; - public static void main(String[] args){ TestDoppler test = new TestDoppler(); test.start(); } @Override - public void simpleInitApp(){ - audioRenderer.setEnvironment(Environment.Dungeon); - AL10.alDistanceModel(AL11.AL_EXPONENT_DISTANCE); - - ufo = new AudioNode(assetManager, "Sound/Effects/Beep.ogg", false); - ufo.setPositional(true); - ufo.setLooping(true); - ufo.setReverbEnabled(true); - ufo.setRefDistance(100000000); - ufo.setMaxDistance(100000000); - ufo.play(); + public void simpleInitApp() { + flyCam.setMoveSpeed(10); + + Torus torus = new Torus(10, 6, 1, 3); + Geometry g = new Geometry("Torus Geom", torus); + g.rotate(-FastMath.HALF_PI, 0, 0); + g.center(); + + g.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); +// rootNode.attachChild(g); + + ufoNode = new AudioNode(assetManager, "Sound/Effects/Beep.ogg", AudioData.DataType.Buffer); + ufoNode.setLooping(true); + ufoNode.setPitch(0.5f); + ufoNode.setRefDistance(1); + ufoNode.setMaxDistance(100000000); + ufoNode.setVelocityFromTranslation(true); + ufoNode.play(); + + Geometry ball = new Geometry("Beeper", new Sphere(10, 10, 0.1f)); + ball.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + ufoNode.attachChild(ball); + + rootNode.attachChild(ufoNode); } + @Override - public void simpleUpdate(float tpf){ - //float x = (float) (Math.cos(angle) * xDist); - float dx = (float) Math.sin(angle) * xDist; - - //float z = (float) (Math.sin(angle) * zDist); - float dz = (float)(-Math.cos(angle) * zDist); - - x += dx * tpf * 0.05f; - z += dz * tpf * 0.05f; - - angle += tpf * rate; - - if (angle > FastMath.TWO_PI){ - angle = FastMath.TWO_PI; - rate = -rate; - }else if (angle < -0){ - angle = -0; - rate = -rate; + public void simpleUpdate(float tpf) { + pos += tpf * vel; + if (pos < -10 || pos > 10) { + vel *= -1; } - - ufo.setVelocity(new Vector3f(dx, 0, dz)); - ufo.setLocalTranslation(x, 0, z); - ufo.updateGeometricState(); - - System.out.println("LOC: " + (int)x +", " + (int)z + - ", VEL: " + (int)dx + ", " + (int)dz); + ufoNode.setLocalTranslation(new Vector3f(pos, 0, 0)); } - } diff --git a/jme3-examples/src/main/java/jme3test/audio/TestOgg.java b/jme3-examples/src/main/java/jme3test/audio/TestOgg.java index 2d2343c11..3e4099c66 100644 --- a/jme3-examples/src/main/java/jme3test/audio/TestOgg.java +++ b/jme3-examples/src/main/java/jme3test/audio/TestOgg.java @@ -33,6 +33,7 @@ package jme3test.audio; import com.jme3.app.SimpleApplication; +import com.jme3.audio.AudioData.DataType; import com.jme3.audio.AudioNode; import com.jme3.audio.AudioSource; import com.jme3.audio.LowPassFilter; @@ -49,7 +50,7 @@ public class TestOgg extends SimpleApplication { @Override public void simpleInitApp(){ System.out.println("Playing without filter"); - audioSource = new AudioNode(assetManager, "Sound/Effects/Foot steps.ogg", true); + audioSource = new AudioNode(assetManager, "Sound/Effects/Foot steps.ogg", DataType.Buffer); audioSource.play(); } @@ -59,7 +60,7 @@ public class TestOgg extends SimpleApplication { audioRenderer.deleteAudioData(audioSource.getAudioData()); System.out.println("Playing with low pass filter"); - audioSource = new AudioNode(assetManager, "Sound/Effects/Foot steps.ogg", true); + audioSource = new AudioNode(assetManager, "Sound/Effects/Foot steps.ogg", DataType.Buffer); audioSource.setDryFilter(new LowPassFilter(1f, .1f)); audioSource.setVolume(3); audioSource.play(); diff --git a/jme3-examples/src/main/java/jme3test/awt/TestAwtPanels.java b/jme3-examples/src/main/java/jme3test/awt/TestAwtPanels.java index 0f47d0c26..5c00e5008 100644 --- a/jme3-examples/src/main/java/jme3test/awt/TestAwtPanels.java +++ b/jme3-examples/src/main/java/jme3test/awt/TestAwtPanels.java @@ -90,7 +90,7 @@ public class TestAwtPanels extends SimpleApplication { public void simpleInitApp() { flyCam.setDragToRotate(true); - Box b = new Box(Vector3f.ZERO, 1, 1, 1); + Box b = new Box(1, 1, 1); Geometry geom = new Geometry("Box", b); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); diff --git a/jme3-examples/src/main/java/jme3test/awt/TestSafeCanvas.java b/jme3-examples/src/main/java/jme3test/awt/TestSafeCanvas.java index 88451f5d7..6264f8246 100644 --- a/jme3-examples/src/main/java/jme3test/awt/TestSafeCanvas.java +++ b/jme3-examples/src/main/java/jme3test/awt/TestSafeCanvas.java @@ -59,7 +59,7 @@ public class TestSafeCanvas extends SimpleApplication { public void simpleInitApp() { flyCam.setDragToRotate(true); - Box b = new Box(Vector3f.ZERO, 1, 1, 1); + Box b = new Box(1, 1, 1); Geometry geom = new Geometry("Box", b); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); diff --git a/jme3-examples/src/main/java/jme3test/batching/TestBatchNode.java b/jme3-examples/src/main/java/jme3test/batching/TestBatchNode.java index af0292864..db7e7a85e 100644 --- a/jme3-examples/src/main/java/jme3test/batching/TestBatchNode.java +++ b/jme3-examples/src/main/java/jme3test/batching/TestBatchNode.java @@ -82,7 +82,7 @@ public class TestBatchNode extends SimpleApplication { * A cube with a color "bleeding" through transparent texture. Uses * Texture from jme3-test-data library! */ - Box boxshape4 = new Box(Vector3f.ZERO, 1f, 1f, 1f); + Box boxshape4 = new Box(1f, 1f, 1f); cube = new Geometry("cube1", boxshape4); Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); cube.setMaterial(mat); @@ -93,7 +93,7 @@ public class TestBatchNode extends SimpleApplication { * A cube with a color "bleeding" through transparent texture. Uses * Texture from jme3-test-data library! */ - Box box = new Box(Vector3f.ZERO, 1f, 1f, 1f); + Box box = new Box(1f, 1f, 1f); cube2 = new Geometry("cube2", box); cube2.setMaterial(mat); diff --git a/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeCluster.java b/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeCluster.java index 4559acfdc..3d88fb408 100644 --- a/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeCluster.java +++ b/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeCluster.java @@ -166,7 +166,7 @@ public class TestBatchNodeCluster extends SimpleApplication { public void randomGenerator() { for (int i = startAt; i < maxCubes - 1; i++) { randomize(); - Geometry box = new Geometry("Box" + i, new Box(Vector3f.ZERO, 1, 1, 1)); + Geometry box = new Geometry("Box" + i, new Box(1, 1, 1)); box.setLocalTranslation(new Vector3f(xPosition.get(xPosition.size() - 1), yPosition.get(yPosition.size() - 1), zPosition.get(zPosition.size() - 1))); diff --git a/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeTower.java b/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeTower.java index 0147c4435..a13dc6168 100644 --- a/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeTower.java +++ b/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeTower.java @@ -193,7 +193,7 @@ public class TestBatchNodeTower extends SimpleApplication { } public void initFloor() { - Box floorBox = new Box(Vector3f.ZERO, 10f, 0.1f, 5f); + Box floorBox = new Box(10f, 0.1f, 5f); floorBox.scaleTextureCoordinates(new Vector2f(3, 6)); Geometry floor = new Geometry("floor", floorBox); diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestAttachDriver.java b/jme3-examples/src/main/java/jme3test/bullet/TestAttachDriver.java index 8f9447ea1..1de5b0118 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestAttachDriver.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestAttachDriver.java @@ -112,7 +112,7 @@ public class TestAttachDriver extends SimpleApplication implements ActionListene tex.setMinFilter(Texture.MinFilter.Trilinear); mat.setTexture("ColorMap", tex); - Box floor = new Box(Vector3f.ZERO, 100, 1f, 100); + Box floor = new Box(100, 1f, 100); Geometry floorGeom = new Geometry("Floor", floor); floorGeom.setMaterial(mat); floorGeom.setLocalTranslation(new Vector3f(0f, -3, 0f)); diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestBrickTower.java b/jme3-examples/src/main/java/jme3test/bullet/TestBrickTower.java index bcadf623d..7b0df933d 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestBrickTower.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestBrickTower.java @@ -126,7 +126,7 @@ public class TestBrickTower extends SimpleApplication { bullet.setTextureMode(TextureMode.Projected); bulletCollisionShape = new SphereCollisionShape(0.4f); - brick = new Box(Vector3f.ZERO, brickWidth, brickHeight, brickDepth); + brick = new Box(brickWidth, brickHeight, brickDepth); brick.scaleTextureCoordinates(new Vector2f(1f, .5f)); //bulletAppState.getPhysicsSpace().enableDebug(assetManager); initMaterial(); @@ -204,7 +204,7 @@ public class TestBrickTower extends SimpleApplication { } public void initFloor() { - Box floorBox = new Box(Vector3f.ZERO, 10f, 0.1f, 5f); + Box floorBox = new Box(10f, 0.1f, 5f); floorBox.scaleTextureCoordinates(new Vector2f(3, 6)); Geometry floor = new Geometry("floor", floorBox); diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestBrickWall.java b/jme3-examples/src/main/java/jme3test/bullet/TestBrickWall.java index b190e8c6c..0173f1a44 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestBrickWall.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestBrickWall.java @@ -90,7 +90,7 @@ public class TestBrickWall extends SimpleApplication { bullet = new Sphere(32, 32, 0.4f, true, false); bullet.setTextureMode(TextureMode.Projected); bulletCollisionShape = new SphereCollisionShape(0.4f); - brick = new Box(Vector3f.ZERO, bLength, bHeight, bWidth); + brick = new Box(bLength, bHeight, bWidth); brick.scaleTextureCoordinates(new Vector2f(1f, .5f)); initMaterial(); @@ -151,7 +151,7 @@ public class TestBrickWall extends SimpleApplication { } public void initFloor() { - Box floorBox = new Box(Vector3f.ZERO, 10f, 0.1f, 5f); + Box floorBox = new Box(10f, 0.1f, 5f); floorBox.scaleTextureCoordinates(new Vector2f(3, 6)); Geometry floor = new Geometry("floor", floorBox); diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestCcd.java b/jme3-examples/src/main/java/jme3test/bullet/TestCcd.java index cda07bc85..58cb77c65 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestCcd.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestCcd.java @@ -98,7 +98,7 @@ public class TestCcd extends SimpleApplication implements ActionListener { Node node2 = new Node(); node2.setName("mesh"); node2.setLocalTranslation(new Vector3f(2.5f, 0, 0f)); - node2.addControl(new RigidBodyControl(new MeshCollisionShape(new Box(Vector3f.ZERO, 4, 4, 0.1f)), 0)); + node2.addControl(new RigidBodyControl(new MeshCollisionShape(new Box(4, 4, 0.1f)), 0)); rootNode.attachChild(node2); getPhysicsSpace().add(node2); diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestCollisionGroups.java b/jme3-examples/src/main/java/jme3test/bullet/TestCollisionGroups.java index 410c125d2..516345d47 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestCollisionGroups.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestCollisionGroups.java @@ -85,7 +85,7 @@ public class TestCollisionGroups extends SimpleApplication { getPhysicsSpace().add(node2); // the floor, does not move (mass=0) - Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Box(Vector3f.ZERO, 100f, 0.2f, 100f)), 0); + Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Box(100f, 0.2f, 100f)), 0); node3.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -6, 0f)); rootNode.attachChild(node3); getPhysicsSpace().add(node3); diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestGhostObject.java b/jme3-examples/src/main/java/jme3test/bullet/TestGhostObject.java index 74a7c1e1e..2ea1af0ab 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestGhostObject.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestGhostObject.java @@ -65,7 +65,7 @@ public class TestGhostObject extends SimpleApplication { bulletAppState.setDebugEnabled(true); // Mesh to be shared across several boxes. - Box boxGeom = new Box(Vector3f.ZERO, 1f, 1f, 1f); + Box boxGeom = new Box(1f, 1f, 1f); // CollisionShape to be shared across several boxes. CollisionShape shape = new BoxCollisionShape(new Vector3f(1, 1, 1)); diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java b/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java index 9785ed250..5b9e948c8 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java @@ -139,7 +139,7 @@ public class TestRagdollCharacter extends SimpleApplication implements AnimEvent } public void initWall(float bLength, float bWidth, float bHeight) { - Box brick = new Box(Vector3f.ZERO, bLength, bHeight, bWidth); + Box brick = new Box(bLength, bHeight, bWidth); brick.scaleTextureCoordinates(new Vector2f(1f, .5f)); Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg"); diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java b/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java index a66a6ecc1..c7e937c0b 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java @@ -171,7 +171,7 @@ public class TestWalkingChar extends SimpleApplication implements ActionListener float zOff = -40; float startpt = bLength / 4 - xOff; float height = 6.1f; - brick = new Box(Vector3f.ZERO, bLength, bHeight, bWidth); + brick = new Box(bLength, bHeight, bWidth); brick.scaleTextureCoordinates(new Vector2f(1f, .5f)); for (int j = 0; j < 15; j++) { for (int i = 0; i < 4; i++) { diff --git a/jme3-examples/src/main/java/jme3test/collision/TestMousePick.java b/jme3-examples/src/main/java/jme3test/collision/TestMousePick.java index f86f956b6..9f58b7fd8 100644 --- a/jme3-examples/src/main/java/jme3test/collision/TestMousePick.java +++ b/jme3-examples/src/main/java/jme3test/collision/TestMousePick.java @@ -107,8 +107,9 @@ public class TestMousePick extends SimpleApplication { /** A cube object for target practice */ protected Geometry makeCube(String name, float x, float y, float z) { - Box box = new Box(new Vector3f(x, y, z), 1, 1, 1); + Box box = new Box(1, 1, 1); Geometry cube = new Geometry(name, box); + cube.setLocalTranslation(x, y, z); Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat1.setColor("Color", ColorRGBA.randomColor()); cube.setMaterial(mat1); @@ -117,8 +118,9 @@ public class TestMousePick extends SimpleApplication { /** A floor to show that the "shot" can go through several objects. */ protected Geometry makeFloor() { - Box box = new Box(new Vector3f(0, -4, -5), 15, .2f, 15); + Box box = new Box(15, .2f, 15); Geometry floor = new Geometry("the Floor", box); + floor.setLocalTranslation(0, -4, -5); Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat1.setColor("Color", ColorRGBA.Gray); floor.setMaterial(mat1); diff --git a/jme3-examples/src/main/java/jme3test/effect/TestEverything.java b/jme3-examples/src/main/java/jme3test/effect/TestEverything.java index 2aca26f5e..be05958c3 100644 --- a/jme3-examples/src/main/java/jme3test/effect/TestEverything.java +++ b/jme3-examples/src/main/java/jme3test/effect/TestEverything.java @@ -123,11 +123,7 @@ public class TestEverything extends SimpleApplication { public void setupFloor(){ Material mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"); - mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat); - mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat); - mat.getTextureParam("ParallaxMap").getTextureValue().setWrap(WrapMode.Repeat); - - Box floor = new Box(Vector3f.ZERO, 50, 1f, 50); + Box floor = new Box(50, 1f, 50); TangentBinormalGenerator.generate(floor); floor.scaleTextureCoordinates(new Vector2f(5, 5)); Geometry floorGeom = new Geometry("Floor", floor); diff --git a/jme3-examples/src/main/java/jme3test/effect/TestSoftParticles.java b/jme3-examples/src/main/java/jme3test/effect/TestSoftParticles.java index 3d8f96d65..71504e51a 100644 --- a/jme3-examples/src/main/java/jme3test/effect/TestSoftParticles.java +++ b/jme3-examples/src/main/java/jme3test/effect/TestSoftParticles.java @@ -76,7 +76,7 @@ public class TestSoftParticles extends SimpleApplication { // -------- floor - Box b = new Box(Vector3f.ZERO, 10, 0.1f, 10); + Box b = new Box(10, 0.1f, 10); Geometry geom = new Geometry("Box", b); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setColor("Color", ColorRGBA.Gray); @@ -84,7 +84,7 @@ public class TestSoftParticles extends SimpleApplication { geom.setMaterial(mat); rootNode.attachChild(geom); - Box b2 = new Box(Vector3f.ZERO, 1, 1, 1); + Box b2 = new Box(1, 1, 1); Geometry geom2 = new Geometry("Box", b2); Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat2.setColor("Color", ColorRGBA.DarkGray); diff --git a/jme3-examples/src/main/java/jme3test/games/CubeField.java b/jme3-examples/src/main/java/jme3test/games/CubeField.java index fdad49de6..c166b5823 100644 --- a/jme3-examples/src/main/java/jme3test/games/CubeField.java +++ b/jme3-examples/src/main/java/jme3test/games/CubeField.java @@ -197,9 +197,9 @@ public class CubeField extends SimpleApplication implements AnalogListener { private Geometry createFirstCube() { Vector3f loc = player.getLocalTranslation(); loc.addLocal(4, 0, 0); - Box b = new Box(loc, 1, 1, 1); - + Box b = new Box(1, 1, 1); Geometry geom = new Geometry("Box", b); + geom.setLocalTranslation(loc); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setColor("Color", ColorRGBA.Blue); geom.setMaterial(mat); @@ -216,10 +216,15 @@ public class CubeField extends SimpleApplication implements AnalogListener { playerMesh.setMaterial(playerMaterial); playerMesh.setName("player"); - Box floor = new Box(Vector3f.ZERO.add(playerMesh.getLocalTranslation().getX(), - playerMesh.getLocalTranslation().getY() - 1, 0), 100, 0, 100); + Box floor = new Box(100, 0, 100); + Geometry floorMesh = new Geometry("Box", floor); + Vector3f translation = Vector3f.ZERO.add(playerMesh.getLocalTranslation().getX(), + playerMesh.getLocalTranslation().getY() - 1, 0); + + floorMesh.setLocalTranslation(translation); + floorMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); floorMaterial.setColor("Color", ColorRGBA.LightGray); floorMesh.setMaterial(floorMaterial); diff --git a/jme3-examples/src/main/java/jme3test/helloworld/HelloAssets.java b/jme3-examples/src/main/java/jme3test/helloworld/HelloAssets.java index 9a3085016..4fb4738ac 100644 --- a/jme3-examples/src/main/java/jme3test/helloworld/HelloAssets.java +++ b/jme3-examples/src/main/java/jme3test/helloworld/HelloAssets.java @@ -60,7 +60,7 @@ public class HelloAssets extends SimpleApplication { rootNode.attachChild(teapot); /** Create a wall (Box with material and texture from test-data) */ - Box box = new Box(Vector3f.ZERO, 2.5f,2.5f,1.0f); + Box box = new Box(2.5f, 2.5f, 1.0f); Spatial wall = new Geometry("Box", box ); Material mat_brick = new Material( assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat_brick.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg")); diff --git a/jme3-examples/src/main/java/jme3test/helloworld/HelloInput.java b/jme3-examples/src/main/java/jme3test/helloworld/HelloInput.java index 4cf09fe6e..c01bfb31c 100644 --- a/jme3-examples/src/main/java/jme3test/helloworld/HelloInput.java +++ b/jme3-examples/src/main/java/jme3test/helloworld/HelloInput.java @@ -57,7 +57,7 @@ public class HelloInput extends SimpleApplication { @Override public void simpleInitApp() { - Box b = new Box(Vector3f.ZERO, 1, 1, 1); + Box b = new Box(1, 1, 1); player = new Geometry("Player", b); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setColor("Color", ColorRGBA.Blue); diff --git a/jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java b/jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java index 14f220374..7e5d30a6d 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java +++ b/jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java @@ -127,9 +127,10 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act t.setLocalTranslation(FastMath.nextRandomFloat() * 200f, FastMath.nextRandomFloat() * 30f + 20, 30f * (i + 2f)); } - Box b = new Box(new Vector3f(0, 10, 550), 1000, 2, 1000); + Box b = new Box(1000, 2, 1000); b.scaleTextureCoordinates(new Vector2f(10, 10)); ground = new Geometry("soil", b); + ground.setLocalTranslation(0, 10, 550); matGroundU = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); matGroundU.setColor("Color", ColorRGBA.Green); diff --git a/jme3-examples/src/main/java/jme3test/light/TestPssmShadow.java b/jme3-examples/src/main/java/jme3test/light/TestPssmShadow.java index 55d5a3f87..9f851d39c 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestPssmShadow.java +++ b/jme3-examples/src/main/java/jme3test/light/TestPssmShadow.java @@ -113,9 +113,10 @@ public class TestPssmShadow extends SimpleApplication implements ActionListener t.setLocalTranslation(FastMath.nextRandomFloat() * 200f, FastMath.nextRandomFloat() * 30f + 20, 30f * (i + 2f)); } - Box b = new Box(new Vector3f(0, 10, 550), 1000, 2, 1000); + Box b = new Box(1000, 2, 1000); b.scaleTextureCoordinates(new Vector2f(10, 10)); ground = new Geometry("soil", b); + ground.setLocalTranslation(0, 10, 550); matGroundU = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); matGroundU.setColor("Color", ColorRGBA.Green); diff --git a/jme3-examples/src/main/java/jme3test/light/TestShadow.java b/jme3-examples/src/main/java/jme3test/light/TestShadow.java index db0c3768f..d3c7122fb 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestShadow.java +++ b/jme3-examples/src/main/java/jme3test/light/TestShadow.java @@ -76,7 +76,7 @@ public class TestShadow extends SimpleApplication { Material mat = assetManager.loadMaterial("Common/Materials/WhiteColor.j3m"); rootNode.setShadowMode(ShadowMode.Off); - Box floor = new Box(Vector3f.ZERO, 3, 0.1f, 3); + Box floor = new Box(3, 0.1f, 3); Geometry floorGeom = new Geometry("Floor", floor); floorGeom.setMaterial(mat); floorGeom.setLocalTranslation(0,-0.2f,0); diff --git a/jme3-examples/src/main/java/jme3test/light/TestShadowsPerf.java b/jme3-examples/src/main/java/jme3test/light/TestShadowsPerf.java index e9ca341b8..f267b1d41 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestShadowsPerf.java +++ b/jme3-examples/src/main/java/jme3test/light/TestShadowsPerf.java @@ -83,7 +83,7 @@ public class TestShadowsPerf extends SimpleApplication { mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); - Box b = new Box(Vector3f.ZERO, 800, 1, 700); + Box b = new Box(800, 1, 700); b.scaleTextureCoordinates(new Vector2f(50, 50)); Geometry ground = new Geometry("ground", b); ground.setMaterial(mat); diff --git a/jme3-examples/src/main/java/jme3test/light/TestSpotLight.java b/jme3-examples/src/main/java/jme3test/light/TestSpotLight.java index 7a6f35c37..0cd4512cd 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestSpotLight.java +++ b/jme3-examples/src/main/java/jme3test/light/TestSpotLight.java @@ -100,7 +100,7 @@ public class TestSpotLight extends SimpleApplication { // mat.setBoolean("VertexLighting", true); - Box floor = new Box(Vector3f.ZERO, 50, 1f, 50); + Box floor = new Box(50, 1f, 50); TangentBinormalGenerator.generate(floor); floor.scaleTextureCoordinates(new Vector2f(5, 5)); Geometry floorGeom = new Geometry("Floor", floor); diff --git a/jme3-examples/src/main/java/jme3test/light/TestSpotLightShadows.java b/jme3-examples/src/main/java/jme3test/light/TestSpotLightShadows.java index 8df514fd3..52a5dc8c5 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestSpotLightShadows.java +++ b/jme3-examples/src/main/java/jme3test/light/TestSpotLightShadows.java @@ -148,7 +148,7 @@ public class TestSpotLightShadows extends SimpleApplication { // mat.setBoolean("VertexLighting", true); - Box floor = new Box(Vector3f.ZERO, 50, 1f, 50); + Box floor = new Box(50, 1f, 50); TangentBinormalGenerator.generate(floor); floor.scaleTextureCoordinates(new Vector2f(5, 5)); Geometry floorGeom = new Geometry("Floor", floor); diff --git a/jme3-examples/src/main/java/jme3test/material/TestMatParamOverride.java b/jme3-examples/src/main/java/jme3test/material/TestMatParamOverride.java new file mode 100644 index 000000000..224290f25 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/material/TestMatParamOverride.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2009-2016 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 jme3test.material; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.MatParamOverride; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.shader.VarType; + +/** + * Test if {@link MatParamOverride}s are working correctly. + * + * @author Kirill Vainer + */ +public class TestMatParamOverride extends SimpleApplication { + + private Box box = new Box(1, 1, 1); + private MatParamOverride override = new MatParamOverride(VarType.Vector4, "Color", ColorRGBA.Yellow); + + public static void main(String[] args) { + TestMatParamOverride app = new TestMatParamOverride(); + app.start(); + } + + private void createBox(float location, ColorRGBA color) { + Geometry geom = new Geometry("Box", box); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", color); + geom.setMaterial(mat); + geom.move(location, 0, 0); + rootNode.attachChild(geom); + } + + @Override + public void simpleInitApp() { + inputManager.setCursorVisible(true); + + createBox(-3, ColorRGBA.Red); + createBox(0, ColorRGBA.Green); + createBox(3, ColorRGBA.Blue); + + inputManager.addMapping("override", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("override") && isPressed) { + if (!rootNode.getLocalMatParamOverrides().isEmpty()) { + rootNode.clearMatParamOverrides(); + } else { + rootNode.addMatParamOverride(override); + } + System.out.println(rootNode.getLocalMatParamOverrides()); + } + } + }, "override"); + } +} diff --git a/jme3-examples/src/main/java/jme3test/material/TestParallax.java b/jme3-examples/src/main/java/jme3test/material/TestParallax.java index f5af57f1f..cf5263ed2 100644 --- a/jme3-examples/src/main/java/jme3test/material/TestParallax.java +++ b/jme3-examples/src/main/java/jme3test/material/TestParallax.java @@ -71,8 +71,7 @@ public class TestParallax extends SimpleApplication { Material mat; public void setupFloor() { - mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall2.j3m"); - //mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"); + mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"); Node floorGeom = new Node("floorGeom"); Quad q = new Quad(100, 100); diff --git a/jme3-examples/src/main/java/jme3test/material/TestShaderNodes.java b/jme3-examples/src/main/java/jme3test/material/TestShaderNodes.java index db8a21c97..a580f54ed 100644 --- a/jme3-examples/src/main/java/jme3test/material/TestShaderNodes.java +++ b/jme3-examples/src/main/java/jme3test/material/TestShaderNodes.java @@ -3,6 +3,7 @@ package jme3test.material; import com.jme3.app.SimpleApplication; import com.jme3.material.Material; import com.jme3.material.Technique; +import com.jme3.material.TechniqueDef; import com.jme3.math.ColorRGBA; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; @@ -27,12 +28,12 @@ public class TestShaderNodes extends SimpleApplication { Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); Material mat = new Material(assetManager, "Common/MatDefs/Misc/UnshadedNodes.j3md"); - mat.selectTechnique("Default", renderManager); + mat.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); Technique t = mat.getActiveTechnique(); - for (Shader.ShaderSource shaderSource : t.getShader().getSources()) { - System.out.println(shaderSource.getSource()); - } +// for (Shader.ShaderSource shaderSource : t.getShader().getSources()) { +// System.out.println(shaderSource.getSource()); +// } mat.setColor("Color", ColorRGBA.Yellow); diff --git a/jme3-examples/src/main/java/jme3test/model/shape/TestBillboard.java b/jme3-examples/src/main/java/jme3test/model/shape/TestBillboard.java index ba7acb1f7..8fa8a66f1 100644 --- a/jme3-examples/src/main/java/jme3test/model/shape/TestBillboard.java +++ b/jme3-examples/src/main/java/jme3test/model/shape/TestBillboard.java @@ -64,8 +64,9 @@ public class TestBillboard extends SimpleApplication { g3.setMaterial(mat2); g3.setLocalTranslation(.5f, .5f, .01f); - Box b = new Box(new Vector3f(0, 0, 3), .25f, .5f, .25f); + Box b = new Box(.25f, .5f, .25f); Geometry g2 = new Geometry("Box", b); + g2.setLocalTranslation(0, 0, 3); g2.setMaterial(mat); Node bb = new Node("billboard"); diff --git a/jme3-examples/src/main/java/jme3test/model/shape/TestBox.java b/jme3-examples/src/main/java/jme3test/model/shape/TestBox.java index 19d26b5ac..0e5e86aef 100644 --- a/jme3-examples/src/main/java/jme3test/model/shape/TestBox.java +++ b/jme3-examples/src/main/java/jme3test/model/shape/TestBox.java @@ -34,7 +34,6 @@ package jme3test.model.shape; import com.jme3.app.SimpleApplication; import com.jme3.material.Material; -import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; diff --git a/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyGui.java b/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyGui.java index fe9171c92..3d2e67b5f 100644 --- a/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyGui.java +++ b/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyGui.java @@ -54,7 +54,7 @@ public class TestNiftyGui extends SimpleApplication implements ScreenController @Override public void simpleInitApp() { - Box b = new Box(Vector3f.ZERO, 1, 1, 1); + Box b = new Box(1, 1, 1); Geometry geom = new Geometry("Box", b); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); diff --git a/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyToMesh.java b/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyToMesh.java index ef82f263d..ce3832c73 100644 --- a/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyToMesh.java +++ b/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyToMesh.java @@ -79,7 +79,7 @@ public class TestNiftyToMesh extends SimpleApplication{ niftyView.setClearFlags(true, true, true); niftyView.setOutputFrameBuffer(fb); - Box b = new Box(Vector3f.ZERO, 1, 1, 1); + Box b = new Box(1, 1, 1); Geometry geom = new Geometry("Box", b); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setTexture("ColorMap", tex); diff --git a/jme3-examples/src/main/java/jme3test/post/TestBloom.java b/jme3-examples/src/main/java/jme3test/post/TestBloom.java index b73d234d7..1a394bf36 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestBloom.java +++ b/jme3-examples/src/main/java/jme3test/post/TestBloom.java @@ -102,7 +102,8 @@ public class TestBloom extends SimpleApplication { - Geometry soil=new Geometry("soil", new Box(new Vector3f(0, -13, 550), 800, 10, 700)); + Geometry soil = new Geometry("soil", new Box(800, 10, 700)); + soil.setLocalTranslation(0, -13, 550); soil.setMaterial(matSoil); soil.setShadowMode(ShadowMode.CastAndReceive); rootNode.attachChild(soil); diff --git a/jme3-examples/src/main/java/jme3test/post/TestCrossHatch.java b/jme3-examples/src/main/java/jme3test/post/TestCrossHatch.java index 2164ec229..ff3ef081c 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestCrossHatch.java +++ b/jme3-examples/src/main/java/jme3test/post/TestCrossHatch.java @@ -102,7 +102,8 @@ public class TestCrossHatch extends SimpleApplication { - Geometry soil=new Geometry("soil", new Box(new Vector3f(0, -13, 550), 800, 10, 700)); + Geometry soil = new Geometry("soil", new Box(800, 10, 700)); + soil.setLocalTranslation(0, -13, 550); soil.setMaterial(matSoil); soil.setShadowMode(ShadowMode.CastAndReceive); rootNode.attachChild(soil); diff --git a/jme3-examples/src/main/java/jme3test/post/TestPostFilters.java b/jme3-examples/src/main/java/jme3test/post/TestPostFilters.java index 4ad419668..3ab2ae295 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestPostFilters.java +++ b/jme3-examples/src/main/java/jme3test/post/TestPostFilters.java @@ -107,10 +107,7 @@ public class TestPostFilters extends SimpleApplication implements ActionListener public void setupFloor() { Material mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"); - mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat); - mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat); - mat.getTextureParam("ParallaxMap").getTextureValue().setWrap(WrapMode.Repeat); - Box floor = new Box(Vector3f.ZERO, 50, 1f, 50); + Box floor = new Box(50, 1f, 50); TangentBinormalGenerator.generate(floor); floor.scaleTextureCoordinates(new Vector2f(5, 5)); Geometry floorGeom = new Geometry("Floor", floor); diff --git a/jme3-examples/src/main/java/jme3test/post/TestPosterization.java b/jme3-examples/src/main/java/jme3test/post/TestPosterization.java index 4200ad463..ff8cf7ee8 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestPosterization.java +++ b/jme3-examples/src/main/java/jme3test/post/TestPosterization.java @@ -102,7 +102,8 @@ public class TestPosterization extends SimpleApplication { - Geometry soil=new Geometry("soil", new Box(new Vector3f(0, -13, 550), 800, 10, 700)); + Geometry soil = new Geometry("soil", new Box(800, 10, 700)); + soil.setLocalTranslation(0, -13, 550); soil.setMaterial(matSoil); soil.setShadowMode(ShadowMode.CastAndReceive); rootNode.attachChild(soil); diff --git a/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java b/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java index ad0172511..17b22d167 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java +++ b/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java @@ -116,7 +116,7 @@ public class TestRenderToMemory extends SimpleApplication implements SceneProces frames ++; t = t2; - if (total > 1000){ + if (total > timer.getResolution()) { fps = frames; total = 0; frames = 0; @@ -202,7 +202,7 @@ public class TestRenderToMemory extends SimpleApplication implements SceneProces offView.setOutputFrameBuffer(offBuffer); // setup framebuffer's scene - Box boxMesh = new Box(Vector3f.ZERO, 1,1,1); + Box boxMesh = new Box(1, 1, 1); Material material = assetManager.loadMaterial("Interface/Logo/Logo.j3m"); offBox = new Geometry("box", boxMesh); offBox.setMaterial(material); diff --git a/jme3-examples/src/main/java/jme3test/post/TestRenderToTexture.java b/jme3-examples/src/main/java/jme3test/post/TestRenderToTexture.java index ba872831a..037c959d3 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestRenderToTexture.java +++ b/jme3-examples/src/main/java/jme3test/post/TestRenderToTexture.java @@ -93,7 +93,7 @@ public class TestRenderToTexture extends SimpleApplication implements ActionList offView.setOutputFrameBuffer(offBuffer); // setup framebuffer's scene - Box boxMesh = new Box(Vector3f.ZERO, 1,1,1); + Box boxMesh = new Box(1, 1, 1); Material material = assetManager.loadMaterial("Interface/Logo/Logo.j3m"); offBox = new Geometry("box", boxMesh); offBox.setMaterial(material); @@ -110,7 +110,7 @@ public class TestRenderToTexture extends SimpleApplication implements ActionList cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); //setup main scene - Geometry quad = new Geometry("box", new Box(Vector3f.ZERO, 1,1,1)); + Geometry quad = new Geometry("box", new Box(1, 1, 1)); Texture offTex = setupOffscreenView(); diff --git a/jme3-examples/src/main/java/jme3test/renderer/TestBlendEquations.java b/jme3-examples/src/main/java/jme3test/renderer/TestBlendEquations.java new file mode 100644 index 000000000..9335912b6 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/renderer/TestBlendEquations.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2009-2016 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 jme3test.renderer; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; + +public class TestBlendEquations extends SimpleApplication { + + public static void main(String[] args) { + TestBlendEquations app = new TestBlendEquations(); + app.start(); + } + + public void simpleInitApp() { + Geometry teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); + teaGeom.scale(6); + teaGeom.getMaterial().getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.Add); + teaGeom.move(0, -2f, 0); + + DirectionalLight dl = new DirectionalLight(); + dl.setColor(ColorRGBA.Red); + dl.setDirection(Vector3f.UNIT_XYZ.negate()); + + rootNode.addLight(dl); + rootNode.attachChild(teaGeom); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", new ColorRGBA(0.5f, 0f, 1f, 0.3f)); + mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Color); + mat.getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.Subtract); + + Geometry geo = new Geometry("BottomLeft", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2)); + geo.setMaterial(mat); + geo.setQueueBucket(RenderQueue.Bucket.Gui); + geo.setLocalTranslation(0, 0, 1); + + guiNode.attachChild(geo); + + Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m.getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.ReverseSubtract); + m.setColor("Color", new ColorRGBA(0.0f, 1f, 1.f, 1f)); + m.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.AlphaAdditive); + + geo = new Geometry("BottomRight", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2)); + geo.setMaterial(m); + geo.setQueueBucket(RenderQueue.Bucket.Gui); + geo.setLocalTranslation(guiViewPort.getCamera().getWidth() / 2, 0, 1); + + guiNode.attachChild(geo); + + m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m.getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.Min); + m.setColor("Color", new ColorRGBA(0.3f, 0f, 0.1f, 0.3f)); + m.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Additive); + + geo = new Geometry("TopRight", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2)); + geo.setMaterial(m); + geo.setQueueBucket(RenderQueue.Bucket.Gui); + geo.setLocalTranslation(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2, 1); + + guiNode.attachChild(geo); + + geo = new Geometry("OverTeaPot", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2)); + geo.setMaterial(mat); + geo.setQueueBucket(RenderQueue.Bucket.Transparent); + geo.setLocalTranslation(0, -100, 5); + + rootNode.attachChild(geo); + + } + + +} diff --git a/jme3-examples/src/main/java/jme3test/texture/TestAnisotropicFilter.java b/jme3-examples/src/main/java/jme3test/texture/TestAnisotropicFilter.java new file mode 100755 index 000000000..c8633f596 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/texture/TestAnisotropicFilter.java @@ -0,0 +1,116 @@ +package jme3test.texture; + +import com.jme3.app.SimpleApplication; +import com.jme3.app.state.ScreenshotAppState; +import com.jme3.asset.AssetManager; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Limits; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; +import com.jme3.texture.Image; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; +import com.jme3.texture.image.ColorSpace; +import com.jme3.texture.image.ImageRaster; +import com.jme3.util.BufferUtils; + +public class TestAnisotropicFilter extends SimpleApplication implements ActionListener { + + private int globalAniso = 1; + private int maxAniso = 1; + + @Override + public void simpleInitApp() { + maxAniso = renderer.getLimits().get(Limits.TextureAnisotropy); + + flyCam.setDragToRotate(true); + flyCam.setMoveSpeed(100); + cam.setLocation(new Vector3f(197.02617f, 4.6769195f, -194.89545f)); + cam.setRotation(new Quaternion(0.07921988f, 0.8992258f, -0.18292196f, 0.38943136f)); + Quad q = new Quad(1000, 1000); + q.scaleTextureCoordinates(new Vector2f(1000, 1000)); + Geometry geom = new Geometry("quad", q); + geom.rotate(-FastMath.HALF_PI, 0, 0); + geom.setMaterial(createCheckerBoardMaterial(assetManager)); + rootNode.attachChild(geom); + + inputManager.addMapping("higher", new KeyTrigger(KeyInput.KEY_1)); + inputManager.addMapping("lower", new KeyTrigger(KeyInput.KEY_2)); + inputManager.addListener(this, "higher"); + inputManager.addListener(this, "lower"); + } + + private static Material createCheckerBoardMaterial(AssetManager assetManager) { + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + Texture tex = createCheckerBoardTexture(); // assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.dds"); + tex.setMagFilter(Texture.MagFilter.Bilinear); + tex.setMinFilter(Texture.MinFilter.Trilinear); + tex.setWrap(Texture.WrapMode.Repeat); + mat.setTexture("ColorMap", tex); + return mat; + } + + private static Texture2D createCheckerBoardTexture() { + Image image = new Image(Format.RGBA8, 1024, 1024, BufferUtils.createByteBuffer(1024 * 1024 * 4), ColorSpace.sRGB); + + ImageRaster raster = ImageRaster.create(image); + for (int y = 0; y < 1024; y++) { + for (int x = 0; x < 1024; x++) { + if (y < 512) { + if (x < 512) { + raster.setPixel(x, y, ColorRGBA.Black); + } else { + raster.setPixel(x, y, ColorRGBA.White); + } + } else { + if (x < 512) { + raster.setPixel(x, y, ColorRGBA.White); + } else { + raster.setPixel(x, y, ColorRGBA.Black); + } + } + } + } + + return new Texture2D(image); + } + + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed) { + return; + } + switch (name) { + case "higher": + globalAniso++; + if (globalAniso > 32) { + globalAniso = 32; + } + renderer.setDefaultAnisotropicFilter(globalAniso); + System.out.format("Global Aniso: %d / %d\r\n", globalAniso, maxAniso); + break; + case "lower": + globalAniso--; + if (globalAniso < 1) { + globalAniso = 1; + } + renderer.setDefaultAnisotropicFilter(globalAniso); + System.out.format("Global Aniso: %d / %d\r\n", globalAniso, maxAniso); + break; + } + } + + public static void main(String[] args) { + TestAnisotropicFilter app = new TestAnisotropicFilter(); + app.start(); + } +} diff --git a/jme3-examples/src/main/java/jme3test/water/TestPostWater.java b/jme3-examples/src/main/java/jme3test/water/TestPostWater.java index a03aeb393..a4d557f78 100644 --- a/jme3-examples/src/main/java/jme3test/water/TestPostWater.java +++ b/jme3-examples/src/main/java/jme3test/water/TestPostWater.java @@ -194,7 +194,7 @@ public class TestPostWater extends SimpleApplication { private void createBox() { //creating a transluscent box - box = new Geometry("box", new Box(new Vector3f(0, 0, 0), 50, 50, 50)); + box = new Geometry("box", new Box(50, 50, 50)); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setColor("Color", new ColorRGBA(1.0f, 0, 0, 0.3f)); mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); diff --git a/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java b/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java index a9398f159..958163596 100644 --- a/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java +++ b/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java @@ -78,6 +78,11 @@ public class IosGL implements GL, GLExt, GLFbo { checkLimit(buffer); return buffer.limit() / elementSize; } + + @Override + public void glBlendEquationSeparate(int colorMode, int alphaMode) { + JmeIosGLES.glBlendEquationSeparate(colorMode, alphaMode); + } private int toArray(IntBuffer buffer) { int remain = buffer.remaining(); diff --git a/jme3-ios/src/main/java/com/jme3/renderer/ios/JmeIosGLES.java b/jme3-ios/src/main/java/com/jme3/renderer/ios/JmeIosGLES.java index 0811dc422..b8ec75a77 100644 --- a/jme3-ios/src/main/java/com/jme3/renderer/ios/JmeIosGLES.java +++ b/jme3-ios/src/main/java/com/jme3/renderer/ios/JmeIosGLES.java @@ -142,6 +142,7 @@ public class JmeIosGLES { public static native void glBindRenderbuffer(int target, int renderbuffer); public static native void glBindTexture(int target, int texture); // public static native void glBindVertexArray // TODO: Investigate this + public static native void glBlendEquationSeparate(int colorMode, int alphaMode); public static native void glBlendFunc(int sfactor, int dfactor); public static native void glBufferData(int target, int size, Buffer data, int usage); public static native void glBufferData2(int target, int size, byte[] data, int offset, int usage); diff --git a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java index 2ca2fb266..8b222d751 100644 --- a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java +++ b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java @@ -78,6 +78,11 @@ public class JoglGL implements GL, GL2, GL3, GL4 { GLContext.getCurrentGL().glBindTexture(param1, param2); } + @Override + public void glBlendEquationSeparate(int colorMode, int alphaMode){ + GLContext.getCurrentGL().glBlendEquationSeparate(colorMode, alphaMode); + } + @Override public void glBlendFunc(int param1, int param2) { GLContext.getCurrentGL().glBlendFunc(param1, param2); diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglAbstractDisplay.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglAbstractDisplay.java index 3b468f1aa..c4f38f970 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglAbstractDisplay.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglAbstractDisplay.java @@ -77,8 +77,6 @@ public abstract class JoglAbstractDisplay extends JoglContext implements GLEvent protected boolean wasAnimating = false; protected void initGLCanvas() { - loadNatives(); - device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); GLCapabilities caps; diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java index 3ed543bc9..24a647ef6 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java @@ -53,8 +53,6 @@ import com.jme3.renderer.opengl.GLTracer; import com.jme3.system.AppSettings; import com.jme3.system.JmeContext; import com.jme3.system.NanoTimer; -import com.jme3.system.NativeLibraryLoader; -import com.jme3.system.NullRenderer; import com.jme3.system.SystemListener; import com.jme3.system.Timer; @@ -86,13 +84,6 @@ public abstract class JoglContext implements JmeContext { protected MouseInput mouseInput; protected JoyInput joyInput; - public void loadNatives() { - // Not sure if need to load OpenAL here ... - if (NativeLibraryLoader.isUsingNativeBullet()) { - NativeLibraryLoader.loadNativeLibrary("bulletjme", true); - } - } - @Override public void setSystemListener(SystemListener listener){ this.listener = listener; diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtAbstractDisplay.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtAbstractDisplay.java index 9c7a49d17..48f191cb3 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtAbstractDisplay.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtAbstractDisplay.java @@ -73,7 +73,6 @@ public abstract class JoglNewtAbstractDisplay extends JoglContext implements GLE protected boolean wasAnimating = false; protected void initGLCanvas() { - loadNatives(); GLCapabilities caps; if (settings.getRenderer().equals(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE)) { caps = new GLCapabilities(GLProfile.getMaxProgrammable(true)); diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java index 56aa2d53f..54fa3b552 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java @@ -123,8 +123,7 @@ public class JoglOffscreenBuffer extends JoglContext implements Runnable { } @Override - public void run(){ - loadNatives(); + public void run() { logger.log(Level.FINE, "Using JOGL {0}", JoglVersion.getInstance().getImplementationVersion()); initInThread(); while (!needClose.get()){ diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java index 6f640042f..abc419c41 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java @@ -50,6 +50,10 @@ public final class LwjglGL implements GL, GL2, GL3, GL4 { GL11.glBindTexture(param1, param2); } + public void glBlendEquationSeparate(int colorMode, int alphaMode){ + GL20.glBlendEquationSeparate(colorMode,alphaMode); + } + public void glBlendFunc(int param1, int param2) { GL11.glBlendFunc(param1, param2); } diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 3f1139886..be3014da5 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -29,6 +29,7 @@ * 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.system.lwjgl; import com.jme3.input.lwjgl.JInputJoyInput; @@ -69,7 +70,6 @@ public abstract class LwjglContext implements JmeContext { private static final Logger logger = Logger.getLogger(LwjglContext.class.getName()); protected static final String THREAD_NAME = "jME3 Main"; - protected AtomicBoolean created = new AtomicBoolean(false); protected AtomicBoolean renderable = new AtomicBoolean(false); protected final Object createdLock = new Object(); @@ -113,7 +113,6 @@ public abstract class LwjglContext implements JmeContext { return null; } } - protected int determineMaxSamples(int requestedSamples) { try { // If we already have a valid context, determine samples using current @@ -131,13 +130,11 @@ public abstract class LwjglContext implements JmeContext { } catch (LWJGLException ex) { listener.handleError("Failed to check if display is current", ex); } - if ((Pbuffer.getCapabilities() & Pbuffer.PBUFFER_SUPPORTED) == 0) { // No pbuffer, assume everything is supported. return Integer.MAX_VALUE; } else { Pbuffer pb = null; - // OpenGL2 method: Create pbuffer and query samples // from GL_ARB_framebuffer_object or GL_EXT_framebuffer_multisample. try { @@ -162,7 +159,6 @@ public abstract class LwjglContext implements JmeContext { } } } - protected void loadNatives() { if (JmeSystem.isLowPermissions()) { return; @@ -174,12 +170,8 @@ public abstract class LwjglContext implements JmeContext { NativeLibraryLoader.loadNativeLibrary("jinput", true); NativeLibraryLoader.loadNativeLibrary("jinput-dx8", true); } - if (NativeLibraryLoader.isUsingNativeBullet()) { - NativeLibraryLoader.loadNativeLibrary("bulletjme", true); - } NativeLibraryLoader.loadNativeLibrary("lwjgl", true); } - protected int getNumSamplesToUse() { int samples = 0; if (settings.getSamples() > 1) { @@ -190,7 +182,6 @@ public abstract class LwjglContext implements JmeContext { "Couldn''t satisfy antialiasing samples requirement: x{0}. " + "Video hardware only supports: x{1}", new Object[]{samples, supportedSamples}); - samples = supportedSamples; } } @@ -202,48 +193,43 @@ public abstract class LwjglContext implements JmeContext { throw new RendererException("OpenGL 2.0 or higher is " + "required for jMonkeyEngine"); } - + if (settings.getRenderer().equals(AppSettings.LWJGL_OPENGL2) || settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)) { GL gl = new LwjglGL(); GLExt glext = new LwjglGLExt(); GLFbo glfbo; - + if (GLContext.getCapabilities().OpenGL30) { glfbo = new LwjglGLFboGL3(); } else { glfbo = new LwjglGLFboEXT(); } - + if (settings.getBoolean("GraphicsDebug")) { gl = new GLDebugDesktop(gl, glext, glfbo); glext = (GLExt) gl; glfbo = (GLFbo) gl; } - if (settings.getBoolean("GraphicsTiming")) { GLTimingState timingState = new GLTimingState(); gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class); glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class); glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class); } - if (settings.getBoolean("GraphicsTrace")) { gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class); glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class); glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class); } - renderer = new GLRenderer(gl, glext, glfbo); renderer.initialize(); } else { throw new UnsupportedOperationException("Unsupported renderer: " + settings.getRenderer()); } - if (GLContext.getCapabilities().GL_ARB_debug_output && settings.getBoolean("GraphicsDebug")) { ARBDebugOutput.glDebugMessageCallbackARB(new ARBDebugOutputCallback(new LwjglGLDebugOutputHandler())); } - renderer.setMainFrameBufferSrgb(settings.isGammaCorrection()); renderer.setLinearizeSrgbImages(settings.isGammaCorrection()); @@ -270,15 +256,12 @@ public abstract class LwjglContext implements JmeContext { createdLock.notifyAll(); } } - public void internalCreate() { timer = new LwjglTimer(); - synchronized (createdLock) { created.set(true); createdLock.notifyAll(); } - if (renderable.get()) { initContextFirstTime(); } else { @@ -308,7 +291,6 @@ public abstract class LwjglContext implements JmeContext { public boolean isCreated() { return created.get(); } - public boolean isRenderable() { return renderable.get(); } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java index 25de6b148..10358c009 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java @@ -79,6 +79,10 @@ public class LwjglGL implements GL, GL2, GL3, GL4 { GL11.glBindTexture(param1, param2); } + public void glBlendEquationSeparate(int colorMode, int alphaMode){ + GL20.glBlendEquationSeparate(colorMode,alphaMode); + } + public void glBlendFunc(int param1, int param2) { GL11.glBlendFunc(param1, param2); } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 0fe8a7b23..20532df36 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -116,17 +116,6 @@ public abstract class LwjglContext implements JmeContext { return samples; } - protected void loadNatives() { - if (JmeSystem.isLowPermissions()) { - return; - } - - if (NativeLibraryLoader.isUsingNativeBullet()) { - NativeLibraryLoader.loadNativeLibrary("bulletjme", true); - } - } - - protected void initContextFirstTime() { final GLCapabilities capabilities = createCapabilities(settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java index aaa24ce42..cac8ecdd1 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -315,8 +315,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { }); } - loadNatives(); - timer = new NanoTimer(); // For canvas, this will create a pbuffer, diff --git a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/SceneLoader.java b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/SceneLoader.java index 491301c22..87e13abed 100644 --- a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/SceneLoader.java +++ b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/SceneLoader.java @@ -803,9 +803,7 @@ public class SceneLoader implements AssetLoader { m.setColor("Diffuse", new ColorRGBA(data.diffuseColor.x, data.diffuseColor.y, data.diffuseColor.z, 1)); m.setColor("Specular", new ColorRGBA(data.specularColor.x, data.specularColor.y, data.specularColor.z, 1)); m.setFloat("Shininess", data.shininessExponent); - m.setBoolean("UseMaterialColors", true); - m.getAdditionalRenderState().setAlphaTest(true); - m.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); + m.setBoolean("UseMaterialColors", true); return m; } diff --git a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/obj/FbxObjectFactory.java b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/obj/FbxObjectFactory.java index ec8c1fd67..111750df1 100644 --- a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/obj/FbxObjectFactory.java +++ b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/obj/FbxObjectFactory.java @@ -74,6 +74,12 @@ public final class FbxObjectFactory { subclassName.equals("FKEffector")) { // jME3 does not support IK. return FbxNullAttribute.class; + } else if (subclassName.equals("Light")) { + // TODO: support lights + return FbxNullAttribute.class; + } else if (subclassName.equals("Camera")) { + // TODO: support cameras + return FbxNullAttribute.class; } else { // NodeAttribute - Unknown logger.log(Level.WARNING, "Unknown object subclass: {0}. Ignoring.", subclassName); diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/GeoMap.java b/jme3-terrain/src/main/java/com/jme3/terrain/GeoMap.java index 21b222023..efa823c66 100644 --- a/jme3-terrain/src/main/java/com/jme3/terrain/GeoMap.java +++ b/jme3-terrain/src/main/java/com/jme3/terrain/GeoMap.java @@ -51,16 +51,7 @@ public class GeoMap implements Savable { protected int width, height, maxval; public GeoMap() {} - - @Deprecated - public GeoMap(FloatBuffer heightData, int width, int height, int maxval){ - hdata = new float[heightData.limit()]; - heightData.get(hdata); - this.width = width; - this.height = height; - this.maxval = maxval; - } - + public GeoMap(float[] heightData, int width, int height, int maxval){ this.hdata = heightData; this.width = width; @@ -68,13 +59,6 @@ public class GeoMap implements Savable { this.maxval = maxval; } - @Deprecated - public FloatBuffer getHeightData(){ - if (!isLoaded()) - return null; - return BufferUtils.createFloatBuffer(hdata); - } - public float[] getHeightArray(){ if (!isLoaded()) return null; diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/LODGeomap.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/LODGeomap.java index fec90d811..286c570d9 100644 --- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/LODGeomap.java +++ b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/LODGeomap.java @@ -69,11 +69,6 @@ public class LODGeomap extends GeoMap { public LODGeomap() { } - - @Deprecated - public LODGeomap(int size, FloatBuffer heightMap) { - super(heightMap, size, size, 1); - } public LODGeomap(int size, float[] heightMap) { super(heightMap, size, size, 1); diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainGrid.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainGrid.java index 50e1f9f73..d232be924 100644 --- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainGrid.java +++ b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainGrid.java @@ -43,7 +43,6 @@ import com.jme3.math.Vector3f; import com.jme3.scene.Spatial; import com.jme3.scene.control.UpdateControl; import com.jme3.terrain.Terrain; -import com.jme3.terrain.heightmap.HeightMap; import com.jme3.terrain.heightmap.HeightMapGrid; import java.io.IOException; import java.util.HashSet; @@ -114,7 +113,6 @@ public class TerrainGrid extends TerrainQuad { protected Vector3f currentCamCell = Vector3f.ZERO; protected int quarterSize; // half of quadSize protected int quadSize; - protected HeightMapGrid heightMapGrid; private TerrainGridTileLoader gridTileLoader; protected Vector3f[] quadIndex; protected Set listeners = new HashSet(); @@ -150,13 +148,7 @@ public class TerrainGrid extends TerrainQuad { final Vector3f quadCell = location.add(quadIndex[quadIdx]); TerrainQuad q = cache.get(quadCell); if (q == null) { - if (heightMapGrid != null) { - // create the new Quad since it doesn't exist - HeightMap heightMapAt = heightMapGrid.getHeightMapAt(quadCell); - q = new TerrainQuad(getName() + "Quad" + quadCell, patchSize, quadSize, heightMapAt == null ? null : heightMapAt.getHeightMap()); - q.setMaterial(material.clone()); - log.log(Level.FINE, "Loaded TerrainQuad {0} from HeightMapGrid", q.getName()); - } else if (gridTileLoader != null) { + if (gridTileLoader != null) { q = gridTileLoader.getTerrainQuadAt(quadCell); // only clone the material to the quad if it doesn't have a material of its own if(q.getMaterial()==null) q.setMaterial(material.clone()); diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainPatch.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainPatch.java index 4641f4de6..44ad5cb30 100644 --- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainPatch.java +++ b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainPatch.java @@ -218,11 +218,6 @@ public class TerrainPatch extends Geometry { return lodEntropy; } - @Deprecated - public FloatBuffer getHeightmap() { - return BufferUtils.createFloatBuffer(geomap.getHeightArray()); - } - public float[] getHeightMap() { return geomap.getHeightArray(); } diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainQuad.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainQuad.java index e21b89155..679afcb70 100644 --- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainQuad.java +++ b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainQuad.java @@ -161,21 +161,6 @@ public class TerrainQuad extends Node implements Terrain { addControl(new NormalRecalcControl(this)); } - /** - * - * @param name the name of the scene element. This is required for - * identification and comparison purposes. - * @param patchSize size of the individual patches - * @param quadSize - * @param totalSize the size of this entire terrain tree (on one side) - * @param heightMap The height map to generate the terrain from (a flat - * height map will be generated if this is null) - */ - @Deprecated - public TerrainQuad(String name, int patchSize, int quadSize, int totalSize, float[] heightMap) { - this(name, patchSize, totalSize, quadSize, Vector3f.UNIT_XYZ, heightMap); - } - /** * * @param name the name of the scene element. This is required for diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodCalculatorFactory.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodCalculatorFactory.java deleted file mode 100644 index bfbd24a11..000000000 --- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodCalculatorFactory.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2009-2012 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.terrain.geomipmap.lodcalc; - -import com.jme3.export.Savable; -import com.jme3.terrain.geomipmap.TerrainPatch; - -/** - * Creates LOD Calculator objects for the terrain patches. - * - * @author Brent Owens - * @deprecated phasing this out - */ -public interface LodCalculatorFactory extends Savable, Cloneable { - - public LodCalculator createCalculator(); - public LodCalculator createCalculator(TerrainPatch terrainPatch); - - public LodCalculatorFactory clone(); -} diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodDistanceCalculatorFactory.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodDistanceCalculatorFactory.java deleted file mode 100644 index ab6e0037e..000000000 --- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodDistanceCalculatorFactory.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2009-2012 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.terrain.geomipmap.lodcalc; - -import com.jme3.export.InputCapsule; -import com.jme3.export.JmeExporter; -import com.jme3.export.JmeImporter; -import com.jme3.export.OutputCapsule; -import com.jme3.terrain.geomipmap.TerrainPatch; -import java.io.IOException; - -/** - * - * @author bowens - * @deprecated phasing out - */ -public class LodDistanceCalculatorFactory implements LodCalculatorFactory { - - private float lodThresholdSize = 2.7f; - private LodThreshold lodThreshold = null; - - - public LodDistanceCalculatorFactory() { - } - - public LodDistanceCalculatorFactory(LodThreshold lodThreshold) { - this.lodThreshold = lodThreshold; - } - - public LodCalculator createCalculator() { - return new DistanceLodCalculator(); - } - - public LodCalculator createCalculator(TerrainPatch terrainPatch) { - return new DistanceLodCalculator(); - } - - public void write(JmeExporter ex) throws IOException { - OutputCapsule c = ex.getCapsule(this); - c.write(lodThreshold, "lodThreshold", null); - c.write(lodThresholdSize, "lodThresholdSize", 2); - } - - public void read(JmeImporter im) throws IOException { - InputCapsule c = im.getCapsule(this); - lodThresholdSize = c.readFloat("lodThresholdSize", 2); - lodThreshold = (LodThreshold) c.readSavable("lodThreshold", null); - } - - @Override - public LodDistanceCalculatorFactory clone() { - LodDistanceCalculatorFactory clone = new LodDistanceCalculatorFactory(); - clone.lodThreshold = lodThreshold.clone(); - clone.lodThresholdSize = lodThresholdSize; - return clone; - } - -} diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodPerspectiveCalculatorFactory.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodPerspectiveCalculatorFactory.java deleted file mode 100644 index cb4a7d41e..000000000 --- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/lodcalc/LodPerspectiveCalculatorFactory.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2009-2012 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.terrain.geomipmap.lodcalc; - -import com.jme3.export.JmeExporter; -import com.jme3.export.JmeImporter; -import com.jme3.renderer.Camera; -import com.jme3.terrain.geomipmap.TerrainPatch; -import java.io.IOException; - -/** - * TODO: Make it work with multiple cameras - * TODO: Fix the cracks when the lod differences are greater than 1 - * for two adjacent blocks. - * @deprecated phasing out - */ -public class LodPerspectiveCalculatorFactory implements LodCalculatorFactory { - - private Camera cam; - private float pixelError; - - public LodPerspectiveCalculatorFactory(Camera cam, float pixelError){ - this.cam = cam; - this.pixelError = pixelError; - } - - public LodCalculator createCalculator() { - return new PerspectiveLodCalculator(cam, pixelError); - } - - public LodCalculator createCalculator(TerrainPatch terrainPatch) { - PerspectiveLodCalculator p = new PerspectiveLodCalculator(cam, pixelError); - return p; - } - - public void write(JmeExporter ex) throws IOException { - } - - public void read(JmeImporter im) throws IOException { - } - - @Override - public LodCalculatorFactory clone() { - try { - return (LodCalculatorFactory) super.clone(); - } catch (CloneNotSupportedException ex) { - throw new AssertionError(); - } - } - -} diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMap.java b/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMap.java index d4e9b22c8..0373c80eb 100644 --- a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMap.java +++ b/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMap.java @@ -44,7 +44,7 @@ import com.jme3.texture.image.ImageRaster; * @author Mike Kienenberger * @version $id$ */ -public class ImageBasedHeightMap extends AbstractHeightMap implements ImageHeightmap { +public class ImageBasedHeightMap extends AbstractHeightMap { protected Image colorImage; diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMapGrid.java b/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMapGrid.java deleted file mode 100644 index f0d841c22..000000000 --- a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMapGrid.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2009-2012 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.terrain.heightmap; - -import com.jme3.asset.AssetManager; -import com.jme3.asset.AssetNotFoundException; -import com.jme3.asset.TextureKey; -import com.jme3.math.Vector3f; -import com.jme3.texture.Texture; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Loads Terrain grid tiles with image heightmaps. - * By default it expects a 16-bit grayscale image as the heightmap, but - * you can also call setImageType(BufferedImage.TYPE_) to set it to be a different - * image type. If you do this, you must also set a custom ImageHeightmap that will - * understand and be able to parse the image. By default if you pass in an image of type - * BufferedImage.TYPE_3BYTE_BGR, it will use the ImageBasedHeightMap for you. - * - * @author Anthyon, Brent Owens - */ -@Deprecated -/** - * @Deprecated in favor of ImageTileLoader - */ -public class ImageBasedHeightMapGrid implements HeightMapGrid { - - private static final Logger logger = Logger.getLogger(ImageBasedHeightMapGrid.class.getName()); - private final AssetManager assetManager; - private final Namer namer; - private int size; - - - public ImageBasedHeightMapGrid(final String textureBase, final String textureExt, AssetManager assetManager) { - this(assetManager, new Namer() { - - public String getName(int x, int y) { - return textureBase + "_" + x + "_" + y + "." + textureExt; - } - }); - } - - public ImageBasedHeightMapGrid(AssetManager assetManager, Namer namer) { - this.assetManager = assetManager; - this.namer = namer; - } - - public HeightMap getHeightMapAt(Vector3f location) { - // HEIGHTMAP image (for the terrain heightmap) - int x = (int) location.x; - int z = (int) location.z; - - AbstractHeightMap heightmap = null; - //BufferedImage im = null; - - try { - String name = namer.getName(x, z); - logger.log(Level.FINE, "Loading heightmap from file: {0}", name); - final Texture texture = assetManager.loadTexture(new TextureKey(name)); - - // CREATE HEIGHTMAP - heightmap = new ImageBasedHeightMap(texture.getImage()); - - heightmap.setHeightScale(1); - heightmap.load(); - - } catch (AssetNotFoundException e) { - logger.log(Level.SEVERE, "Asset Not found! ", e); - } - return heightmap; - } - - public void setSize(int size) { - this.size = size - 1; - } -} diff --git a/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall.j3m b/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall.j3m index 41af10431..c35ab04c4 100644 --- a/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall.j3m +++ b/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall.j3m @@ -1,7 +1,8 @@ Material Pong Rock : Common/MatDefs/Light/Lighting.j3md { MaterialParameters { - Shininess: 2.0 - DiffuseMap : Repeat Textures/Terrain/BrickWall/BrickWall.jpg - ParallaxMap : Repeat Textures/Terrain/BrickWall/BrickWall_height.jpg + Shininess : 2.0 + DiffuseMap : Repeat Textures/Terrain/BrickWall/BrickWall.dds + NormalMap : Repeat Textures/Terrain/BrickWall/BrickWall_normal_parallax.dds + PackedNormalParallax : true } } \ No newline at end of file diff --git a/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall2.j3m b/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall2.j3m deleted file mode 100644 index 8f90a9454..000000000 --- a/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall2.j3m +++ /dev/null @@ -1,8 +0,0 @@ -Material Pong Rock : Common/MatDefs/Light/Lighting.j3md { - MaterialParameters { - Shininess: 2.0 - DiffuseMap : Repeat Textures/Terrain/BrickWall/BrickWall.jpg - NormalMap : Repeat Textures/Terrain/BrickWall/BrickWall_normal_parallax.dds - PackedNormalParallax: true - } -} \ No newline at end of file