diff --git a/jme3-android-native/libs/openalsoft/arm64-v8a/libopenalsoftjme.so b/jme3-android-native/libs/openalsoft/arm64-v8a/libopenalsoftjme.so new file mode 100755 index 000000000..b85db58ec Binary files /dev/null and b/jme3-android-native/libs/openalsoft/arm64-v8a/libopenalsoftjme.so differ diff --git a/jme3-android-native/libs/openalsoft/armeabi-v7a/libopenalsoftjme.so b/jme3-android-native/libs/openalsoft/armeabi-v7a/libopenalsoftjme.so old mode 100644 new mode 100755 index 04d4fd48f..5cdf3af9f Binary files a/jme3-android-native/libs/openalsoft/armeabi-v7a/libopenalsoftjme.so and b/jme3-android-native/libs/openalsoft/armeabi-v7a/libopenalsoftjme.so differ diff --git a/jme3-android-native/libs/openalsoft/armeabi/libopenalsoftjme.so b/jme3-android-native/libs/openalsoft/armeabi/libopenalsoftjme.so old mode 100644 new mode 100755 index ff561809c..5205dec7e Binary files a/jme3-android-native/libs/openalsoft/armeabi/libopenalsoftjme.so and b/jme3-android-native/libs/openalsoft/armeabi/libopenalsoftjme.so differ diff --git a/jme3-android-native/libs/openalsoft/mips/libopenalsoftjme.so b/jme3-android-native/libs/openalsoft/mips/libopenalsoftjme.so old mode 100644 new mode 100755 index 24f07dd22..ec3e9f747 Binary files a/jme3-android-native/libs/openalsoft/mips/libopenalsoftjme.so and b/jme3-android-native/libs/openalsoft/mips/libopenalsoftjme.so differ diff --git a/jme3-android-native/libs/openalsoft/mips64/libopenalsoftjme.so b/jme3-android-native/libs/openalsoft/mips64/libopenalsoftjme.so new file mode 100755 index 000000000..c523483a8 Binary files /dev/null and b/jme3-android-native/libs/openalsoft/mips64/libopenalsoftjme.so differ diff --git a/jme3-android-native/libs/openalsoft/x86/libopenalsoftjme.so b/jme3-android-native/libs/openalsoft/x86/libopenalsoftjme.so old mode 100644 new mode 100755 index 93e2029ad..cb2f480da Binary files a/jme3-android-native/libs/openalsoft/x86/libopenalsoftjme.so and b/jme3-android-native/libs/openalsoft/x86/libopenalsoftjme.so differ diff --git a/jme3-android-native/libs/openalsoft/x86_64/libopenalsoftjme.so b/jme3-android-native/libs/openalsoft/x86_64/libopenalsoftjme.so new file mode 100755 index 000000000..53a04ef16 Binary files /dev/null and b/jme3-android-native/libs/openalsoft/x86_64/libopenalsoftjme.so differ diff --git a/jme3-android-native/libs/stb_image/arm64-v8a/libstbijme.so b/jme3-android-native/libs/stb_image/arm64-v8a/libstbijme.so new file mode 100755 index 000000000..6ecb94ff4 Binary files /dev/null and b/jme3-android-native/libs/stb_image/arm64-v8a/libstbijme.so differ diff --git a/jme3-android-native/libs/stb_image/armeabi-v7a/libstbijme.so b/jme3-android-native/libs/stb_image/armeabi-v7a/libstbijme.so old mode 100644 new mode 100755 index 225b5b701..58af1854c Binary files a/jme3-android-native/libs/stb_image/armeabi-v7a/libstbijme.so and b/jme3-android-native/libs/stb_image/armeabi-v7a/libstbijme.so differ diff --git a/jme3-android-native/libs/stb_image/armeabi/libstbijme.so b/jme3-android-native/libs/stb_image/armeabi/libstbijme.so old mode 100644 new mode 100755 index 652b81474..a800d5210 Binary files a/jme3-android-native/libs/stb_image/armeabi/libstbijme.so and b/jme3-android-native/libs/stb_image/armeabi/libstbijme.so differ diff --git a/jme3-android-native/libs/stb_image/mips/libstbijme.so b/jme3-android-native/libs/stb_image/mips/libstbijme.so old mode 100644 new mode 100755 index 310e89902..d7267f7d0 Binary files a/jme3-android-native/libs/stb_image/mips/libstbijme.so and b/jme3-android-native/libs/stb_image/mips/libstbijme.so differ diff --git a/jme3-android-native/libs/stb_image/mips64/libstbijme.so b/jme3-android-native/libs/stb_image/mips64/libstbijme.so new file mode 100755 index 000000000..118945b15 Binary files /dev/null and b/jme3-android-native/libs/stb_image/mips64/libstbijme.so differ diff --git a/jme3-android-native/libs/stb_image/x86/libstbijme.so b/jme3-android-native/libs/stb_image/x86/libstbijme.so old mode 100644 new mode 100755 index 7ce477f27..e590a80f3 Binary files a/jme3-android-native/libs/stb_image/x86/libstbijme.so and b/jme3-android-native/libs/stb_image/x86/libstbijme.so differ diff --git a/jme3-android-native/libs/stb_image/x86_64/libstbijme.so b/jme3-android-native/libs/stb_image/x86_64/libstbijme.so new file mode 100755 index 000000000..c8d80c289 Binary files /dev/null and b/jme3-android-native/libs/stb_image/x86_64/libstbijme.so differ diff --git a/jme3-android-native/openalsoft.gradle b/jme3-android-native/openalsoft.gradle index 1027f44ef..d32a804b8 100644 --- a/jme3-android-native/openalsoft.gradle +++ b/jme3-android-native/openalsoft.gradle @@ -1,9 +1,5 @@ -// OpenAL Soft r1.15.1 -//String openALSoftUrl = 'http://repo.or.cz/w/openal-soft.git/snapshot/9b6a226da55a987cb883f425eeb568776ea12c8d.zip' -// OpenAL Soft r1.15.1 + Android OpenSL Support -String openALSoftUrl = 'http://repo.or.cz/w/openal-soft.git/snapshot/be25e6802dacad78876c6fa1d6a5c63797b8a9ed.zip' -// OpenAL Soft r1.15.1 latest build (at the time) -//String openALSoftUrl = 'http://repo.or.cz/w/openal-soft.git/snapshot/3f5914e0949ee12b504ee7254990e007ff8057ef.zip' +// OpenAL Soft r1.16 +String openALSoftUrl = 'http://repo.or.cz/w/openal-soft.git/snapshot/e5016f814a265ed592a88acea95cf912c4bfdf12.zip' String openALSoftZipFile = 'OpenALSoft.zip' // OpenAL Soft directory the download is extracted into @@ -81,22 +77,23 @@ task generateOpenAlSoftHeaders(dependsOn: copyJmeOpenALSoft) << { String classes = "" .concat("com.jme3.audio.android.AndroidOpenALSoftAudioRenderer, ") // println "openalsoft classes = " + classes -// println "openalsoft destDir = " + destDir +// println "openalsoft destDir = " + destDirPath // println "openalsoft classpath = " + project.projectClassPath - ant.javah( - classpath: project.projectClassPath, - destdir: destDirPath, - class: classes - ) + exec { + executable org.gradle.internal.jvm.Jvm.current().getExecutable('javah') + args '-d', destDirPath + args '-classpath', project.projectClassPath + args "com.jme3.audio.android.AndroidOpenALSoftAudioRenderer" + } } task buildOpenAlSoftNativeLib(type: Exec, dependsOn: generateOpenAlSoftHeaders) { // println "openalsoft build dir: " + openalsoftBuildDir // println "ndkCommandPath: " + project.ndkCommandPath - args 'TARGET_PLATFORM=android-9' workingDir openalsoftBuildDir executable rootProject.ndkCommandPath + args '-j8' } task updatePreCompiledOpenAlSoftLibs(type: Copy, dependsOn: buildOpenAlSoftNativeLib) { diff --git a/jme3-android-native/src/native/jme_openalsoft/Android.mk b/jme3-android-native/src/native/jme_openalsoft/Android.mk index 428008320..cac2e4df8 100644 --- a/jme3-android-native/src/native/jme_openalsoft/Android.mk +++ b/jme3-android-native/src/native/jme_openalsoft/Android.mk @@ -1,58 +1,68 @@ TARGET_PLATFORM := android-9 -ROOT_PATH := $(call my-dir) - -######################################################################################################## +LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := openalsoftjme -LOCAL_ARM_MODE := arm -LOCAL_PATH := $(ROOT_PATH) -LOCAL_C_INCLUDES := $(LOCAL_PATH) $(LOCAL_PATH)/include $(LOCAL_PATH)/OpenAL32/Include - -LOCAL_CFLAGS := -ffast-math -DAL_BUILD_LIBRARY -DAL_ALEXT_PROTOTYPES -LOCAL_LDLIBS := -llog -Wl,-s -LOCAL_LDLIBS += -lOpenSLES -# LOCAL_CFLAGS += -DPOST_FROYO #-I$(ANDROID_NDK_ROOT)/platforms/android-9/arch-arm/usr/include/ -# LOCAL_LDLIBS += -ldl -L$(ANDROID_NDK_ROOT)/platforms/android-9/arch-arm/usr/lib/ - -LOCAL_SRC_FILES := OpenAL32/alAuxEffectSlot.c \ - OpenAL32/alBuffer.c \ - OpenAL32/alEffect.c \ - OpenAL32/alError.c \ - OpenAL32/alExtension.c \ - OpenAL32/alFilter.c \ - OpenAL32/alListener.c \ - OpenAL32/alSource.c \ - OpenAL32/alState.c \ - OpenAL32/alThunk.c \ - Alc/ALc.c \ - Alc/ALu.c \ - Alc/alcConfig.c \ - Alc/alcDedicated.c \ - Alc/alcEcho.c \ - Alc/alcModulator.c \ - Alc/alcReverb.c \ - Alc/alcRing.c \ - Alc/alcThread.c \ - Alc/bs2b.c \ - Alc/helpers.c \ - Alc/panning.c \ - Alc/hrtf.c \ - Alc/mixer.c \ - Alc/mixer_c.c \ - Alc/backends/loopback.c \ - Alc/backends/null.c \ - Alc/backends/opensl.c \ - com_jme3_audio_android_AndroidOpenALSoftAudioRenderer.cpp -# Alc/backends/alsa.c \ -# Alc/backends/android.c \ -# Alc/alcChorus.c \ -# Alc/alcFlanger.c \ -# Alc/mixer_c.c \ -# Alc/backends/loopback.c \ -# Alc/backends/null.c \ + +LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/OpenAL32/Include $(LOCAL_PATH)/Alc + +LOCAL_CFLAGS := -std=c99 -ffast-math -DAL_BUILD_LIBRARY -DAL_ALEXT_PROTOTYPES +LOCAL_LDLIBS := -lOpenSLES -llog -Wl,-s + +LOCAL_SRC_FILES := Alc/backends/opensl.c \ + Alc/backends/loopback.c \ + Alc/backends/wave.c \ + Alc/backends/base.c \ + Alc/backends/null.c \ + Alc/ALc.c \ + Alc/helpers.c \ + Alc/bs2b.c \ + Alc/alcRing.c \ + Alc/effects/chorus.c \ + Alc/effects/flanger.c \ + Alc/effects/dedicated.c \ + Alc/effects/reverb.c \ + Alc/effects/distortion.c \ + Alc/effects/autowah.c \ + Alc/effects/equalizer.c \ + Alc/effects/modulator.c \ + Alc/effects/echo.c \ + Alc/effects/compressor.c \ + Alc/effects/null.c \ + Alc/alcConfig.c \ + Alc/ALu.c \ + Alc/mixer_c.c \ + Alc/panning.c \ + Alc/hrtf.c \ + Alc/mixer.c \ + Alc/midi/soft.c \ + Alc/midi/sf2load.c \ + Alc/midi/dummy.c \ + Alc/midi/fluidsynth.c \ + Alc/midi/base.c \ + common/uintmap.c \ + common/atomic.c \ + common/threads.c \ + common/rwlock.c \ + OpenAL32/alBuffer.c \ + OpenAL32/alPreset.c \ + OpenAL32/alListener.c \ + OpenAL32/alEffect.c \ + OpenAL32/alExtension.c \ + OpenAL32/alThunk.c \ + OpenAL32/alMidi.c \ + OpenAL32/alSoundfont.c \ + OpenAL32/alFontsound.c \ + OpenAL32/alAuxEffectSlot.c \ + OpenAL32/alError.c \ + OpenAL32/alFilter.c \ + OpenAL32/alSource.c \ + OpenAL32/alState.c \ + OpenAL32/sample_cvt.c \ + com_jme3_audio_android_AndroidOpenALSoftAudioRenderer.cpp include $(BUILD_SHARED_LIBRARY) diff --git a/jme3-android-native/src/native/jme_openalsoft/Application.mk b/jme3-android-native/src/native/jme_openalsoft/Application.mk index fcdc69644..fbc028f84 100644 --- a/jme3-android-native/src/native/jme_openalsoft/Application.mk +++ b/jme3-android-native/src/native/jme_openalsoft/Application.mk @@ -1,3 +1,3 @@ +APP_PLATFORM := android-9 APP_OPTIM := release -APP_ABI := all -#APP_ABI := armeabi-v7a +APP_ABI := all \ No newline at end of file diff --git a/jme3-android-native/src/native/jme_openalsoft/config.h b/jme3-android-native/src/native/jme_openalsoft/config.h index bf3ee85db..f9de99528 100644 --- a/jme3-android-native/src/native/jme_openalsoft/config.h +++ b/jme3-android-native/src/native/jme_openalsoft/config.h @@ -1,147 +1,203 @@ -#ifndef CONFIG_H -#define CONFIG_H +/* API declaration export attribute */ +#define AL_API __attribute__((visibility("protected"))) +#define ALC_API __attribute__((visibility("protected"))) /* Define to the library version */ -#define ALSOFT_VERSION "1.15.1" +#define ALSOFT_VERSION "1.16.0" -#define ALIGN(x) __attribute__ ((aligned(x))) +#ifdef IN_IDE_PARSER +/* KDevelop's parser doesn't recognize the C99-standard restrict keyword, but + * recent versions (at least 4.5.1) do recognize GCC's __restrict. */ +#define restrict __restrict +#endif -/* Define if we have the Android backend */ -/* #define HAVE_ANDROID 1 */ +/* Define any available alignment declaration */ +#define ALIGN(x) __attribute__((aligned(x))) + +/* Define if we have the C11 aligned_alloc function */ +/* #undef HAVE_ALIGNED_ALLOC */ + +/* Define if we have the posix_memalign function */ +/* #undef HAVE_POSIX_MEMALIGN */ + +/* Define if we have the _aligned_malloc function */ +/* #undef HAVE__ALIGNED_MALLOC */ + +/* Define if we have SSE CPU extensions */ +/* #undef HAVE_SSE */ +/* #undef HAVE_SSE2 */ +/* #undef HAVE_SSE4_1 */ + +/* Define if we have ARM Neon CPU extensions */ +/* #undef HAVE_NEON */ + +/* Define if we have FluidSynth support */ +/* #undef HAVE_FLUIDSYNTH */ /* Define if we have the ALSA backend */ -/* #define HAVE_ALSA */ +/* #undef HAVE_ALSA */ /* Define if we have the OSS backend */ -/* #cmakedefine HAVE_OSS */ +/* #undef HAVE_OSS */ /* Define if we have the Solaris backend */ -/* #cmakedefine HAVE_SOLARIS */ +/* #undef HAVE_SOLARIS */ /* Define if we have the SndIO backend */ -/* #cmakedefine HAVE_SNDIO */ +/* #undef HAVE_SNDIO */ + +/* Define if we have the QSA backend */ +/* #undef HAVE_QSA */ /* Define if we have the MMDevApi backend */ -/* #cmakedefine HAVE_MMDEVAPI */ +/* #undef HAVE_MMDEVAPI */ /* Define if we have the DSound backend */ -/* #cmakedefine HAVE_DSOUND */ +/* #undef HAVE_DSOUND */ /* Define if we have the Windows Multimedia backend */ -/* #cmakedefine HAVE_WINMM */ +/* #undef HAVE_WINMM */ /* Define if we have the PortAudio backend */ -/* #cmakedefine HAVE_PORTAUDIO */ +/* #undef HAVE_PORTAUDIO */ /* Define if we have the PulseAudio backend */ -/* #cmakedefine HAVE_PULSEAUDIO */ +/* #undef HAVE_PULSEAUDIO */ /* Define if we have the CoreAudio backend */ -/* #cmakedefine HAVE_COREAUDIO */ +/* #undef HAVE_COREAUDIO */ /* Define if we have the OpenSL backend */ -#define HAVE_OPENSL /* THIS BACKEND WORKS ON >=2.3 Android!! */ +#define HAVE_OPENSL /* Define if we have the Wave Writer backend */ -/* #cmakedefine HAVE_WAVE */ - -/* Define if we have dlfcn.h */ -#define HAVE_DLFCN_H +#define HAVE_WAVE /* Define if we have the stat function */ #define HAVE_STAT -/* Define if we have the powf function */ -/* #define HAVE_POWF 1 */ +/* Define if we have the lrintf function */ +#define HAVE_LRINTF -/* Define if we have the sqrtf function */ -/* #define HAVE_SQRTF 1 */ +/* Define if we have the strtof function */ +/* #undef HAVE_STRTOF */ -/* Define if we have the cosf function */ -/* #define HAVE_COSF 1 */ +/* Define if we have the __int64 type */ +/* #undef HAVE___INT64 */ -/* Define if we have the sinf function */ -/* #define HAVE_SINF 1 */ +/* Define to the size of a long int type */ +#define SIZEOF_LONG 4 -/* Define if we have the acosf function */ -/* #define HAVE_ACOSF 1 */ +/* Define to the size of a long long int type */ +#define SIZEOF_LONG_LONG 8 -/* Define if we have the asinf function */ -/* #define HAVE_ASINF 1 */ +/* Define if we have C99 variable-length array support */ +#define HAVE_C99_VLA -/* Define if we have the atanf function */ -/* #define HAVE_ATANF 1 */ +/* Define if we have C99 _Bool support */ +#define HAVE_C99_BOOL -/* Define if we have the atan2f function */ -/* #define HAVE_ATAN2F 1 */ +/* Define if we have C11 _Static_assert support */ +#define HAVE_C11_STATIC_ASSERT -/* Define if we have the fabsf function */ -/* #define HAVE_FABSF 1 */ +/* Define if we have C11 _Alignas support */ +/* #undef HAVE_C11_ALIGNAS */ -/* Define if we have the log10f function */ -/* #define HAVE_LOG10F 1 */ +/* Define if we have C11 _Atomic support */ +/* #undef HAVE_C11_ATOMIC */ -/* Define if we have the floorf function */ -/* #define HAVE_FLOORF 1 */ +/* Define if we have GCC's destructor attribute */ +#define HAVE_GCC_DESTRUCTOR -/* Define if we have the strtof function */ -#define HAVE_STRTOF +/* Define if we have GCC's format attribute */ +#define HAVE_GCC_FORMAT /* Define if we have stdint.h */ #define HAVE_STDINT_H -/* Define if we have the __int64 type */ -/* #cmakedefine HAVE___INT64 */ +/* Define if we have stdbool.h */ +#define HAVE_STDBOOL_H -/* Define to the size of a long int type */ -#define SIZEOF_LONG 4 +/* Define if we have stdalign.h */ +/* #undef HAVE_STDALIGN_H */ -/* Define to the size of a long long int type */ -#define SIZEOF_LONG_LONG 8 - -/* Define if we have GCC's destructor attribute */ -#define HAVE_GCC_DESTRUCTOR +/* Define if we have windows.h */ +/* #undef HAVE_WINDOWS_H */ -/* Define if we have GCC's format attribute */ -#define HAVE_GCC_FORMAT +/* Define if we have dlfcn.h */ +#define HAVE_DLFCN_H /* Define if we have pthread_np.h */ -/* #cmakedefine HAVE_PTHREAD_NP_H */ +/* #undef HAVE_PTHREAD_NP_H */ -/* Define if we have arm_neon.h */ -/* #cmakedefine HAVE_ARM_NEON_H */ +/* Define if we have alloca.h */ +/* #undef HAVE_ALLOCA_H */ -/* Define if we have guiddef.h */ -/* #cmakedefine HAVE_GUIDDEF_H */ +/* Define if we have malloc.h */ +#define HAVE_MALLOC_H + +/* Define if we have ftw.h */ +/* #undef HAVE_FTW_H */ + +/* Define if we have io.h */ +/* #undef HAVE_IO_H */ + +/* Define if we have strings.h */ +#define HAVE_STRINGS_H + +/* Define if we have cpuid.h */ +/* #undef HAVE_CPUID_H */ + +/* Define if we have intrin.h */ +/* #undef HAVE_INTRIN_H */ + +/* Define if we have sys/sysconf.h */ +#define HAVE_SYS_SYSCONF_H /* Define if we have guiddef.h */ -/* #cmakedefine HAVE_INITGUID_H */ +/* #undef HAVE_GUIDDEF_H */ + +/* Define if we have initguid.h */ +/* #undef HAVE_INITGUID_H */ /* Define if we have ieeefp.h */ -/* #cmakedefine HAVE_IEEEFP_H */ +/* #undef HAVE_IEEEFP_H */ /* Define if we have float.h */ -/* #cmakedefine HAVE_FLOAT_H */ - -/* Define if we have fpu_control.h */ -/* #cmakedefine HAVE_FPU_CONTROL_H */ +#define HAVE_FLOAT_H /* Define if we have fenv.h */ #define HAVE_FENV_H -/* Define if we have fesetround() */ -/* #cmakedefine HAVE_FESETROUND */ +/* Define if we have GCC's __get_cpuid() */ +/* #undef HAVE_GCC_GET_CPUID */ + +/* Define if we have the __cpuid() intrinsic */ +/* #undef HAVE_CPUID_INTRINSIC */ /* Define if we have _controlfp() */ -/* #cmakedefine HAVE__CONTROLFP */ +/* #undef HAVE__CONTROLFP */ + +/* Define if we have __control87_2() */ +/* #undef HAVE___CONTROL87_2 */ + +/* Define if we have ftw() */ +/* #undef HAVE_FTW */ + +/* Define if we have _wfindfirst() */ +/* #undef HAVE__WFINDFIRST */ /* Define if we have pthread_setschedparam() */ #define HAVE_PTHREAD_SETSCHEDPARAM -/* Define if we have the restrict keyword */ -/* #cmakedefine HAVE_RESTRICT 1 */ +/* Define if we have pthread_setname_np() */ +#define HAVE_PTHREAD_SETNAME_NP + +/* Define if we have pthread_set_name_np() */ +/* #undef HAVE_PTHREAD_SET_NAME_NP */ -/* Define if we have the __restrict keyword */ -#define RESTRICT __restrict +/* Define if we have pthread_mutexattr_setkind_np() */ +/* #undef HAVE_PTHREAD_MUTEXATTR_SETKIND_NP */ -#endif +/* Define if we have pthread_mutex_timedlock() */ +/* #undef HAVE_PTHREAD_MUTEX_TIMEDLOCK */ \ No newline at end of file diff --git a/jme3-android-native/src/native/jme_stbi/Android.mk b/jme3-android-native/src/native/jme_stbi/Android.mk index ba8a4e64e..469c63e4d 100644 --- a/jme3-android-native/src/native/jme_stbi/Android.mk +++ b/jme3-android-native/src/native/jme_stbi/Android.mk @@ -1,13 +1,15 @@ +TARGET_PLATFORM := android-9 + LOCAL_PATH := $(call my-dir) + include $(CLEAR_VARS) LOCAL_MODULE := stbijme -LOCAL_C_INCLUDES := $(LOCAL_PATH) -LOCAL_CFLAGS += -O2 -LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) -LOCAL_SRC_FILES := $(subst $(LOCAL_PATH)/,, $(wildcard $(LOCAL_PATH)/*.c)) - -#adds zlib -LOCAL_LDLIBS += -lz -llog + +LOCAL_C_INCLUDES += $(LOCAL_PATH) + +LOCAL_LDLIBS := -lz -llog -Wl,-s + +LOCAL_SRC_FILES := com_jme3_texture_plugins_AndroidNativeImageLoader.c include $(BUILD_SHARED_LIBRARY) diff --git a/jme3-android-native/src/native/jme_stbi/Application.mk b/jme3-android-native/src/native/jme_stbi/Application.mk index fcdc69644..fbc028f84 100644 --- a/jme3-android-native/src/native/jme_stbi/Application.mk +++ b/jme3-android-native/src/native/jme_stbi/Application.mk @@ -1,3 +1,3 @@ +APP_PLATFORM := android-9 APP_OPTIM := release -APP_ABI := all -#APP_ABI := armeabi-v7a +APP_ABI := all \ No newline at end of file diff --git a/jme3-android-native/src/native/jme_stbi/com_jme3_texture_plugins_AndroidNativeImageLoader.c b/jme3-android-native/src/native/jme_stbi/com_jme3_texture_plugins_AndroidNativeImageLoader.c index 45dbed0b0..a4064a622 100644 --- a/jme3-android-native/src/native/jme_stbi/com_jme3_texture_plugins_AndroidNativeImageLoader.c +++ b/jme3-android-native/src/native/jme_stbi/com_jme3_texture_plugins_AndroidNativeImageLoader.c @@ -6,8 +6,9 @@ #include #include #include -#define STBI_HEADER_FILE_ONLY -#include "stb_image.c" + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" typedef unsigned int uint32; diff --git a/jme3-android-native/stb_image.gradle b/jme3-android-native/stb_image.gradle index e5a0c3af7..61286d0af 100644 --- a/jme3-android-native/stb_image.gradle +++ b/jme3-android-native/stb_image.gradle @@ -1,6 +1,6 @@ // stb_image url for download -String stbiUrl = 'http://www.nothings.org/stb_image.c' -String stbiDownloadTarget = 'stb_image.c' +String stbiUrl = 'https://raw.githubusercontent.com/nothings/stb/master/stb_image.h' +String stbiDownloadTarget = 'stb_image.h' // stb_image is not downloaded. The single source file is included in the repo String stbiFolder = 'stb_image' @@ -63,20 +63,21 @@ task generateStbiHeaders(dependsOn: copyStbiJmeFiles) << { // println "stb_image destDir = " + destDir // println "stb_image classpath = " + project.projectClassPath - ant.javah( - classpath: project.projectClassPath, - destdir: destDirPath, - class: classes - ) - + exec { + executable org.gradle.internal.jvm.Jvm.current().getExecutable('javah') + args '-d', destDirPath + args '-classpath', project.projectClassPath + args "com.jme3.texture.plugins.AndroidNativeImageLoader" + } } task buildStbiNativeLib(type: Exec, dependsOn: generateStbiHeaders) { -// println "stb_image build dir: " + buildLibDir -// println "ndkCommandPath: " + project.ndkCommandPath - args 'TARGET_PLATFORM=android-9' +// println "stb_image build dir: " + stbiBuildDir +// println "ndkCommandPath: " + rootProject.ndkCommandPath + workingDir stbiBuildDir executable rootProject.ndkCommandPath + args '-j8' } task updatePreCompiledStbiLibs(type: Copy, dependsOn: buildStbiNativeLib) { diff --git a/jme3-android/src/main/java/com/jme3/app/AndroidHarness.java b/jme3-android/src/main/java/com/jme3/app/AndroidHarness.java index d14a27e30..9254944a5 100644 --- a/jme3-android/src/main/java/com/jme3/app/AndroidHarness.java +++ b/jme3-android/src/main/java/com/jme3/app/AndroidHarness.java @@ -6,6 +6,7 @@ import android.content.DialogInterface; import android.content.pm.ActivityInfo; import android.graphics.drawable.Drawable; import android.graphics.drawable.NinePatchDrawable; +import android.opengl.GLSurfaceView; import android.os.Bundle; import android.util.Log; import android.view.*; @@ -21,7 +22,6 @@ import com.jme3.input.android.AndroidSensorJoyInput; import com.jme3.input.controls.TouchListener; import com.jme3.input.controls.TouchTrigger; import com.jme3.input.event.TouchEvent; -import com.jme3.renderer.android.AndroidGLSurfaceView; import com.jme3.system.AppSettings; import com.jme3.system.SystemListener; import com.jme3.system.android.AndroidConfigChooser.ConfigType; @@ -195,7 +195,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt */ protected int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR; protected OGLESContext ctx; - protected AndroidGLSurfaceView view = null; + protected GLSurfaceView view = null; protected boolean isGLThreadPaused = true; protected ImageView splashImageView = null; protected FrameLayout frameLayout = null; diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java index f2ea5a4b4..9bccb5752 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java @@ -32,6 +32,7 @@ package com.jme3.input.android; +import android.opengl.GLSurfaceView; import android.os.Build; import android.view.View; import com.jme3.input.RawInputListener; @@ -41,7 +42,6 @@ import com.jme3.input.event.KeyInputEvent; import com.jme3.input.event.MouseButtonEvent; import com.jme3.input.event.MouseMotionEvent; import com.jme3.input.event.TouchEvent; -import com.jme3.renderer.android.AndroidGLSurfaceView; import com.jme3.system.AppSettings; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.logging.Level; @@ -67,7 +67,7 @@ public class AndroidInputHandler implements TouchInput { // Internal - private AndroidGLSurfaceView view; + private GLSurfaceView view; private AndroidTouchHandler touchHandler; private AndroidKeyHandler keyHandler; private AndroidGestureHandler gestureHandler; @@ -112,7 +112,7 @@ public class AndroidInputHandler implements TouchInput { if (gestureHandler != null) { gestureHandler.setView(view); } - this.view = (AndroidGLSurfaceView)view; + this.view = (GLSurfaceView)view; } public View getView() { diff --git a/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGLSurfaceView.java b/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGLSurfaceView.java deleted file mode 100644 index b328c6b79..000000000 --- a/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGLSurfaceView.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.jme3.renderer.android; - -import android.content.Context; -import android.opengl.GLSurfaceView; -import android.util.AttributeSet; -import java.util.logging.Logger; - -/** - * AndroidGLSurfaceView is derived from GLSurfaceView - * @author iwgeric - * - */ -public class AndroidGLSurfaceView extends GLSurfaceView { - - private final static Logger logger = Logger.getLogger(AndroidGLSurfaceView.class.getName()); - - public AndroidGLSurfaceView(Context ctx, AttributeSet attribs) { - super(ctx, attribs); - } - - public AndroidGLSurfaceView(Context ctx) { - super(ctx); - } - - -} \ No newline at end of file diff --git a/jme3-android/src/main/java/com/jme3/system/android/AndroidTimer.java b/jme3-android/src/main/java/com/jme3/system/android/AndroidTimer.java deleted file mode 100644 index 965895c41..000000000 --- a/jme3-android/src/main/java/com/jme3/system/android/AndroidTimer.java +++ /dev/null @@ -1,96 +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.android; - -import com.jme3.system.Timer; - -/** - * AndroidTimer is a System.nanoTime implementation of Timer. - */ -public class AndroidTimer extends Timer { - - //private static final long TIMER_RESOLUTION = 1000L; - //private static final float INVERSE_TIMER_RESOLUTION = 1f/1000L; - private static final long TIMER_RESOLUTION = 1000000000L; - private static final float INVERSE_TIMER_RESOLUTION = 1f/1000000000L; - - private long startTime; - private long previousTime; - private float tpf; - private float fps; - - public AndroidTimer() { - //startTime = System.currentTimeMillis(); - startTime = System.nanoTime(); - } - - /** - * Returns the time in seconds. The timer starts - * at 0.0 seconds. - * - * @return the current time in seconds - */ - @Override - public float getTimeInSeconds() { - return getTime() * INVERSE_TIMER_RESOLUTION; - } - - public long getTime() { - //return System.currentTimeMillis() - startTime; - return System.nanoTime() - startTime; - } - - public long getResolution() { - return TIMER_RESOLUTION; - } - - public float getFrameRate() { - return fps; - } - - public float getTimePerFrame() { - return tpf; - } - - public void update() { - tpf = (getTime() - previousTime) * (1.0f / TIMER_RESOLUTION); - fps = 1.0f / tpf; - previousTime = getTime(); - } - - public void reset() { - //startTime = System.currentTimeMillis(); - startTime = System.nanoTime(); - previousTime = getTime(); - } -} diff --git a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java index cf49c1cee..a01d1a480 100644 --- a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java +++ b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java @@ -47,13 +47,11 @@ import android.view.ViewGroup.LayoutParams; import android.widget.EditText; import android.widget.FrameLayout; import com.jme3.input.*; -import com.jme3.input.android.AndroidInput; import com.jme3.input.android.AndroidSensorJoyInput; import com.jme3.input.android.AndroidInputHandler; import com.jme3.input.controls.SoftTextDialogInputListener; import com.jme3.input.dummy.DummyKeyInput; import com.jme3.input.dummy.DummyMouseInput; -import com.jme3.renderer.android.AndroidGLSurfaceView; import com.jme3.renderer.android.OGLESShaderRenderer; import com.jme3.system.*; import java.util.concurrent.atomic.AtomicBoolean; @@ -80,11 +78,6 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex protected AndroidInputHandler androidInput; protected int minFrameDuration = 0; // No FPS cap protected JoyInput androidSensorJoyInput = null; - /** - * EGL_RENDERABLE_TYPE: EGL_OPENGL_ES_BIT = OpenGL ES 1.0 | - * EGL_OPENGL_ES2_BIT = OpenGL ES 2.0 - */ - protected int clientOpenGLESVersion = 1; public OGLESContext() { } @@ -103,12 +96,17 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex * * @return GLSurfaceView The newly created view */ - public AndroidGLSurfaceView createView() { - AndroidGLSurfaceView view; - int buildVersion = Build.VERSION.SDK_INT; - + public GLSurfaceView createView() { + Context appContext = JmeAndroidSystem.getActivity().getApplication(); + + ActivityManager am = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE); + ConfigurationInfo info = am.getDeviceConfigurationInfo(); + if (info.reqGlEsVersion < 0x20000) { + throw new UnsupportedOperationException("OpenGL ES 2.0 is not supported on this device"); + } + // Start to set up the view - view = new AndroidGLSurfaceView(JmeAndroidSystem.getActivity().getApplication()); + GLSurfaceView view = new GLSurfaceView(appContext); if (androidInput == null) { androidInput = new AndroidInputHandler(); } @@ -117,20 +115,11 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex // setEGLContextClientVersion must be set before calling setRenderer // this means it cannot be set in AndroidConfigChooser (too late) - int rawOpenGLESVersion = getOpenGLESVersion(); -// logger.log(Level.FINE, "clientOpenGLESVersion {0}.{1}", -// new Object[]{clientOpenGLESVersion>>16, clientOpenGLESVersion<<16}); - if (rawOpenGLESVersion < 0x20000) { - throw new UnsupportedOperationException("OpenGL ES 2.0 is not supported on this device"); - } else { - clientOpenGLESVersion = 2; - view.setEGLContextClientVersion(clientOpenGLESVersion); - } + view.setEGLContextClientVersion(2); view.setFocusableInTouchMode(true); view.setFocusable(true); - view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU); - + // setFormat must be set before AndroidConfigChooser is called by the surfaceview. // if setFormat is called after ConfigChooser is called, then execution // stops at the setFormat call without a crash. @@ -160,25 +149,13 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex // Not destroying and recreating the EGL context // will help with resume time by reusing the existing context to avoid // reloading all the OpenGL objects. - if (buildVersion >= 11) { + if (Build.VERSION.SDK_INT >= 11) { view.setPreserveEGLContextOnPause(true); } return view; } - /** - * Get the OpenGL ES version - * @return version returns the int value of the GLES version - */ - public int getOpenGLESVersion() { - ActivityManager am = - (ActivityManager) JmeAndroidSystem.getActivity().getApplication().getSystemService(Context.ACTIVITY_SERVICE); - ConfigurationInfo info = am.getDeviceConfigurationInfo(); - logger.log(Level.FINE, "OpenGL Version {0}:", info.getGlEsVersion()); - return info.reqGlEsVersion; -// return (info.reqGlEsVersion >= 0x20000); - } - + // renderer:initialize @Override public void onSurfaceCreated(GL10 gl, EGLConfig cfg) { @@ -207,7 +184,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex } }); - timer = new AndroidTimer(); + timer = new NanoTimer(); renderer = new OGLESShaderRenderer(); renderer.initialize(); 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 20fcd1e9a..489139ef5 100644 --- a/jme3-core/src/main/java/com/jme3/material/Material.java +++ b/jme3-core/src/main/java/com/jme3/material/Material.java @@ -42,7 +42,6 @@ import com.jme3.material.TechniqueDef.LightMode; import com.jme3.material.TechniqueDef.ShadowMode; import com.jme3.math.*; import com.jme3.renderer.Caps; -import com.jme3.renderer.GL1Renderer; import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.RendererException; @@ -52,7 +51,6 @@ 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.Texture; import com.jme3.texture.image.ColorSpace; @@ -697,12 +695,15 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { setParam(name, VarType.Vector4, value); } - private ColorRGBA getAmbientColor(LightList lightList) { + 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; @@ -741,75 +742,106 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { * g_LightPosition.w is the inverse radius (1/r) of the light (for * attenuation)

*/ - protected void updateLightListUniforms(Shader shader, Geometry g, LightList lightList, int numLights) { + 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; + return 0; } - Uniform lightColor = shader.getUniform("g_LightColor"); - Uniform lightPos = shader.getUniform("g_LightPosition"); - Uniform lightDir = shader.getUniform("g_LightDirection"); - lightColor.setVector4Length(numLights); - lightPos.setVector4Length(numLights); - lightDir.setVector4Length(numLights); - + Uniform lightData = shader.getUniform("g_LightData"); + lightData.setVector4Length(numLights * 3);//8 lights * max 3 Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); - ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList)); - - int lightIndex = 0; + - for (int i = 0; i < numLights; i++) { - if (lightList.size() <= i) { - lightColor.setVector4InArray(0f, 0f, 0f, 0f, lightIndex); - lightPos.setVector4InArray(0f, 0f, 0f, 0f, lightIndex); - } else { - Light l = lightList.get(i); + 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(); - lightColor.setVector4InArray(color.getRed(), + //Color + lightData.setVector4InArray(color.getRed(), color.getGreen(), color.getBlue(), l.getType().getId(), - i); - + lightDataIndex); + lightDataIndex++; + switch (l.getType()) { case Directional: DirectionalLight dl = (DirectionalLight) l; - Vector3f dir = dl.getDirection(); - lightPos.setVector4InArray(dir.getX(), dir.getY(), dir.getZ(), -1, lightIndex); + 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(); - lightPos.setVector4InArray(pos.getX(), pos.getY(), pos.getZ(), invRadius, lightIndex); + 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: + case Spot: SpotLight sl = (SpotLight) l; Vector3f pos2 = sl.getPosition(); Vector3f dir2 = sl.getDirection(); float invRange = sl.getInvSpotRange(); float spotAngleCos = sl.getPackedAngleCos(); - - lightPos.setVector4InArray(pos2.getX(), pos2.getY(), pos2.getZ(), invRange, lightIndex); - lightDir.setVector4InArray(dir2.getX(), dir2.getY(), dir2.getZ(), spotAngleCos, lightIndex); - break; - case Ambient: - // skip this light. Does not increase lightIndex - continue; + 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()); } - } - - lightIndex++; - } - - while (lightIndex < numLights) { - lightColor.setVector4InArray(0f, 0f, 0f, 0f, lightIndex); - lightPos.setVector4InArray(0f, 0f, 0f, 0f, lightIndex); - - lightIndex++; } + 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) { @@ -830,7 +862,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { if (isFirstLight) { // set ambient color for first light only - ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList)); + ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, false)); isFirstLight = false; isSecondLight = true; } else if (isSecondLight) { @@ -885,9 +917,9 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { tmpLightPosition.set(pos2.getX(), pos2.getY(), pos2.getZ(), invRange); lightPos.setValue(VarType.Vector4, tmpLightPosition); - //We transform the spot directoin in view space here to save 5 varying later in the lighting shader + //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 happen now in the frag shader. + //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); @@ -906,7 +938,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { if (isFirstLight && lightList.size() > 0) { // There are only ambient lights in the scene. Render // a dummy "normal light" so we can see the ambient - ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList)); + ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, false)); lightColor.setValue(VarType.Vector4, ColorRGBA.BlackNoAlpha); lightPos.setValue(VarType.Vector4, nullDirLight); r.setShader(shader); @@ -955,9 +987,12 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { for (TechniqueDef techDef : techDefs) { if (rendererCaps.containsAll(techDef.getRequiredCaps())) { // use the first one that supports all the caps - tech = new Technique(this, techDef); + tech = new Technique(this, techDef); techniques.put(name, tech); - break; + if(tech.getDef().getLightMode() == renderManager.getPreferredLightMode() || + tech.getDef().getLightMode() == LightMode.Disable){ + break; + } } lastTech = techDef; } @@ -990,7 +1025,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { } technique = tech; - tech.makeCurrent(def.getAssetManager(), true, rendererCaps); + tech.makeCurrent(def.getAssetManager(), true, rendererCaps, renderManager); // shader was changed sortingId = -1; @@ -1000,7 +1035,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { if (technique == null) { selectTechnique("Default", rm); } else { - technique.makeCurrent(def.getAssetManager(), false, rm.getRenderer().getCaps()); + technique.makeCurrent(def.getAssetManager(), false, rm.getRenderer().getCaps(), rm); } } @@ -1162,8 +1197,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { r.setLighting(null); break; case SinglePass: - updateLightListUniforms(shader, geom, lights, 4); - break; + int nbRenderedLights = 0; + resetUniformsNotSetByCurrent(shader); + while(nbRenderedLights < lights.size()){ + nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, nbRenderedLights); + r.setShader(shader); + renderMeshFromGeometry(r, geom); + } + return; case FixedPipeline: r.setLighting(lights); break; 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 b99cbc3bb..024311551 100644 --- a/jme3-core/src/main/java/com/jme3/material/Technique.java +++ b/jme3-core/src/main/java/com/jme3/material/Technique.java @@ -33,8 +33,8 @@ package com.jme3.material; import com.jme3.asset.AssetManager; import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; import com.jme3.shader.*; -import com.jme3.util.ListMap; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; @@ -172,7 +172,7 @@ public class Technique /* implements Savable */ { * * @param assetManager The asset manager to use for loading shaders. */ - public void makeCurrent(AssetManager assetManager, boolean techniqueSwitched, EnumSet rendererCaps) { + public void makeCurrent(AssetManager assetManager, boolean techniqueSwitched, EnumSet rendererCaps, RenderManager rm) { if (!def.isUsingShaders()) { // No shaders are used, no processing is neccessary. return; @@ -182,6 +182,13 @@ public class Technique /* implements Savable */ { 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) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/Caps.java b/jme3-core/src/main/java/com/jme3/renderer/Caps.java index 80c5b976a..d4a7ae79e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Caps.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Caps.java @@ -236,7 +236,22 @@ public enum Caps { /** * Supports sRGB framebuffers and sRGB texture format */ - Srgb; + Srgb, + + /** + * Supports blitting framebuffers. + */ + FrameBufferBlit, + + /** + * Supports {@link Format#DXT1} and sister formats. + */ + TextureCompressionS3TC, + + /** + * Supports anisotropic texture filtering. + */ + TextureFilterAnisotropic; /** * Returns true if given the renderer capabilities, the texture 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 ea89ab58c..8fa479e44 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java @@ -35,6 +35,7 @@ import com.jme3.material.RenderState; import com.jme3.math.ColorRGBA; import com.jme3.scene.Mesh; import com.jme3.scene.VertexBuffer; +import com.jme3.shader.Shader; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; @@ -138,11 +139,21 @@ public class RenderContext { * @see Renderer#setShader(com.jme3.shader.Shader) */ public int boundShaderProgram; + + /** + * @see Renderer#setShader(com.jme3.shader.Shader) + */ + public Shader boundShader; /** * @see Renderer#setFrameBuffer(com.jme3.texture.FrameBuffer) */ public int boundFBO = 0; + + /** + * @see Renderer#setFrameBuffer(com.jme3.texture.FrameBuffer) + */ + public FrameBuffer boundFB; /** * Currently bound Renderbuffer @@ -279,6 +290,10 @@ public class RenderContext { */ public RenderState.TestFunction alphaFunc = RenderState.TestFunction.Greater; + + public int initialDrawBuf; + public int initialReadBuf; + /** * Reset the RenderContext to default GL state */ @@ -298,7 +313,9 @@ public class RenderContext { blendMode = RenderState.BlendMode.Off; wireframe = false; boundShaderProgram = 0; + boundShader = null; boundFBO = 0; + boundFB = null; boundRB = 0; boundDrawBuf = -1; boundReadBuf = -1; 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 b8aa705fb..592ecf3cf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -38,6 +38,7 @@ 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; @@ -89,6 +90,8 @@ public class RenderManager { 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 @@ -780,6 +783,33 @@ public class RenderManager { vp.getQueue().clear(); } + /** + * Sets the light filter to use when rendering Lighted Geometries + * + * @see LightFilter + * @param lightFilter The light filter tose. Set it to null if you want all lights to be rendered + */ + public void setLightFilter(LightFilter lightFilter) { + this.lightFilter = lightFilter; + } + + public void setPreferredLightMode(TechniqueDef.LightMode preferredLightMode) { + this.preferredLightMode = preferredLightMode; + } + + public TechniqueDef.LightMode getPreferredLightMode() { + return preferredLightMode; + } + + public int getSinglePassLightBatchSize() { + return singlePassLightBatchSize; + } + + public void setSinglePassLightBatchSize(int singlePassLightBatchSize) { + this.singlePassLightBatchSize = singlePassLightBatchSize; + } + + /** * Render the given viewport queues. *

diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag index e4773c8cf..a1f58b898 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag @@ -1,7 +1,9 @@ #import "Common/ShaderLib/Parallax.glsllib" #import "Common/ShaderLib/Optics.glsllib" -#define ATTENUATION -//#define HQ_ATTENUATION +#ifndef VERTEX_LIGHTING + #import "Common/ShaderLib/PhongLighting.glsllib" + #import "Common/ShaderLib/Lighting.glsllib" +#endif varying vec2 texCoord; #ifdef SEPARATE_TEXCOORD @@ -58,82 +60,14 @@ varying vec3 SpecularSum; uniform float m_AlphaDiscardThreshold; #ifndef VERTEX_LIGHTING -uniform float m_Shininess; - -#ifdef HQ_ATTENUATION -uniform vec4 g_LightPosition; -#endif + uniform float m_Shininess; + #ifdef USE_REFLECTION + uniform float m_ReflectionPower; + uniform float m_ReflectionIntensity; + varying vec4 refVec; -#ifdef USE_REFLECTION - uniform float m_ReflectionPower; - uniform float m_ReflectionIntensity; - varying vec4 refVec; - - uniform ENVMAP m_EnvMap; -#endif - -float tangDot(in vec3 v1, in vec3 v2){ - float d = dot(v1,v2); - #ifdef V_TANGENT - d = 1.0 - d*d; - return step(0.0, d) * sqrt(d); - #else - return d; + uniform ENVMAP m_EnvMap; #endif -} - -float lightComputeDiffuse(in vec3 norm, in vec3 lightdir, in vec3 viewdir){ - #ifdef MINNAERT - float NdotL = max(0.0, dot(norm, lightdir)); - float NdotV = max(0.0, dot(norm, viewdir)); - return NdotL * pow(max(NdotL * NdotV, 0.1), -1.0) * 0.5; - #else - return max(0.0, dot(norm, lightdir)); - #endif -} - -float lightComputeSpecular(in vec3 norm, in vec3 viewdir, in vec3 lightdir, in float shiny){ - // NOTE: check for shiny <= 1 removed since shininess is now - // 1.0 by default (uses matdefs default vals) - #ifdef LOW_QUALITY - // Blinn-Phong - // Note: preferably, H should be computed in the vertex shader - vec3 H = (viewdir + lightdir) * vec3(0.5); - return pow(max(tangDot(H, norm), 0.0), shiny); - #elif defined(WARDISO) - // Isotropic Ward - vec3 halfVec = normalize(viewdir + lightdir); - float NdotH = max(0.001, tangDot(norm, halfVec)); - float NdotV = max(0.001, tangDot(norm, viewdir)); - float NdotL = max(0.001, tangDot(norm, lightdir)); - float a = tan(acos(NdotH)); - float p = max(shiny/128.0, 0.001); - return NdotL * (1.0 / (4.0*3.14159265*p*p)) * (exp(-(a*a)/(p*p)) / (sqrt(NdotV * NdotL))); - #else - // Standard Phong - vec3 R = reflect(-lightdir, norm); - return pow(max(tangDot(R, viewdir), 0.0), shiny); - #endif -} - -vec2 computeLighting(in vec3 wvNorm, in vec3 wvViewDir, in vec3 wvLightDir){ - float diffuseFactor = lightComputeDiffuse(wvNorm, wvLightDir, wvViewDir); - float specularFactor = lightComputeSpecular(wvNorm, wvViewDir, wvLightDir, m_Shininess); - - #ifdef HQ_ATTENUATION - float att = clamp(1.0 - g_LightPosition.w * length(lightVec), 0.0, 1.0); - #else - float att = vLightDir.w; - #endif - - if (m_Shininess <= 1.0) { - specularFactor = 0.0; // should be one instruction on most cards .. - } - - specularFactor *= diffuseFactor; - - return vec2(diffuseFactor, specularFactor) * vec2(att); -} #endif void main(){ @@ -172,40 +106,13 @@ void main(){ #ifdef ALPHAMAP alpha = alpha * texture2D(m_AlphaMap, newTexCoord).r; #endif - if(alpha < m_AlphaDiscardThreshold){ - discard; - } - - #ifndef VERTEX_LIGHTING - float spotFallOff = 1.0; - - #if __VERSION__ >= 110 - // allow use of control flow - if(g_LightDirection.w != 0.0){ - #endif + #ifdef DISCARD_ALPHA + if(alpha < m_AlphaDiscardThreshold){ + discard; + } + #endif - vec3 L = normalize(lightVec.xyz); - vec3 spotdir = normalize(g_LightDirection.xyz); - float curAngleCos = dot(-L, spotdir); - float innerAngleCos = floor(g_LightDirection.w) * 0.001; - float outerAngleCos = fract(g_LightDirection.w); - float innerMinusOuter = innerAngleCos - outerAngleCos; - spotFallOff = (curAngleCos - outerAngleCos) / innerMinusOuter; - #if __VERSION__ >= 110 - if(spotFallOff <= 0.0){ - gl_FragColor.rgb = AmbientSum * diffuseColor.rgb; - gl_FragColor.a = alpha; - return; - }else{ - spotFallOff = clamp(spotFallOff, 0.0, 1.0); - } - } - #else - spotFallOff = clamp(spotFallOff, step(g_LightDirection.w, 0.001), 1.0); - #endif - #endif - // *********************** // Read from textures // *********************** @@ -257,8 +164,23 @@ void main(){ vec4 lightDir = vLightDir; lightDir.xyz = normalize(lightDir.xyz); vec3 viewDir = normalize(vViewDir); + float spotFallOff = 1.0; + + #if __VERSION__ >= 110 + // allow use of control flow + if(g_LightDirection.w != 0.0){ + #endif + spotFallOff = computeSpotFalloff(g_LightDirection, lightVec); + #if __VERSION__ >= 110 + if(spotFallOff <= 0.0){ + gl_FragColor.rgb = AmbientSum * diffuseColor.rgb; + gl_FragColor.a = alpha; + return; + } + } + #endif - vec2 light = computeLighting(normal, viewDir, lightDir.xyz) * spotFallOff; + vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff, m_Shininess) ; #ifdef COLORRAMP diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb; specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb; 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 779242445..e5613f040 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md @@ -6,34 +6,12 @@ MaterialDef Phong Lighting { // For better performance Boolean VertexLighting - // Use more efficent algorithms to improve performance - Boolean LowQuality - - // Improve quality at the cost of performance - Boolean HighQuality - - // Output alpha from the diffuse map - Boolean UseAlpha - // Alpha threshold for fragment discarding Float AlphaDiscardThreshold (AlphaTestFallOff) - // Normal map is in BC5/ATI2n/LATC/3Dc compression format - Boolean LATC - // Use the provided ambient, diffuse, and specular colors Boolean UseMaterialColors - // Activate shading along the tangent, instead of the normal - // Requires tangent data to be available on the model. - Boolean VTangent - - // Use minnaert diffuse instead of lambert - Boolean Minnaert - - // Use ward specular instead of phong - Boolean WardIso - // Use vertex color as an additional diffuse color. Boolean UseVertexColor @@ -133,9 +111,48 @@ MaterialDef Phong Lighting { Int NumberOfBones Matrix4Array BoneMatrices + //For instancing Boolean UseInstancing } + Technique { + LightMode SinglePass + + VertexShader GLSL100: Common/MatDefs/Light/SPLighting.vert + FragmentShader GLSL100: Common/MatDefs/Light/SPLighting.frag + + WorldParameters { + WorldViewProjectionMatrix + NormalMatrix + WorldViewMatrix + ViewMatrix + CameraPosition + WorldMatrix + ViewProjectionMatrix + } + + Defines { + VERTEX_COLOR : UseVertexColor + VERTEX_LIGHTING : VertexLighting + MATERIAL_COLORS : UseMaterialColors + DIFFUSEMAP : DiffuseMap + NORMALMAP : NormalMap + SPECULARMAP : SpecularMap + PARALLAXMAP : ParallaxMap + NORMALMAP_PARALLAX : PackedNormalParallax + STEEP_PARALLAX : SteepParallax + ALPHAMAP : AlphaMap + COLORRAMP : ColorRamp + LIGHTMAP : LightMap + SEPARATE_TEXCOORD : SeparateTexCoord + DISCARD_ALPHA : AlphaDiscardThreshold + USE_REFLECTION : EnvMap + SPHERE_MAP : SphereMap + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + } + Technique { LightMode MultiPass @@ -154,17 +171,9 @@ MaterialDef Phong Lighting { } Defines { - LATC : LATC VERTEX_COLOR : UseVertexColor - VERTEX_LIGHTING : VertexLighting - ATTENUATION : Attenuation + VERTEX_LIGHTING : VertexLighting MATERIAL_COLORS : UseMaterialColors - V_TANGENT : VTangent - MINNAERT : Minnaert - WARDISO : WardIso - LOW_QUALITY : LowQuality - HQ_ATTENUATION : HighQuality - DIFFUSEMAP : DiffuseMap NORMALMAP : NormalMap SPECULARMAP : SpecularMap @@ -175,16 +184,16 @@ MaterialDef Phong Lighting { COLORRAMP : ColorRamp LIGHTMAP : LightMap SEPARATE_TEXCOORD : SeparateTexCoord - + DISCARD_ALPHA : AlphaDiscardThreshold USE_REFLECTION : EnvMap SPHERE_MAP : SphereMap - - NUM_BONES : NumberOfBones - + NUM_BONES : NumberOfBones INSTANCING : UseInstancing } } + + Technique PreShadow { VertexShader GLSL100 : Common/MatDefs/Shadow/PreShadow.vert @@ -373,4 +382,4 @@ MaterialDef Phong Lighting { } } -} \ No newline at end of file +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert index 737786fb4..1901ebc67 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert @@ -1,8 +1,10 @@ #import "Common/ShaderLib/Instancing.glsllib" -#define ATTENUATION -//#define HQ_ATTENUATION - #import "Common/ShaderLib/Skinning.glsllib" +#import "Common/ShaderLib/Lighting.glsllib" +#ifdef VERTEX_LIGHTING + #import "Common/ShaderLib/PhongLighting.glsllib" +#endif + uniform vec4 m_Ambient; uniform vec4 m_Diffuse; @@ -28,7 +30,6 @@ attribute vec2 inTexCoord; attribute vec3 inNormal; varying vec3 lightVec; -//varying vec4 spotVec; #ifdef VERTEX_COLOR attribute vec4 inColor; @@ -39,8 +40,7 @@ varying vec3 lightVec; #ifndef NORMALMAP varying vec3 vNormal; - #endif - //varying vec3 vPosition; + #endif varying vec3 vViewDir; varying vec4 vLightDir; #else @@ -77,57 +77,6 @@ varying vec3 lightVec; } #endif -// JME3 lights in world space -void lightComputeDir(in vec3 worldPos, in vec4 color, in vec4 position, out vec4 lightDir){ - float posLight = step(0.5, color.w); - vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight); - lightVec = tempVec; - #ifdef ATTENUATION - float dist = length(tempVec); - lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0); - lightDir.xyz = tempVec / vec3(dist); - #else - lightDir = vec4(normalize(tempVec), 1.0); - #endif -} - -#ifdef VERTEX_LIGHTING - float lightComputeDiffuse(in vec3 norm, in vec3 lightdir){ - return max(0.0, dot(norm, lightdir)); - } - - float lightComputeSpecular(in vec3 norm, in vec3 viewdir, in vec3 lightdir, in float shiny){ - if (shiny <= 1.0){ - return 0.0; - } - #ifndef LOW_QUALITY - vec3 H = (viewdir + lightdir) * vec3(0.5); - return pow(max(dot(H, norm), 0.0), shiny); - #else - return 0.0; - #endif - } - -vec2 computeLighting(in vec3 wvPos, in vec3 wvNorm, in vec3 wvViewDir, in vec4 wvLightPos){ - vec4 lightDir; - lightComputeDir(wvPos, g_LightColor, wvLightPos, lightDir); - float spotFallOff = 1.0; - if(g_LightDirection.w != 0.0){ - vec3 L=normalize(lightVec.xyz); - vec3 spotdir = normalize(g_LightDirection.xyz); - float curAngleCos = dot(-L, spotdir); - float innerAngleCos = floor(g_LightDirection.w) * 0.001; - float outerAngleCos = fract(g_LightDirection.w); - float innerMinusOuter = innerAngleCos - outerAngleCos; - spotFallOff = clamp((curAngleCos - outerAngleCos) / innerMinusOuter, 0.0, 1.0); - } - float diffuseFactor = lightComputeDiffuse(wvNorm, lightDir.xyz); - float specularFactor = lightComputeSpecular(wvNorm, wvViewDir, lightDir.xyz, m_Shininess); - //specularFactor *= step(0.01, diffuseFactor); - return vec2(diffuseFactor, specularFactor) * vec2(lightDir.w)*spotFallOff; - } -#endif - void main(){ vec4 modelSpacePos = vec4(inPosition, 1.0); vec3 modelSpaceNorm = inNormal; @@ -154,11 +103,6 @@ void main(){ vec3 wvNormal = normalize(TransformNormal(modelSpaceNorm));//normalize(g_NormalMatrix * modelSpaceNorm); vec3 viewDir = normalize(-wvPosition); - //vec4 lightColor = g_LightColor[gl_InstanceID]; - //vec4 lightPos = g_LightPosition[gl_InstanceID]; - //vec4 wvLightPos = (g_ViewMatrix * vec4(lightPos.xyz, lightColor.w)); - //wvLightPos.w = lightPos.w; - vec4 wvLightPos = (g_ViewMatrix * vec4(g_LightPosition.xyz,clamp(g_LightColor.w,0.0,1.0))); wvLightPos.w = g_LightPosition.w; vec4 lightColor = g_LightColor; @@ -166,41 +110,24 @@ void main(){ #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) vec3 wvTangent = normalize(TransformNormal(modelSpaceTan)); vec3 wvBinormal = cross(wvNormal, wvTangent); - mat3 tbnMat = mat3(wvTangent, wvBinormal * inTangent.w,wvNormal); - - //vPosition = wvPosition * tbnMat; - //vViewDir = viewDir * tbnMat; + vViewDir = -wvPosition * tbnMat; - lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir); + lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz; #elif !defined(VERTEX_LIGHTING) vNormal = wvNormal; - - //vPosition = wvPosition; vViewDir = viewDir; - - lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir); - - #ifdef V_TANGENT - vNormal = normalize(TransformNormal(inTangent.xyz)); - vNormal = -cross(cross(vLightDir.xyz, vNormal), vNormal); - #endif + lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); #endif - //computing spot direction in view space and unpacking spotlight cos -// spotVec = (g_ViewMatrix * vec4(g_LightDirection.xyz, 0.0) ); -// spotVec.w = floor(g_LightDirection.w) * 0.001; -// lightVec.w = fract(g_LightDirection.w); - - lightColor.w = 1.0; #ifdef MATERIAL_COLORS AmbientSum = (m_Ambient * g_AmbientLightColor).rgb; - DiffuseSum = m_Diffuse * lightColor; + DiffuseSum = m_Diffuse * vec4(lightColor.rgb, 1.0); SpecularSum = (m_Specular * lightColor).rgb; #else - AmbientSum = vec3(0.2, 0.2, 0.2) * g_AmbientLightColor.rgb; // Default: ambient color is dark gray - DiffuseSum = lightColor; + AmbientSum = g_AmbientLightColor.rgb; // Default: ambient color is dark gray + DiffuseSum = vec4(lightColor.rgb, 1.0); SpecularSum = vec3(0.0); #endif @@ -210,10 +137,22 @@ void main(){ #endif #ifdef VERTEX_LIGHTING - vertexLightValues = computeLighting(wvPosition, wvNormal, viewDir, wvLightPos); + float spotFallOff = 1.0; + vec4 vLightDir; + lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); + #if __VERSION__ >= 110 + // allow use of control flow + if(lightColor.w > 1.0){ + #endif + spotFallOff = computeSpotFalloff(g_LightDirection, lightVec); + #if __VERSION__ >= 110 + } + #endif + + vertexLightValues = computeLighting(wvNormal, viewDir, vLightDir.xyz, vLightDir.w * spotFallOff, m_Shininess); #endif - #ifdef USE_REFLECTION + #ifdef USE_REFLECTION computeRef(modelSpacePos); #endif } \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag new file mode 100644 index 000000000..09478c6e8 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag @@ -0,0 +1,218 @@ +#import "Common/ShaderLib/Parallax.glsllib" +#import "Common/ShaderLib/Optics.glsllib" +#ifndef VERTEX_LIGHTING + #import "Common/ShaderLib/PhongLighting.glsllib" + #import "Common/ShaderLib/Lighting.glsllib" +#endif + +varying vec2 texCoord; +#ifdef SEPARATE_TEXCOORD + varying vec2 texCoord2; +#endif + +varying vec3 AmbientSum; +varying vec4 DiffuseSum; +varying vec3 SpecularSum; + +#ifndef VERTEX_LIGHTING + uniform mat4 g_ViewMatrix; + uniform vec4 g_LightData[NB_LIGHTS]; + varying vec3 vPos; +#else + varying vec3 specularAccum; + varying vec4 diffuseAccum; +#endif + +#ifdef DIFFUSEMAP + uniform sampler2D m_DiffuseMap; +#endif + +#ifdef SPECULARMAP + uniform sampler2D m_SpecularMap; +#endif + +#ifdef PARALLAXMAP + uniform sampler2D m_ParallaxMap; +#endif +#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING) + uniform float m_ParallaxHeight; +#endif + +#ifdef LIGHTMAP + uniform sampler2D m_LightMap; +#endif + +#ifdef NORMALMAP + uniform sampler2D m_NormalMap; + varying vec3 vTangent; + varying vec3 vBinormal; +#endif +varying vec3 vNormal; + +#ifdef ALPHAMAP + uniform sampler2D m_AlphaMap; +#endif + +#ifdef COLORRAMP + uniform sampler2D m_ColorRamp; +#endif + +uniform float m_AlphaDiscardThreshold; + +#ifndef VERTEX_LIGHTING +uniform float m_Shininess; + + #ifdef USE_REFLECTION + uniform float m_ReflectionPower; + uniform float m_ReflectionIntensity; + varying vec4 refVec; + + uniform ENVMAP m_EnvMap; + #endif +#endif + +void main(){ + vec2 newTexCoord; + + #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING) + + #ifdef STEEP_PARALLAX + #ifdef NORMALMAP_PARALLAX + //parallax map is stored in the alpha channel of the normal map + newTexCoord = steepParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight); + #else + //parallax map is a texture + newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight); + #endif + #else + #ifdef NORMALMAP_PARALLAX + //parallax map is stored in the alpha channel of the normal map + newTexCoord = classicParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight); + #else + //parallax map is a texture + newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight); + #endif + #endif + #else + newTexCoord = texCoord; + #endif + + #ifdef DIFFUSEMAP + vec4 diffuseColor = texture2D(m_DiffuseMap, newTexCoord); + #else + vec4 diffuseColor = vec4(1.0); + #endif + + float alpha = DiffuseSum.a * diffuseColor.a; + + #ifdef ALPHAMAP + alpha = alpha * texture2D(m_AlphaMap, newTexCoord).r; + #endif + + #ifdef DISCARD_ALPHA + if(alpha < m_AlphaDiscardThreshold){ + discard; + } + #endif + + // *********************** + // Read from textures + // *********************** + #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) + vec4 normalHeight = texture2D(m_NormalMap, newTexCoord); + //Note the -2.0 and -1.0. We invert the green channel of the normal map, + //as it's complient with normal maps generated with blender. + //see http://hub.jmonkeyengine.org/forum/topic/parallax-mapping-fundamental-bug/#post-256898 + //for more explanation. + vec3 normal = normalize((normalHeight.xyz * vec3(2.0,-2.0,2.0) - vec3(1.0,-1.0,1.0))); + #elif !defined(VERTEX_LIGHTING) + vec3 normal = normalize(vNormal); + #endif + + #ifdef SPECULARMAP + vec4 specularColor = texture2D(m_SpecularMap, newTexCoord); + #else + vec4 specularColor = vec4(1.0); + #endif + + #ifdef LIGHTMAP + vec3 lightMapColor; + #ifdef SEPARATE_TEXCOORD + lightMapColor = texture2D(m_LightMap, texCoord2).rgb; + #else + lightMapColor = texture2D(m_LightMap, texCoord).rgb; + #endif + specularColor.rgb *= lightMapColor; + diffuseColor.rgb *= lightMapColor; + #endif + + #ifdef VERTEX_LIGHTING + gl_FragColor.rgb = AmbientSum * diffuseColor.rgb + +diffuseAccum.rgb *diffuseColor.rgb + +specularAccum.rgb * specularColor.rgb; + gl_FragColor.a=1.0; + #else + + int i = 0; + gl_FragColor.rgb = AmbientSum * diffuseColor.rgb; + + #ifdef USE_REFLECTION + vec4 refColor = Optics_GetEnvColor(m_EnvMap, refVec.xyz); + #endif + + #ifdef NORMALMAP + mat3 tbnMat = mat3(normalize(vTangent.xyz) , normalize(vBinormal.xyz) , normalize(vNormal.xyz)); + #endif + + for( int i = 0;i < NB_LIGHTS; i+=3){ + vec4 lightColor = g_LightData[i]; + vec4 lightData1 = g_LightData[i+1]; + vec4 lightDir; + vec3 lightVec; + lightComputeDir(vPos, lightColor.w, lightData1, lightDir,lightVec); + + float spotFallOff = 1.0; + #if __VERSION__ >= 110 + // allow use of control flow + if(lightColor.w > 1.0){ + #endif + spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); + #if __VERSION__ >= 110 + } + #endif + + #ifdef NORMALMAP + //Normal map -> lighting is computed in tangent space + lightDir.xyz = normalize(lightDir.xyz * tbnMat); + vec3 viewDir = normalize(-vPos.xyz * tbnMat); + #else + //no Normal map -> lighting is computed in view space + lightDir.xyz = normalize(lightDir.xyz); + vec3 viewDir = normalize(-vPos.xyz); + #endif + + vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff , m_Shininess); + + #ifdef COLORRAMP + diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb; + specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb; + #endif + + // Workaround, since it is not possible to modify varying variables + vec4 SpecularSum2 = vec4(SpecularSum, 1.0); + #ifdef USE_REFLECTION + // Interpolate light specularity toward reflection color + // Multiply result by specular map + specularColor = mix(SpecularSum2 * light.y, refColor, refVec.w) * specularColor; + + SpecularSum2 = vec4(1.0); + light.y = 1.0; + #endif + + gl_FragColor.rgb += DiffuseSum.rgb * lightColor.rgb * diffuseColor.rgb * vec3(light.x) + + SpecularSum2.rgb * specularColor.rgb * vec3(light.y); + } + + #endif + gl_FragColor.a = alpha; +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert new file mode 100644 index 000000000..81ea869b6 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert @@ -0,0 +1,172 @@ +#import "Common/ShaderLib/Instancing.glsllib" +#import "Common/ShaderLib/Skinning.glsllib" +#import "Common/ShaderLib/Lighting.glsllib" +#ifdef VERTEX_LIGHTING + #import "Common/ShaderLib/PhongLighting.glsllib" +#endif + + +uniform vec4 m_Ambient; +uniform vec4 m_Diffuse; +uniform vec4 m_Specular; +uniform float m_Shininess; + +#if defined(VERTEX_LIGHTING) + uniform vec4 g_LightData[NB_LIGHTS]; +#endif +uniform vec4 g_AmbientLightColor; +varying vec2 texCoord; + +#ifdef SEPARATE_TEXCOORD + varying vec2 texCoord2; + attribute vec2 inTexCoord2; +#endif + +varying vec3 AmbientSum; +varying vec4 DiffuseSum; +varying vec3 SpecularSum; + +attribute vec3 inPosition; +attribute vec2 inTexCoord; +attribute vec3 inNormal; + +#ifdef VERTEX_COLOR + attribute vec4 inColor; +#endif + +#ifndef VERTEX_LIGHTING + varying vec3 vNormal; + varying vec3 vPos; + #ifdef NORMALMAP + attribute vec4 inTangent; + varying vec3 vTangent; + varying vec3 vBinormal; + #endif +#else + varying vec3 specularAccum; + varying vec4 diffuseAccum; +#endif + +#ifdef USE_REFLECTION + uniform vec3 g_CameraPosition; + uniform vec3 m_FresnelParams; + varying vec4 refVec; + + /** + * Input: + * attribute inPosition + * attribute inNormal + * uniform g_WorldMatrix + * uniform g_CameraPosition + * + * Output: + * varying refVec + */ + void computeRef(in vec4 modelSpacePos){ + // vec3 worldPos = (g_WorldMatrix * modelSpacePos).xyz; + vec3 worldPos = TransformWorld(modelSpacePos).xyz; + + vec3 I = normalize( g_CameraPosition - worldPos ).xyz; + // vec3 N = normalize( (g_WorldMatrix * vec4(inNormal, 0.0)).xyz ); + vec3 N = normalize( TransformWorld(vec4(inNormal, 0.0)).xyz ); + + refVec.xyz = reflect(I, N); + refVec.w = m_FresnelParams.x + m_FresnelParams.y * pow(1.0 + dot(I, N), m_FresnelParams.z); + } +#endif + +void main(){ + vec4 modelSpacePos = vec4(inPosition, 1.0); + vec3 modelSpaceNorm = inNormal; + + #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) + vec3 modelSpaceTan = inTangent.xyz; + #endif + + #ifdef NUM_BONES + #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) + Skinning_Compute(modelSpacePos, modelSpaceNorm, modelSpaceTan); + #else + Skinning_Compute(modelSpacePos, modelSpaceNorm); + #endif + #endif + + gl_Position = TransformWorldViewProjection(modelSpacePos); + texCoord = inTexCoord; + #ifdef SEPARATE_TEXCOORD + texCoord2 = inTexCoord2; + #endif + + vec3 wvPosition = TransformWorldView(modelSpacePos).xyz; + vec3 wvNormal = normalize(TransformNormal(modelSpaceNorm)); + vec3 viewDir = normalize(-wvPosition); + + + #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) + vTangent = TransformNormal(modelSpaceTan); + vBinormal = cross(wvNormal, vTangent)* inTangent.w; + vNormal = wvNormal; + vPos = wvPosition; + #elif !defined(VERTEX_LIGHTING) + vNormal = wvNormal; + vPos = wvPosition; + #endif + + #ifdef MATERIAL_COLORS + AmbientSum = m_Ambient.rgb * g_AmbientLightColor.rgb; + SpecularSum = m_Specular.rgb; + DiffuseSum = m_Diffuse; + #else + AmbientSum = g_AmbientLightColor.rgb; + SpecularSum = vec3(0.0); + DiffuseSum = vec4(1.0); + #endif + #ifdef VERTEX_COLOR + AmbientSum *= inColor.rgb; + DiffuseSum *= inColor; + #endif + #ifdef VERTEX_LIGHTING + int i = 0; + diffuseAccum = vec4(0.0); + specularAccum = vec3(0.0); + vec4 diffuseColor; + vec3 specularColor; + for (int i =0;i < NB_LIGHTS; i+=3){ + vec4 lightColor = g_LightData[i]; + vec4 lightData1 = g_LightData[i+1]; + DiffuseSum = vec4(1.0); + #ifdef MATERIAL_COLORS + diffuseColor = m_Diffuse * vec4(lightColor.rgb, 1.0); + specularColor = m_Specular.rgb * lightColor.rgb; + #else + diffuseColor = vec4(lightColor.rgb, 1.0); + specularColor = vec3(0.0); + #endif + + vec4 lightDir; + vec3 lightVec; + lightComputeDir(wvPosition, lightColor.w, lightData1, lightDir, lightVec); + // lightDir = normalize(lightDir); + // lightVec = normalize(lightVec); + + float spotFallOff = 1.0; + #if __VERSION__ >= 110 + // allow use of control flow + if(lightColor.w > 1.0){ + #endif + vec4 lightDirection = g_LightData[i+2]; + spotFallOff = computeSpotFalloff(lightDirection, lightVec); + #if __VERSION__ >= 110 + } + #endif + vec2 v = computeLighting(wvNormal, viewDir, lightDir.xyz, lightDir.w * spotFallOff, m_Shininess); + diffuseAccum +=v.x * diffuseColor; + specularAccum += v.y * specularColor; + } + #endif + + + #ifdef USE_REFLECTION + computeRef(modelSpacePos); + #endif +} \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib index 4d1b40436..3b8863b6c 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib @@ -1,48 +1,30 @@ -#ifndef NUM_LIGHTS - #define NUM_LIGHTS 4 -#endif +/*Common function for light calculations*/ -uniform mat4 g_ViewMatrix; -uniform vec4 g_LightPosition[NUM_LIGHTS]; -uniform vec4 g_g_LightColor[NUM_LIGHTS]; -uniform float m_Shininess; -float Lighting_Diffuse(vec3 norm, vec3 lightdir){ - return max(0.0, dot(norm, lightdir)); -} - -float Lighting_Specular(vec3 norm, vec3 viewdir, vec3 lightdir, float shiny){ - vec3 refdir = reflect(-lightdir, norm); - return pow(max(dot(refdir, viewdir), 0.0), shiny); -} - -void Lighting_Direction(vec3 worldPos, vec4 color, vec4 position, out vec4 lightDir){ - float posLight = step(0.5, color.w); +/* +* Computes light direction +* lightType should be 0.0,1.0,2.0, repectively for Directional, point and spot lights. +* Outputs the light direction and the light half vector. +*/ +void lightComputeDir(in vec3 worldPos, in float ligthType, in vec4 position, out vec4 lightDir, out vec3 lightVec){ + float posLight = step(0.5, ligthType); vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight); + lightVec = tempVec; float dist = length(tempVec); - lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0); - lightDir.xyz = tempVec / dist; + lightDir.xyz = tempVec / vec3(dist); } -void Lighting_ComputePS(vec3 tanNormal, mat3 tbnMat, - int lightCount, out vec3 outDiffuse, out vec3 outSpecular){ - // find tangent view dir & vert pos - vec3 tanViewDir = viewDir * tbnMat; - - for (int i = 0; i < lightCount; i++){ - // find light dir in tangent space, works for point & directional lights - vec4 wvLightPos = (g_ViewMatrix * vec4(g_LightPosition[i].xyz, g_LightColor[i].w)); - wvLightPos.w = g_LightPosition[i].w; - - vec4 tanLightDir; - Lighting_Direction(wvPosition, g_LightColor[i], wvLightPos, tanLightDir); - tanLightDir.xyz = tanLightDir.xyz * tbnMat; - - vec3 lightScale = g_LightColor[i].rgb * tanLightDir.w; - float specular = Lighting_Specular(tanNormal, tanViewDir, tanLightDir.xyz, m_Shininess); - float diffuse = Lighting_Diffuse(tanNormal, tanLightDir.xyz); - outSpecular += specular * lightScale * step(0.01, diffuse) * g_LightColor[i].rgb; - outDiffuse += diffuse * lightScale * g_LightColor[i].rgb; - } +/* +* Computes the spot falloff for a spotlight +*/ +float computeSpotFalloff(in vec4 lightDirection, in vec3 lightVector){ + vec3 L=normalize(lightVector); + vec3 spotdir = normalize(lightDirection.xyz); + float curAngleCos = dot(-L, spotdir); + float innerAngleCos = floor(lightDirection.w) * 0.001; + float outerAngleCos = fract(lightDirection.w); + float innerMinusOuter = innerAngleCos - outerAngleCos; + return clamp((curAngleCos - outerAngleCos) / innerMinusOuter, step(lightDirection.w, 0.001), 1.0); } + diff --git a/jme3-core/src/main/resources/Common/ShaderLib/PhongLighting.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/PhongLighting.glsllib new file mode 100644 index 000000000..8ebeb9924 --- /dev/null +++ b/jme3-core/src/main/resources/Common/ShaderLib/PhongLighting.glsllib @@ -0,0 +1,29 @@ +/*Standard Phong ligting*/ + +/* +* Computes diffuse factor +*/ +float lightComputeDiffuse(in vec3 norm, in vec3 lightdir){ + return max(0.0, dot(norm, lightdir)); +} + +/* +* Computes specular factor +*/ +float lightComputeSpecular(in vec3 norm, in vec3 viewdir, in vec3 lightdir, in float shiny){ + vec3 R = reflect(-lightdir, norm); + return pow(max(dot(R, viewdir), 0.0), shiny); +} + +/* +* Computes diffuse and specular factors and pack them in a vec2 (x=diffuse, y=specular) +*/ +vec2 computeLighting(in vec3 norm, in vec3 viewDir, in vec3 lightDir, in float attenuation, in float shininess){ + float diffuseFactor = lightComputeDiffuse(norm, lightDir); + float specularFactor = lightComputeSpecular(norm, viewDir, lightDir, shininess); + if (shininess <= 1.0) { + specularFactor = 0.0; // should be one instruction on most cards .. + } + specularFactor *= diffuseFactor; + return vec2(diffuseFactor, specularFactor) * vec2(attenuation); +} \ No newline at end of file diff --git a/jme3-examples/src/main/java/jme3test/light/TestManyLightsSingle.java b/jme3-examples/src/main/java/jme3test/light/TestManyLightsSingle.java new file mode 100644 index 000000000..acc0037b8 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/light/TestManyLightsSingle.java @@ -0,0 +1,255 @@ +/* + * 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.light; + +import com.jme3.app.BasicProfilerState; +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +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.Material; +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.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.LightNode; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.AbstractControl; +import com.jme3.scene.shape.Box; + +public class TestManyLightsSingle extends SimpleApplication { + + public static void main(String[] args) { + TestManyLightsSingle app = new TestManyLightsSingle(); + app.start(); + } + TechniqueDef.LightMode lm = TechniqueDef.LightMode.MultiPass; + int lightNum = 6 ; + + @Override + public void simpleInitApp() { + renderManager.setPreferredLightMode(lm); + renderManager.setSinglePassLightBatchSize(lightNum); + + + flyCam.setMoveSpeed(10); + + Node scene = (Node) assetManager.loadModel("Scenes/ManyLights/Main.scene"); + rootNode.attachChild(scene); + Node n = (Node) rootNode.getChild(0); + LightList lightList = n.getWorldLightList(); + Geometry g = (Geometry) n.getChild("Grid-geom-1"); + + g.getMaterial().setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f)); + + /* A colored lit cube. Needs light source! */ + Box boxMesh = new Box(1f, 1f, 1f); + Geometry boxGeo = new Geometry("Colored Box", boxMesh); + Material boxMat = g.getMaterial().clone(); + boxMat.setBoolean("UseMaterialColors", true); + boxMat.setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f)); + boxMat.setColor("Diffuse", ColorRGBA.Blue); + boxGeo.setMaterial(boxMat); + + int nb = 0; + for (Light light : lightList) { + nb++; + PointLight p = (PointLight) light; + if (nb >60) { + n.removeLight(light); + } else { + + LightNode ln = new LightNode("l", light); + n.attachChild(ln); + ln.setLocalTranslation(p.getPosition()); + int rand = FastMath.nextRandomInt(0, 3); + switch (rand) { + case 0: + light.setColor(ColorRGBA.Red); + // ln.addControl(new MoveControl(5f)); + break; + case 1: + light.setColor(ColorRGBA.Yellow); + // ln.addControl(new MoveControl(5f)); + break; + case 2: + light.setColor(ColorRGBA.Green); + //ln.addControl(new MoveControl(-5f)); + break; + case 3: + light.setColor(ColorRGBA.Orange); + //ln.addControl(new MoveControl(-5f)); + break; + } + } + Geometry b = boxGeo.clone(); + n.attachChild(b); + b.setLocalTranslation(p.getPosition().x, 2, p.getPosition().z); + + } + + +// cam.setLocation(new Vector3f(3.1893547f, 17.977385f, 30.8378f)); +// cam.setRotation(new Quaternion(0.14317635f, 0.82302624f, -0.23777823f, 0.49557027f)); + + cam.setLocation(new Vector3f(-1.8901939f, 29.34097f, 73.07533f)); + cam.setRotation(new Quaternion(0.0021000702f, 0.971012f, -0.23886925f, 0.008527749f)); + + + BasicProfilerState profiler = new BasicProfilerState(true); + profiler.setGraphScale(1000f); + + // getStateManager().attach(profiler); +// guiNode.setCullHint(CullHint.Always); + + + + + flyCam.setDragToRotate(true); + flyCam.setMoveSpeed(50); + + + inputManager.addListener(new ActionListener() { + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("toggle") && isPressed) { + if (lm == TechniqueDef.LightMode.SinglePass) { + lm = TechniqueDef.LightMode.MultiPass; + } else { + lm = TechniqueDef.LightMode.SinglePass; + } + renderManager.setPreferredLightMode(lm); + } + if (name.equals("lightsUp") && isPressed) { + lightNum++; + renderManager.setSinglePassLightBatchSize(lightNum); + helloText.setText("nb lights per batch : " + lightNum); + } + if (name.equals("lightsDown") && isPressed) { + lightNum--; + renderManager.setSinglePassLightBatchSize(lightNum); + helloText.setText("nb lights per batch : " + lightNum); + } + } + }, "toggle", "lightsUp", "lightsDown"); + + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("lightsUp", new KeyTrigger(KeyInput.KEY_UP)); + inputManager.addMapping("lightsDown", new KeyTrigger(KeyInput.KEY_DOWN)); + + + SpotLight spot = new SpotLight(); + spot.setDirection(new Vector3f(-1f, -1f, -1f).normalizeLocal()); + spot.setColor(ColorRGBA.Blue.mult(5)); + spot.setSpotOuterAngle(FastMath.DEG_TO_RAD * 20); + spot.setSpotInnerAngle(FastMath.DEG_TO_RAD * 5); + spot.setPosition(new Vector3f(10, 10, 20)); + rootNode.addLight(spot); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, 1)); + rootNode.addLight(dl); + + AmbientLight al = new AmbientLight(); + al.setColor(new ColorRGBA(0.2f, 0.2f, 0.2f, 1f)); + rootNode.addLight(al); + + + /** + * Write text on the screen (HUD) + */ + guiNode.detachAllChildren(); + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + helloText = new BitmapText(guiFont, false); + helloText.setSize(guiFont.getCharSet().getRenderedSize()); + helloText.setText("nb lights per batch : " + lightNum); + helloText.setLocalTranslation(300, helloText.getLineHeight(), 0); + guiNode.attachChild(helloText); + + + } + BitmapText helloText; + long time; + long nbFrames; + long startTime = 0; + + @Override + public void simpleUpdate(float tpf) { +// if (nbFrames == 4000) { +// startTime = System.nanoTime(); +// } +// if (nbFrames > 4000) { +// time = System.nanoTime(); +// float average = ((float) time - (float) startTime) / ((float) nbFrames - 4000f); +// helloText.setText("Average = " + average); +// } +// nbFrames++; + } + + class MoveControl extends AbstractControl { + + float direction; + Vector3f origPos = new Vector3f(); + + public MoveControl(float direction) { + this.direction = direction; + } + + @Override + public void setSpatial(Spatial spatial) { + super.setSpatial(spatial); //To change body of generated methods, choose Tools | Templates. + origPos.set(spatial.getLocalTranslation()); + } + float time = 0; + + @Override + protected void controlUpdate(float tpf) { + time += tpf; + spatial.setLocalTranslation(origPos.x + FastMath.cos(time) * direction, origPos.y, origPos.z + FastMath.sin(time) * direction); + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + } + } +} \ No newline at end of file diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java index 4909b393e..af42dd5ee 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java @@ -802,7 +802,7 @@ public class LwjglGL1Renderer implements GL1Renderer { TextureUtil.uploadTexture(img, target, i, 0, tdc); } } else {*/ - TextureUtil.uploadTexture(ctxCaps, img, target, 0, 0, false); + TextureUtil.uploadTexture(caps, img, target, 0, 0, false); //} img.clearUpdateNeeded(); @@ -853,7 +853,7 @@ public class LwjglGL1Renderer implements GL1Renderer { public void modifyTexture(Texture tex, Image pixels, int x, int y) { setTexture(0, tex); - TextureUtil.uploadSubTexture(ctxCaps, pixels, convertTextureType(tex.getType()), 0, x, y, false); + TextureUtil.uploadSubTexture(caps, pixels, convertTextureType(tex.getType()), 0, x, y, false); } private void clearTextureUnits() { diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java index fc0a1c294..6caeb4a88 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java @@ -57,7 +57,9 @@ import com.jme3.util.BufferUtils; import com.jme3.util.ListMap; import com.jme3.util.NativeObjectManager; import java.nio.*; +import java.util.ArrayList; import java.util.EnumSet; +import java.util.HashSet; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -70,7 +72,6 @@ import static org.lwjgl.opengl.ARBInstancedArrays.*; import static org.lwjgl.opengl.ARBMultisample.*; import static org.lwjgl.opengl.ARBTextureMultisample.*; import static org.lwjgl.opengl.ARBVertexArrayObject.*; -import org.lwjgl.opengl.ContextCapabilities; import static org.lwjgl.opengl.EXTFramebufferBlit.*; import static org.lwjgl.opengl.EXTFramebufferMultisample.*; import static org.lwjgl.opengl.EXTFramebufferObject.*; @@ -84,7 +85,7 @@ import static org.lwjgl.opengl.GL13.*; import static org.lwjgl.opengl.GL14.*; import static org.lwjgl.opengl.GL15.*; import static org.lwjgl.opengl.GL20.*; -import org.lwjgl.opengl.GLContext; +import org.lwjgl.opengl.GL30; //import static org.lwjgl.opengl.GL21.*; //import static org.lwjgl.opengl.GL30.*; @@ -101,10 +102,7 @@ public class LwjglRenderer implements Renderer { private final RenderContext context = new RenderContext(); private final NativeObjectManager objManager = new NativeObjectManager(); private final EnumSet caps = EnumSet.noneOf(Caps.class); - // current state - private Shader boundShader; - private int initialDrawBuf, initialReadBuf; - private int glslVer; + private int vertexTextureUnits; private int fragTextureUnits; private int vertexUniforms; @@ -120,13 +118,12 @@ public class LwjglRenderer implements Renderer { private int maxTriCount; private int maxColorTexSamples; private int maxDepthTexSamples; - private FrameBuffer lastFb = null; private FrameBuffer mainFbOverride = null; private final Statistics statistics = new Statistics(); private int vpX, vpY, vpW, vpH; private int clipX, clipY, clipW, clipH; private boolean linearizeSrgbImages; - private ContextCapabilities ctxCaps; + private HashSet extensions; public LwjglRenderer() { } @@ -153,18 +150,67 @@ public class LwjglRenderer implements Renderer { return caps; } - @SuppressWarnings("fallthrough") - public void initialize() { - ctxCaps = GLContext.getCapabilities(); - if (ctxCaps.OpenGL20) { + private static HashSet loadExtensions(String extensions) { + HashSet extensionSet = new HashSet(64); + for (String extension : extensions.split(" ")) { + extensionSet.add(extension); + } + return extensionSet; + } + + private static int extractVersion(String prefixStr, String versionStr) { + if (versionStr != null) { + int spaceIdx = versionStr.indexOf(" ", prefixStr.length()); + if (spaceIdx >= 1) { + versionStr = versionStr.substring(prefixStr.length(), spaceIdx).trim(); + } else { + versionStr = versionStr.substring(prefixStr.length()).trim(); + } + // Some device have ":" at the end of the version. + versionStr = versionStr.replaceAll("\\:", ""); + + // Pivot on first point. + int firstPoint = versionStr.indexOf("."); + + // Remove everything after second point. + int secondPoint = versionStr.indexOf(".", firstPoint + 1); + + if (secondPoint != -1) { + versionStr = versionStr.substring(0, secondPoint); + } + + String majorVerStr = versionStr.substring(0, firstPoint); + String minorVerStr = versionStr.substring(firstPoint + 1); + + if (minorVerStr.endsWith("0") && minorVerStr.length() > 1) { + minorVerStr = minorVerStr.substring(0, minorVerStr.length() - 1); + } + + int majorVer = Integer.parseInt(majorVerStr); + int minorVer = Integer.parseInt(minorVerStr); + + return majorVer * 100 + minorVer * 10; + } else { + return -1; + } + } + + private boolean hasExtension(String extensionName) { + return extensions.contains(extensionName); + } + + private void loadCapabilities() { + int oglVer = extractVersion("", glGetString(GL_VERSION)); + + if (oglVer >= 200) { caps.add(Caps.OpenGL20); - if (ctxCaps.OpenGL21) { + if (oglVer >= 210) { caps.add(Caps.OpenGL21); - if (ctxCaps.OpenGL30) { + if (oglVer >= 300) { caps.add(Caps.OpenGL30); - if (ctxCaps.OpenGL31) { + if (oglVer >= 310) { caps.add(Caps.OpenGL31); - if (ctxCaps.OpenGL32) { + if (oglVer >= 320) { caps.add(Caps.OpenGL32); } } @@ -172,49 +218,15 @@ public class LwjglRenderer implements Renderer { } } - //workaround, always assume we support GLSL100 - //some cards just don't report this correctly - caps.add(Caps.GLSL100); + int glslVer = extractVersion("", glGetString(GL_SHADING_LANGUAGE_VERSION)); - String versionStr = null; - if (ctxCaps.OpenGL20) { - versionStr = glGetString(GL_SHADING_LANGUAGE_VERSION); - } - if (versionStr == null || versionStr.equals("")) { - glslVer = -1; - throw new UnsupportedOperationException("GLSL and OpenGL2 is " - + "required for the LWJGL " - + "renderer!"); - } - - // Fix issue in TestRenderToMemory when GL_FRONT is the main - // buffer being used. - initialDrawBuf = glGetInteger(GL_DRAW_BUFFER); - initialReadBuf = glGetInteger(GL_READ_BUFFER); - - // XXX: This has to be GL_BACK for canvas on Mac - // Since initialDrawBuf is GL_FRONT for pbuffer, gotta - // change this value later on ... -// initialDrawBuf = GL_BACK; -// initialReadBuf = GL_BACK; - - int spaceIdx = versionStr.indexOf(" "); - if (spaceIdx >= 1) { - versionStr = versionStr.substring(0, spaceIdx); - } - - float version = Float.parseFloat(versionStr); - glslVer = (int) (version * 100); - switch (glslVer) { default: if (glslVer < 400) { break; } - - // so that future OpenGL revisions wont break jme3 - - // fall through intentional + // so that future OpenGL revisions wont break jme3 + // fall through intentional case 400: case 330: case 150: @@ -231,11 +243,28 @@ public class LwjglRenderer implements Renderer { caps.add(Caps.GLSL100); break; } + + // Workaround, always assume we support GLSL100. + // Some cards just don't report this correctly. + caps.add(Caps.GLSL100); + + extensions = loadExtensions(glGetString(GL_EXTENSIONS)); + } + + @SuppressWarnings("fallthrough") + public void initialize() { + loadCapabilities(); + + // Fix issue in TestRenderToMemory when GL_FRONT is the main + // buffer being used. + context.initialDrawBuf = glGetInteger(GL_DRAW_BUFFER); + context.initialReadBuf = glGetInteger(GL_READ_BUFFER); - if (!caps.contains(Caps.GLSL100)) { - logger.log(Level.WARNING, "Force-adding GLSL100 support, since OpenGL2 is supported."); - caps.add(Caps.GLSL100); - } + // XXX: This has to be GL_BACK for canvas on Mac + // Since initialDrawBuf is GL_FRONT for pbuffer, gotta + // change this value later on ... +// initialDrawBuf = GL_BACK; +// initialReadBuf = GL_BACK; glGetInteger(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, intBuf16); vertexTextureUnits = intBuf16.get(0); @@ -280,44 +309,41 @@ public class LwjglRenderer implements Renderer { maxCubeTexSize = intBuf16.get(0); logger.log(Level.FINER, "Maximum CubeMap Resolution: {0}", maxCubeTexSize); - if (ctxCaps.GL_ARB_color_buffer_float) { + // ctxCaps = GLContext.getCapabilities(); + + if (hasExtension("GL_ARB_color_buffer_float") && + hasExtension("GL_ARB_half_float_pixel")) { // XXX: Require both 16 and 32 bit float support for FloatColorBuffer. - if (ctxCaps.GL_ARB_half_float_pixel) { - caps.add(Caps.FloatColorBuffer); - } + caps.add(Caps.FloatColorBuffer); } - if (ctxCaps.GL_ARB_depth_buffer_float) { + if (hasExtension("GL_ARB_depth_buffer_float")) { caps.add(Caps.FloatDepthBuffer); } - if (ctxCaps.OpenGL30) { + if (caps.contains(Caps.OpenGL30)) { caps.add(Caps.PackedDepthStencilBuffer); } - if (ctxCaps.GL_ARB_draw_instanced && ctxCaps.GL_ARB_instanced_arrays) { + if (hasExtension("GL_ARB_draw_instanced") && + hasExtension("GL_ARB_instanced_arrays")) { caps.add(Caps.MeshInstancing); } - if (ctxCaps.GL_ARB_fragment_program) { - caps.add(Caps.ARBprogram); - } - - if (ctxCaps.GL_ARB_texture_buffer_object) { + if (hasExtension("GL_ARB_texture_buffer_object")) { caps.add(Caps.TextureBuffer); } - if (ctxCaps.GL_ARB_texture_float) { - if (ctxCaps.GL_ARB_half_float_pixel) { - caps.add(Caps.FloatTexture); - } + if (hasExtension("GL_ARB_texture_float") && + hasExtension("GL_ARB_half_float_pixel")) { + caps.add(Caps.FloatTexture); } - if (ctxCaps.GL_ARB_vertex_array_object) { + if (hasExtension("GL_ARB_vertex_array_object") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.VertexBufferArray); } - if (ctxCaps.GL_ARB_texture_non_power_of_two) { + if (hasExtension("GL_ARB_texture_non_power_of_two") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.NonPowerOfTwoTextures); } else { logger.log(Level.WARNING, "Your graphics card does not " @@ -325,30 +351,34 @@ public class LwjglRenderer implements Renderer { + "Some features might not work."); } - boolean latc = ctxCaps.GL_EXT_texture_compression_latc; - if (latc) { + if (hasExtension("GL_EXT_texture_compression_latc")) { caps.add(Caps.TextureCompressionLATC); } - if (ctxCaps.GL_EXT_packed_float || ctxCaps.OpenGL30) { + if (hasExtension("GL_EXT_packed_float") || caps.contains(Caps.OpenGL30)) { // This format is part of the OGL3 specification caps.add(Caps.PackedFloatColorBuffer); - if (ctxCaps.GL_ARB_half_float_pixel) { + + if (hasExtension("GL_ARB_half_float_pixel")) { // because textures are usually uploaded as RGB16F // need half-float pixel caps.add(Caps.PackedFloatTexture); } } - if (ctxCaps.GL_EXT_texture_array || ctxCaps.OpenGL30) { + if (hasExtension("GL_EXT_texture_array") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.TextureArray); } - if (ctxCaps.GL_EXT_texture_shared_exponent || ctxCaps.OpenGL30) { + if (hasExtension("GL_EXT_texture_shared_exponent") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.SharedExponentTexture); } + + if (hasExtension("GL_EXT_texture_filter_anisotropic")) { + caps.add(Caps.TextureFilterAnisotropic); + } - if (ctxCaps.GL_EXT_framebuffer_object) { + if (hasExtension("GL_EXT_framebuffer_object")) { caps.add(Caps.FrameBuffer); glGetInteger(GL_MAX_RENDERBUFFER_SIZE_EXT, intBuf16); @@ -359,7 +389,7 @@ public class LwjglRenderer implements Renderer { maxFBOAttachs = intBuf16.get(0); logger.log(Level.FINER, "FBO Max renderbuffers: {0}", maxFBOAttachs); - if (ctxCaps.GL_EXT_framebuffer_multisample) { + if (hasExtension("GL_EXT_framebuffer_multisample")) { caps.add(Caps.FrameBufferMultisample); glGetInteger(GL_MAX_SAMPLES_EXT, intBuf16); @@ -367,7 +397,7 @@ public class LwjglRenderer implements Renderer { logger.log(Level.FINER, "FBO Max Samples: {0}", maxFBOSamples); } - if (ctxCaps.GL_ARB_texture_multisample) { + if (hasExtension("GL_ARB_texture_multisample")) { caps.add(Caps.TextureMultisample); glGetInteger(GL_MAX_COLOR_TEXTURE_SAMPLES, intBuf16); @@ -387,7 +417,7 @@ public class LwjglRenderer implements Renderer { } } - if (ctxCaps.GL_ARB_multisample) { + if (hasExtension("GL_ARB_multisample")) { glGetInteger(GL_SAMPLE_BUFFERS_ARB, intBuf16); boolean available = intBuf16.get(0) != 0; glGetInteger(GL_SAMPLES_ARB, intBuf16); @@ -401,7 +431,8 @@ public class LwjglRenderer implements Renderer { } // Supports sRGB pipeline. - if ( (ctxCaps.GL_ARB_framebuffer_sRGB && ctxCaps.GL_EXT_texture_sRGB ) || ctxCaps.OpenGL30 ) { + if ( (hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB")) + || caps.contains(Caps.OpenGL30) ) { caps.add(Caps.Srgb); } @@ -410,11 +441,8 @@ public class LwjglRenderer implements Renderer { public void invalidateState() { context.reset(); - boundShader = null; - lastFb = null; - - initialDrawBuf = glGetInteger(GL_DRAW_BUFFER); - initialReadBuf = glGetInteger(GL_READ_BUFFER); + context.initialDrawBuf = glGetInteger(GL_DRAW_BUFFER); + context.initialReadBuf = glGetInteger(GL_READ_BUFFER); } public void resetGLObjects() { @@ -479,7 +507,7 @@ public class LwjglRenderer implements Renderer { } public void setAlphaToCoverage(boolean value) { - if (ctxCaps.GL_ARB_multisample) { + if (caps.contains(Caps.Multisample)) { if (value) { glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); } else { @@ -822,7 +850,7 @@ public class LwjglRenderer implements Renderer { if (context.boundShaderProgram != shaderId) { glUseProgram(shaderId); statistics.onShaderUse(shader, true); - boundShader = shader; + context.boundShader = shader; context.boundShaderProgram = shaderId; } else { statistics.onShaderUse(shader, false); @@ -1081,12 +1109,12 @@ public class LwjglRenderer implements Renderer { glAttachShader(id, source.getId()); } - if (ctxCaps.GL_EXT_gpu_shader4) { + if (caps.contains(Caps.OpenGL30)) { // Check if GLSL version is 1.5 for shader - glBindFragDataLocationEXT(id, 0, "outFragColor"); + GL30.glBindFragDataLocation(id, 0, "outFragColor"); // For MRT for (int i = 0; i < maxMRTFBOAttachs; i++) { - glBindFragDataLocationEXT(id, i, "outFragData[" + i + "]"); + GL30.glBindFragDataLocation(id, i, "outFragData[" + i + "]"); } } @@ -1191,7 +1219,7 @@ public class LwjglRenderer implements Renderer { } public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) { - if (ctxCaps.GL_EXT_framebuffer_blit) { + if (caps.contains(Caps.FrameBufferBlit)) { int srcX0 = 0; int srcY0 = 0; int srcX1; @@ -1292,11 +1320,11 @@ public class LwjglRenderer implements Renderer { int attachment = convertAttachmentSlot(rb.getSlot()); - int type = glGetFramebufferAttachmentParameterEXT(GL_DRAW_FRAMEBUFFER_EXT, + int type = glGetFramebufferAttachmentParameteriEXT(GL_DRAW_FRAMEBUFFER_EXT, attachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT); - int rbName = glGetFramebufferAttachmentParameterEXT(GL_DRAW_FRAMEBUFFER_EXT, + int rbName = glGetFramebufferAttachmentParameteriEXT(GL_DRAW_FRAMEBUFFER_EXT, attachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT); @@ -1397,9 +1425,9 @@ public class LwjglRenderer implements Renderer { + ":" + fb.getHeight() + " is not supported."); } - TextureUtil.GLImageFormat glFmt = TextureUtil.getImageFormatWithError(ctxCaps, rb.getFormat(), fb.isSrgb()); + TextureUtil.GLImageFormat glFmt = TextureUtil.getImageFormatWithError(caps, rb.getFormat(), fb.isSrgb()); - if (fb.getSamples() > 1 && ctxCaps.GL_EXT_framebuffer_multisample) { + if (fb.getSamples() > 1 && caps.contains(Caps.FrameBufferMultisample)) { int samples = fb.getSamples(); if (maxFBOSamples < samples) { samples = maxFBOSamples; @@ -1503,7 +1531,7 @@ public class LwjglRenderer implements Renderer { if (fb.getSamples() <= 1) { throw new IllegalArgumentException("Framebuffer must be multisampled"); } - if (!ctxCaps.GL_ARB_texture_multisample) { + if (!caps.contains(Caps.TextureMultisample)) { throw new RendererException("Multisampled textures are not supported"); } @@ -1525,7 +1553,7 @@ public class LwjglRenderer implements Renderer { } public void setFrameBuffer(FrameBuffer fb) { - if (!ctxCaps.GL_EXT_framebuffer_object) { + if (!caps.contains(Caps.FrameBuffer)) { throw new RendererException("Framebuffer objects are not supported" + " by the video hardware"); } @@ -1534,16 +1562,16 @@ public class LwjglRenderer implements Renderer { fb = mainFbOverride; } - if (lastFb == fb) { + if (context.boundFB == fb) { if (fb == null || !fb.isUpdateNeeded()) { return; } } // generate mipmaps for last FB if needed - if (lastFb != null) { - for (int i = 0; i < lastFb.getNumColorBuffers(); i++) { - RenderBuffer rb = lastFb.getColorBuffer(i); + if (context.boundFB != null) { + for (int i = 0; i < context.boundFB.getNumColorBuffers(); i++) { + RenderBuffer rb = context.boundFB.getColorBuffer(i); Texture tex = rb.getTexture(); if (tex != null && tex.getMinFilter().usesMipMapLevels()) { @@ -1567,15 +1595,15 @@ public class LwjglRenderer implements Renderer { } // select back buffer if (context.boundDrawBuf != -1) { - glDrawBuffer(initialDrawBuf); + glDrawBuffer(context.initialDrawBuf); context.boundDrawBuf = -1; } if (context.boundReadBuf != -1) { - glReadBuffer(initialReadBuf); + glReadBuffer(context.initialReadBuf); context.boundReadBuf = -1; } - lastFb = null; + context.boundFB = null; } else { if (fb.getNumColorBuffers() == 0 && fb.getDepthBuffer() == null) { throw new IllegalArgumentException("The framebuffer: " + fb @@ -1644,7 +1672,7 @@ public class LwjglRenderer implements Renderer { assert fb.getId() >= 0; assert context.boundFBO == fb.getId(); - lastFb = fb; + context.boundFB = fb; try { checkFrameBufferError(); @@ -1707,7 +1735,7 @@ public class LwjglRenderer implements Renderer { |* Textures *| \*********************************************************************/ private int convertTextureType(Texture.Type type, int samples, int face) { - if (samples > 1 && !ctxCaps.GL_ARB_texture_multisample) { + if (samples > 1 && !caps.contains(Caps.TextureMultisample)) { throw new RendererException("Multisample textures are not supported" + " by the video hardware."); } @@ -1751,22 +1779,37 @@ public class LwjglRenderer implements Renderer { } } - private int convertMinFilter(Texture.MinFilter filter) { - switch (filter) { - case Trilinear: - return GL_LINEAR_MIPMAP_LINEAR; - case BilinearNearestMipMap: - return GL_LINEAR_MIPMAP_NEAREST; - case NearestLinearMipMap: - return GL_NEAREST_MIPMAP_LINEAR; - case NearestNearestMipMap: - return GL_NEAREST_MIPMAP_NEAREST; - case BilinearNoMipMaps: - return GL_LINEAR; - case NearestNoMipMaps: - return GL_NEAREST; - default: - throw new UnsupportedOperationException("Unknown min filter: " + filter); + private int convertMinFilter(Texture.MinFilter filter, boolean haveMips) { + if (haveMips){ + switch (filter) { + case Trilinear: + return GL_LINEAR_MIPMAP_LINEAR; + case BilinearNearestMipMap: + return GL_LINEAR_MIPMAP_NEAREST; + case NearestLinearMipMap: + return GL_NEAREST_MIPMAP_LINEAR; + case NearestNearestMipMap: + return GL_NEAREST_MIPMAP_NEAREST; + case BilinearNoMipMaps: + return GL_LINEAR; + case NearestNoMipMaps: + return GL_NEAREST; + default: + throw new UnsupportedOperationException("Unknown min filter: " + filter); + } + } else { + switch (filter) { + case Trilinear: + case BilinearNearestMipMap: + case BilinearNoMipMaps: + return GL_LINEAR; + case NearestLinearMipMap: + case NearestNearestMipMap: + case NearestNoMipMaps: + return GL_NEAREST; + default: + throw new UnsupportedOperationException("Unknown min filter: " + filter); + } } } @@ -1792,14 +1835,20 @@ public class LwjglRenderer implements Renderer { Image image = tex.getImage(); int target = convertTextureType(tex.getType(), image != null ? image.getMultiSamples() : 1, -1); + boolean haveMips = true; + + if (image != null) { + haveMips = image.isGeneratedMipmapsRequired() || image.hasMipmaps(); + } + // filter things - int minFilter = convertMinFilter(tex.getMinFilter()); + int minFilter = convertMinFilter(tex.getMinFilter(), haveMips); int magFilter = convertMagFilter(tex.getMagFilter()); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilter); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilter); if (tex.getAnisotropicFilter() > 1) { - if (ctxCaps.GL_EXT_texture_filter_anisotropic) { + if (caps.contains(Caps.TextureFilterAnisotropic)) { glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, tex.getAnisotropicFilter()); @@ -1881,7 +1930,7 @@ public class LwjglRenderer implements Renderer { // Image does not have mipmaps, but they are required. // Generate from base level. - if (!ctxCaps.OpenGL30) { + if (!caps.contains(Caps.OpenGL30)) { glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE); img.setMipmapsGenerated(true); } else { @@ -1908,7 +1957,7 @@ public class LwjglRenderer implements Renderer { } // Yes, some OpenGL2 cards (GeForce 5) still dont support NPOT. - if (!ctxCaps.GL_ARB_texture_non_power_of_two && img.isNPOT()) { + if (!caps.contains(Caps.NonPowerOfTwoTextures) && img.isNPOT()) { if (img.getData(0) == null) { throw new RendererException("non-power-of-2 framebuffer textures are not supported by the video hardware"); } else { @@ -1917,7 +1966,7 @@ public class LwjglRenderer implements Renderer { } // Check if graphics card doesn't support multisample textures - if (!ctxCaps.GL_ARB_texture_multisample) { + if (!caps.contains(Caps.TextureMultisample)) { if (img.getMultiSamples() > 1) { throw new RendererException("Multisample textures not supported by graphics hardware"); } @@ -1928,6 +1977,9 @@ public class LwjglRenderer implements Renderer { if (img.getWidth() > maxCubeTexSize || img.getHeight() > maxCubeTexSize) { throw new RendererException("Cannot upload cubemap " + img + ". The maximum supported cubemap resolution is " + maxCubeTexSize); } + if (img.getWidth() != img.getHeight()) { + throw new RendererException("Cubemaps must have square dimensions"); + } } else { if (img.getWidth() > maxTexSize || img.getHeight() > maxTexSize) { throw new RendererException("Cannot upload texture " + img + ". The maximum supported texture resolution is " + maxTexSize); @@ -1942,7 +1994,7 @@ public class LwjglRenderer implements Renderer { return; } for (int i = 0; i < 6; i++) { - TextureUtil.uploadTexture(ctxCaps, img, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, linearizeSrgbImages); + TextureUtil.uploadTexture(caps, img, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, linearizeSrgbImages); } } else if (target == GL_TEXTURE_2D_ARRAY_EXT) { if (!caps.contains(Caps.TextureArray)) { @@ -1952,22 +2004,22 @@ public class LwjglRenderer implements Renderer { List data = img.getData(); // -1 index specifies prepare data for 2D Array - TextureUtil.uploadTexture(ctxCaps, img, target, -1, 0, linearizeSrgbImages); + TextureUtil.uploadTexture(caps, img, target, -1, 0, linearizeSrgbImages); for (int i = 0; i < data.size(); i++) { // upload each slice of 2D array in turn // this time with the appropriate index - TextureUtil.uploadTexture(ctxCaps, img, target, i, 0, linearizeSrgbImages); + TextureUtil.uploadTexture(caps, img, target, i, 0, linearizeSrgbImages); } } else { - TextureUtil.uploadTexture(ctxCaps, img, target, 0, 0, linearizeSrgbImages); + TextureUtil.uploadTexture(caps, img, target, 0, 0, linearizeSrgbImages); } if (img.getMultiSamples() != imageSamples) { img.setMultiSamples(imageSamples); } - if (ctxCaps.OpenGL30) { + if (caps.contains(Caps.OpenGL30)) { if (!img.hasMipmaps() && img.isGeneratedMipmapsRequired() && img.getData() != null) { // XXX: Required for ATI glEnable(target); @@ -2018,7 +2070,7 @@ public class LwjglRenderer implements Renderer { public void modifyTexture(Texture tex, Image pixels, int x, int y) { setTexture(0, tex); - TextureUtil.uploadSubTexture(ctxCaps, pixels, convertTextureType(tex.getType(), pixels.getMultiSamples(), -1), 0, x, y, linearizeSrgbImages); + TextureUtil.uploadSubTexture(caps, pixels, convertTextureType(tex.getType(), pixels.getMultiSamples(), -1), 0, x, y, linearizeSrgbImages); } public void clearTextureUnits() { @@ -2213,8 +2265,9 @@ public class LwjglRenderer implements Renderer { } int programId = context.boundShaderProgram; + if (programId > 0) { - Attribute attrib = boundShader.getAttribute(vb.getBufferType()); + Attribute attrib = context.boundShader.getAttribute(vb.getBufferType()); int loc = attrib.getLocation(); if (loc == -1) { return; // not defined @@ -2236,8 +2289,7 @@ public class LwjglRenderer implements Renderer { } if (vb.isInstanced()) { - if (!ctxCaps.GL_ARB_instanced_arrays - || !ctxCaps.GL_ARB_draw_instanced) { + if (!caps.contains(Caps.MeshInstancing)) { throw new RendererException("Instancing is required, " + "but not supported by the " + "graphics hardware"); diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java index bab26f6ad..2eca2a06b 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java @@ -32,11 +32,13 @@ package com.jme3.renderer.lwjgl; +import com.jme3.renderer.Caps; import com.jme3.renderer.RendererException; import com.jme3.texture.Image; import com.jme3.texture.Image.Format; import com.jme3.texture.image.ColorSpace; import java.nio.ByteBuffer; +import java.util.EnumSet; import java.util.logging.Level; import java.util.logging.Logger; import static org.lwjgl.opengl.ARBDepthBufferFloat.*; @@ -55,7 +57,6 @@ import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.opengl.GL12.*; import static org.lwjgl.opengl.GL13.*; import static org.lwjgl.opengl.GL14.*; -import static org.lwjgl.opengl.GL20.*; class TextureUtil { @@ -140,7 +141,7 @@ class TextureUtil { // LTC/LATC/3Dc formats setFormat(Format.LTC, GL_COMPRESSED_LUMINANCE_LATC1_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE, true); - setFormat(Format.LATC, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, true); + setFormat(Format.LATC, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, true); } //sRGB formats @@ -157,18 +158,18 @@ class TextureUtil { private static final GLImageFormat sRGB_DXT3 = new GLImageFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); private static final GLImageFormat sRGB_DXT5 = new GLImageFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); - public static GLImageFormat getImageFormat(ContextCapabilities caps, Format fmt, boolean isSrgb){ + public static GLImageFormat getImageFormat(EnumSet caps, Format fmt, boolean isSrgb){ switch (fmt){ case DXT1: case DXT1A: case DXT3: case DXT5: - if (!caps.GL_EXT_texture_compression_s3tc) { + if (!caps.contains(Caps.TextureCompressionS3TC)) { return null; } break; case Depth24Stencil8: - if (!caps.OpenGL30 && !caps.GL_EXT_packed_depth_stencil){ + if (!caps.contains(Caps.PackedDepthStencilBuffer)){ return null; } break; @@ -179,30 +180,30 @@ class TextureUtil { case RGB32F: case RGBA16F: case RGBA32F: - if (!caps.OpenGL30 && !caps.GL_ARB_texture_float){ + if (!caps.contains(Caps.FloatTexture)){ return null; } break; case Depth32F: - if (!caps.OpenGL30 && !caps.GL_NV_depth_buffer_float){ + if (!caps.contains(Caps.FloatDepthBuffer)){ return null; } break; case LATC: case LTC: - if (!caps.GL_EXT_texture_compression_latc){ + if (!caps.contains(Caps.TextureCompressionLATC)){ return null; } break; case RGB9E5: case RGB16F_to_RGB9E5: - if (!caps.OpenGL30 && !caps.GL_EXT_texture_shared_exponent){ + if (!caps.contains(Caps.SharedExponentTexture)){ return null; } break; case RGB111110F: case RGB16F_to_RGB111110F: - if (!caps.OpenGL30 && !caps.GL_EXT_packed_float){ + if (!caps.contains(Caps.PackedFloatTexture)){ return null; } break; @@ -214,7 +215,7 @@ class TextureUtil { } } - public static GLImageFormat getImageFormatWithError(ContextCapabilities caps, Format fmt, boolean isSrgb) { + public static GLImageFormat getImageFormatWithError(EnumSet caps, Format fmt, boolean isSrgb) { GLImageFormat glFmt = getImageFormat(caps, fmt, isSrgb); if (glFmt == null) { throw new RendererException("Image format '" + fmt + "' is unsupported by the video hardware."); @@ -254,7 +255,7 @@ class TextureUtil { } } - public static void uploadTexture(ContextCapabilities caps, + public static void uploadTexture(EnumSet caps, Image image, int target, int index, @@ -412,7 +413,7 @@ class TextureUtil { * @param y the y position where to put the image in the texture */ public static void uploadSubTexture( - ContextCapabilities caps, + EnumSet caps, Image image, int target, int index, diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/SPTerrainLighting.frag b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/SPTerrainLighting.frag new file mode 100644 index 000000000..9556f256d --- /dev/null +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/SPTerrainLighting.frag @@ -0,0 +1,615 @@ +#import "Common/ShaderLib/PhongLighting.glsllib" +#import "Common/ShaderLib/Lighting.glsllib" + +uniform float m_Shininess; + +varying vec4 AmbientSum; +varying vec4 DiffuseSum; +varying vec4 SpecularSum; + +uniform mat4 g_ViewMatrix; +uniform vec4 g_LightData[NB_LIGHTS]; +varying vec3 vTangent; +varying vec3 vBinormal; +varying vec3 vPos; +varying vec3 vNormal; +varying vec2 texCoord; + + +#ifdef DIFFUSEMAP + uniform sampler2D m_DiffuseMap; +#endif +#ifdef DIFFUSEMAP_1 + uniform sampler2D m_DiffuseMap_1; +#endif +#ifdef DIFFUSEMAP_2 + uniform sampler2D m_DiffuseMap_2; +#endif +#ifdef DIFFUSEMAP_3 + uniform sampler2D m_DiffuseMap_3; +#endif +#ifdef DIFFUSEMAP_4 + uniform sampler2D m_DiffuseMap_4; +#endif +#ifdef DIFFUSEMAP_5 + uniform sampler2D m_DiffuseMap_5; +#endif +#ifdef DIFFUSEMAP_6 + uniform sampler2D m_DiffuseMap_6; +#endif +#ifdef DIFFUSEMAP_7 + uniform sampler2D m_DiffuseMap_7; +#endif +#ifdef DIFFUSEMAP_8 + uniform sampler2D m_DiffuseMap_8; +#endif +#ifdef DIFFUSEMAP_9 + uniform sampler2D m_DiffuseMap_9; +#endif +#ifdef DIFFUSEMAP_10 + uniform sampler2D m_DiffuseMap_10; +#endif +#ifdef DIFFUSEMAP_11 + uniform sampler2D m_DiffuseMap_11; +#endif + + +#ifdef DIFFUSEMAP_0_SCALE + uniform float m_DiffuseMap_0_scale; +#endif +#ifdef DIFFUSEMAP_1_SCALE + uniform float m_DiffuseMap_1_scale; +#endif +#ifdef DIFFUSEMAP_2_SCALE + uniform float m_DiffuseMap_2_scale; +#endif +#ifdef DIFFUSEMAP_3_SCALE + uniform float m_DiffuseMap_3_scale; +#endif +#ifdef DIFFUSEMAP_4_SCALE + uniform float m_DiffuseMap_4_scale; +#endif +#ifdef DIFFUSEMAP_5_SCALE + uniform float m_DiffuseMap_5_scale; +#endif +#ifdef DIFFUSEMAP_6_SCALE + uniform float m_DiffuseMap_6_scale; +#endif +#ifdef DIFFUSEMAP_7_SCALE + uniform float m_DiffuseMap_7_scale; +#endif +#ifdef DIFFUSEMAP_8_SCALE + uniform float m_DiffuseMap_8_scale; +#endif +#ifdef DIFFUSEMAP_9_SCALE + uniform float m_DiffuseMap_9_scale; +#endif +#ifdef DIFFUSEMAP_10_SCALE + uniform float m_DiffuseMap_10_scale; +#endif +#ifdef DIFFUSEMAP_11_SCALE + uniform float m_DiffuseMap_11_scale; +#endif + + +#ifdef ALPHAMAP + uniform sampler2D m_AlphaMap; +#endif +#ifdef ALPHAMAP_1 + uniform sampler2D m_AlphaMap_1; +#endif +#ifdef ALPHAMAP_2 + uniform sampler2D m_AlphaMap_2; +#endif + +#ifdef NORMALMAP + uniform sampler2D m_NormalMap; +#endif +#ifdef NORMALMAP_1 + uniform sampler2D m_NormalMap_1; +#endif +#ifdef NORMALMAP_2 + uniform sampler2D m_NormalMap_2; +#endif +#ifdef NORMALMAP_3 + uniform sampler2D m_NormalMap_3; +#endif +#ifdef NORMALMAP_4 + uniform sampler2D m_NormalMap_4; +#endif +#ifdef NORMALMAP_5 + uniform sampler2D m_NormalMap_5; +#endif +#ifdef NORMALMAP_6 + uniform sampler2D m_NormalMap_6; +#endif +#ifdef NORMALMAP_7 + uniform sampler2D m_NormalMap_7; +#endif +#ifdef NORMALMAP_8 + uniform sampler2D m_NormalMap_8; +#endif +#ifdef NORMALMAP_9 + uniform sampler2D m_NormalMap_9; +#endif +#ifdef NORMALMAP_10 + uniform sampler2D m_NormalMap_10; +#endif +#ifdef NORMALMAP_11 + uniform sampler2D m_NormalMap_11; +#endif + + +#ifdef TRI_PLANAR_MAPPING + varying vec4 wVertex; + varying vec3 wNormal; +#endif + + +#ifdef ALPHAMAP + + vec4 calculateDiffuseBlend(in vec2 texCoord) { + vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy ); + + #ifdef ALPHAMAP_1 + vec4 alphaBlend1 = texture2D( m_AlphaMap_1, texCoord.xy ); + #endif + #ifdef ALPHAMAP_2 + vec4 alphaBlend2 = texture2D( m_AlphaMap_2, texCoord.xy ); + #endif + + vec4 diffuseColor = texture2D(m_DiffuseMap, texCoord * m_DiffuseMap_0_scale); + diffuseColor *= alphaBlend.r; + #ifdef DIFFUSEMAP_1 + vec4 diffuseColor1 = texture2D(m_DiffuseMap_1, texCoord * m_DiffuseMap_1_scale); + diffuseColor = mix( diffuseColor, diffuseColor1, alphaBlend.g ); + #endif + #ifdef DIFFUSEMAP_2 + vec4 diffuseColor2 = texture2D(m_DiffuseMap_2, texCoord * m_DiffuseMap_2_scale); + diffuseColor = mix( diffuseColor, diffuseColor2, alphaBlend.b ); + #endif + #ifdef DIFFUSEMAP_3 + vec4 diffuseColor3 = texture2D(m_DiffuseMap_3, texCoord * m_DiffuseMap_3_scale); + diffuseColor = mix( diffuseColor, diffuseColor3, alphaBlend.a ); + #endif + + #ifdef ALPHAMAP_1 + #ifdef DIFFUSEMAP_4 + vec4 diffuseColor4 = texture2D(m_DiffuseMap_4, texCoord * m_DiffuseMap_4_scale); + diffuseColor = mix( diffuseColor, diffuseColor4, alphaBlend1.r ); + #endif + #ifdef DIFFUSEMAP_5 + vec4 diffuseColor5 = texture2D(m_DiffuseMap_5, texCoord * m_DiffuseMap_5_scale); + diffuseColor = mix( diffuseColor, diffuseColor5, alphaBlend1.g ); + #endif + #ifdef DIFFUSEMAP_6 + vec4 diffuseColor6 = texture2D(m_DiffuseMap_6, texCoord * m_DiffuseMap_6_scale); + diffuseColor = mix( diffuseColor, diffuseColor6, alphaBlend1.b ); + #endif + #ifdef DIFFUSEMAP_7 + vec4 diffuseColor7 = texture2D(m_DiffuseMap_7, texCoord * m_DiffuseMap_7_scale); + diffuseColor = mix( diffuseColor, diffuseColor7, alphaBlend1.a ); + #endif + #endif + + #ifdef ALPHAMAP_2 + #ifdef DIFFUSEMAP_8 + vec4 diffuseColor8 = texture2D(m_DiffuseMap_8, texCoord * m_DiffuseMap_8_scale); + diffuseColor = mix( diffuseColor, diffuseColor8, alphaBlend2.r ); + #endif + #ifdef DIFFUSEMAP_9 + vec4 diffuseColor9 = texture2D(m_DiffuseMap_9, texCoord * m_DiffuseMap_9_scale); + diffuseColor = mix( diffuseColor, diffuseColor9, alphaBlend2.g ); + #endif + #ifdef DIFFUSEMAP_10 + vec4 diffuseColor10 = texture2D(m_DiffuseMap_10, texCoord * m_DiffuseMap_10_scale); + diffuseColor = mix( diffuseColor, diffuseColor10, alphaBlend2.b ); + #endif + #ifdef DIFFUSEMAP_11 + vec4 diffuseColor11 = texture2D(m_DiffuseMap_11, texCoord * m_DiffuseMap_11_scale); + diffuseColor = mix( diffuseColor, diffuseColor11, alphaBlend2.a ); + #endif + #endif + + return diffuseColor; + } + + vec3 calculateNormal(in vec2 texCoord) { + vec3 normal = vec3(0,0,1); + vec3 n = vec3(0,0,0); + + vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy ); + + #ifdef ALPHAMAP_1 + vec4 alphaBlend1 = texture2D( m_AlphaMap_1, texCoord.xy ); + #endif + #ifdef ALPHAMAP_2 + vec4 alphaBlend2 = texture2D( m_AlphaMap_2, texCoord.xy ); + #endif + + #ifdef NORMALMAP + n = texture2D(m_NormalMap, texCoord * m_DiffuseMap_0_scale).xyz; + normal += n * alphaBlend.r; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.r; + #endif + + #ifdef NORMALMAP_1 + n = texture2D(m_NormalMap_1, texCoord * m_DiffuseMap_1_scale).xyz; + normal += n * alphaBlend.g; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.g; + #endif + + #ifdef NORMALMAP_2 + n = texture2D(m_NormalMap_2, texCoord * m_DiffuseMap_2_scale).xyz; + normal += n * alphaBlend.b; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.b; + #endif + + #ifdef NORMALMAP_3 + n = texture2D(m_NormalMap_3, texCoord * m_DiffuseMap_3_scale).xyz; + normal += n * alphaBlend.a; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.a; + #endif + + #ifdef ALPHAMAP_1 + #ifdef NORMALMAP_4 + n = texture2D(m_NormalMap_4, texCoord * m_DiffuseMap_4_scale).xyz; + normal += n * alphaBlend1.r; + #endif + + #ifdef NORMALMAP_5 + n = texture2D(m_NormalMap_5, texCoord * m_DiffuseMap_5_scale).xyz; + normal += n * alphaBlend1.g; + #endif + + #ifdef NORMALMAP_6 + n = texture2D(m_NormalMap_6, texCoord * m_DiffuseMap_6_scale).xyz; + normal += n * alphaBlend1.b; + #endif + + #ifdef NORMALMAP_7 + n = texture2D(m_NormalMap_7, texCoord * m_DiffuseMap_7_scale).xyz; + normal += n * alphaBlend1.a; + #endif + #endif + + #ifdef ALPHAMAP_2 + #ifdef NORMALMAP_8 + n = texture2D(m_NormalMap_8, texCoord * m_DiffuseMap_8_scale).xyz; + normal += n * alphaBlend2.r; + #endif + + #ifdef NORMALMAP_9 + n = texture2D(m_NormalMap_9, texCoord * m_DiffuseMap_9_scale); + normal += n * alphaBlend2.g; + #endif + + #ifdef NORMALMAP_10 + n = texture2D(m_NormalMap_10, texCoord * m_DiffuseMap_10_scale); + normal += n * alphaBlend2.b; + #endif + + #ifdef NORMALMAP_11 + n = texture2D(m_NormalMap_11, texCoord * m_DiffuseMap_11_scale); + normal += n * alphaBlend2.a; + #endif + #endif + + normal = (normal.xyz * vec3(2.0) - vec3(1.0)); + return normalize(normal); + } + + #ifdef TRI_PLANAR_MAPPING + + vec4 getTriPlanarBlend(in vec4 coords, in vec3 blending, in sampler2D map, in float scale) { + vec4 col1 = texture2D( map, coords.yz * scale); + vec4 col2 = texture2D( map, coords.xz * scale); + vec4 col3 = texture2D( map, coords.xy * scale); + // blend the results of the 3 planar projections. + vec4 tex = col1 * blending.x + col2 * blending.y + col3 * blending.z; + return tex; + } + + vec4 calculateTriPlanarDiffuseBlend(in vec3 wNorm, in vec4 wVert, in vec2 texCoord) { + // tri-planar texture bending factor for this fragment's normal + vec3 blending = abs( wNorm ); + blending = (blending -0.2) * 0.7; + blending = normalize(max(blending, 0.00001)); // Force weights to sum to 1.0 (very important!) + float b = (blending.x + blending.y + blending.z); + blending /= vec3(b, b, b); + + // texture coords + vec4 coords = wVert; + + // blend the results of the 3 planar projections. + vec4 tex0 = getTriPlanarBlend(coords, blending, m_DiffuseMap, m_DiffuseMap_0_scale); + + #ifdef DIFFUSEMAP_1 + // blend the results of the 3 planar projections. + vec4 tex1 = getTriPlanarBlend(coords, blending, m_DiffuseMap_1, m_DiffuseMap_1_scale); + #endif + #ifdef DIFFUSEMAP_2 + // blend the results of the 3 planar projections. + vec4 tex2 = getTriPlanarBlend(coords, blending, m_DiffuseMap_2, m_DiffuseMap_2_scale); + #endif + #ifdef DIFFUSEMAP_3 + // blend the results of the 3 planar projections. + vec4 tex3 = getTriPlanarBlend(coords, blending, m_DiffuseMap_3, m_DiffuseMap_3_scale); + #endif + #ifdef DIFFUSEMAP_4 + // blend the results of the 3 planar projections. + vec4 tex4 = getTriPlanarBlend(coords, blending, m_DiffuseMap_4, m_DiffuseMap_4_scale); + #endif + #ifdef DIFFUSEMAP_5 + // blend the results of the 3 planar projections. + vec4 tex5 = getTriPlanarBlend(coords, blending, m_DiffuseMap_5, m_DiffuseMap_5_scale); + #endif + #ifdef DIFFUSEMAP_6 + // blend the results of the 3 planar projections. + vec4 tex6 = getTriPlanarBlend(coords, blending, m_DiffuseMap_6, m_DiffuseMap_6_scale); + #endif + #ifdef DIFFUSEMAP_7 + // blend the results of the 3 planar projections. + vec4 tex7 = getTriPlanarBlend(coords, blending, m_DiffuseMap_7, m_DiffuseMap_7_scale); + #endif + #ifdef DIFFUSEMAP_8 + // blend the results of the 3 planar projections. + vec4 tex8 = getTriPlanarBlend(coords, blending, m_DiffuseMap_8, m_DiffuseMap_8_scale); + #endif + #ifdef DIFFUSEMAP_9 + // blend the results of the 3 planar projections. + vec4 tex9 = getTriPlanarBlend(coords, blending, m_DiffuseMap_9, m_DiffuseMap_9_scale); + #endif + #ifdef DIFFUSEMAP_10 + // blend the results of the 3 planar projections. + vec4 tex10 = getTriPlanarBlend(coords, blending, m_DiffuseMap_10, m_DiffuseMap_10_scale); + #endif + #ifdef DIFFUSEMAP_11 + // blend the results of the 3 planar projections. + vec4 tex11 = getTriPlanarBlend(coords, blending, m_DiffuseMap_11, m_DiffuseMap_11_scale); + #endif + + vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy ); + + #ifdef ALPHAMAP_1 + vec4 alphaBlend1 = texture2D( m_AlphaMap_1, texCoord.xy ); + #endif + #ifdef ALPHAMAP_2 + vec4 alphaBlend2 = texture2D( m_AlphaMap_2, texCoord.xy ); + #endif + + vec4 diffuseColor = tex0 * alphaBlend.r; + #ifdef DIFFUSEMAP_1 + diffuseColor = mix( diffuseColor, tex1, alphaBlend.g ); + #endif + #ifdef DIFFUSEMAP_2 + diffuseColor = mix( diffuseColor, tex2, alphaBlend.b ); + #endif + #ifdef DIFFUSEMAP_3 + diffuseColor = mix( diffuseColor, tex3, alphaBlend.a ); + #endif + #ifdef ALPHAMAP_1 + #ifdef DIFFUSEMAP_4 + diffuseColor = mix( diffuseColor, tex4, alphaBlend1.r ); + #endif + #ifdef DIFFUSEMAP_5 + diffuseColor = mix( diffuseColor, tex5, alphaBlend1.g ); + #endif + #ifdef DIFFUSEMAP_6 + diffuseColor = mix( diffuseColor, tex6, alphaBlend1.b ); + #endif + #ifdef DIFFUSEMAP_7 + diffuseColor = mix( diffuseColor, tex7, alphaBlend1.a ); + #endif + #endif + #ifdef ALPHAMAP_2 + #ifdef DIFFUSEMAP_8 + diffuseColor = mix( diffuseColor, tex8, alphaBlend2.r ); + #endif + #ifdef DIFFUSEMAP_9 + diffuseColor = mix( diffuseColor, tex9, alphaBlend2.g ); + #endif + #ifdef DIFFUSEMAP_10 + diffuseColor = mix( diffuseColor, tex10, alphaBlend2.b ); + #endif + #ifdef DIFFUSEMAP_11 + diffuseColor = mix( diffuseColor, tex11, alphaBlend2.a ); + #endif + #endif + + return diffuseColor; + } + + vec3 calculateNormalTriPlanar(in vec3 wNorm, in vec4 wVert,in vec2 texCoord) { + // tri-planar texture bending factor for this fragment's world-space normal + vec3 blending = abs( wNorm ); + blending = (blending -0.2) * 0.7; + blending = normalize(max(blending, 0.00001)); // Force weights to sum to 1.0 (very important!) + float b = (blending.x + blending.y + blending.z); + blending /= vec3(b, b, b); + + // texture coords + vec4 coords = wVert; + vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy ); + + #ifdef ALPHAMAP_1 + vec4 alphaBlend1 = texture2D( m_AlphaMap_1, texCoord.xy ); + #endif + #ifdef ALPHAMAP_2 + vec4 alphaBlend2 = texture2D( m_AlphaMap_2, texCoord.xy ); + #endif + + vec3 normal = vec3(0,0,1); + vec3 n = vec3(0,0,0); + + #ifdef NORMALMAP + n = getTriPlanarBlend(coords, blending, m_NormalMap, m_DiffuseMap_0_scale).xyz; + normal += n * alphaBlend.r; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.r; + #endif + + #ifdef NORMALMAP_1 + n = getTriPlanarBlend(coords, blending, m_NormalMap_1, m_DiffuseMap_1_scale).xyz; + normal += n * alphaBlend.g; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.g; + #endif + + #ifdef NORMALMAP_2 + n = getTriPlanarBlend(coords, blending, m_NormalMap_2, m_DiffuseMap_2_scale).xyz; + normal += n * alphaBlend.b; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.b; + #endif + + #ifdef NORMALMAP_3 + n = getTriPlanarBlend(coords, blending, m_NormalMap_3, m_DiffuseMap_3_scale).xyz; + normal += n * alphaBlend.a; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.a; + #endif + + #ifdef ALPHAMAP_1 + #ifdef NORMALMAP_4 + n = getTriPlanarBlend(coords, blending, m_NormalMap_4, m_DiffuseMap_4_scale).xyz; + normal += n * alphaBlend1.r; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.r; + #endif + + #ifdef NORMALMAP_5 + n = getTriPlanarBlend(coords, blending, m_NormalMap_5, m_DiffuseMap_5_scale).xyz; + normal += n * alphaBlend1.g; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.g; + #endif + + #ifdef NORMALMAP_6 + n = getTriPlanarBlend(coords, blending, m_NormalMap_6, m_DiffuseMap_6_scale).xyz; + normal += n * alphaBlend1.b; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.b; + #endif + + #ifdef NORMALMAP_7 + n = getTriPlanarBlend(coords, blending, m_NormalMap_7, m_DiffuseMap_7_scale).xyz; + normal += n * alphaBlend1.a; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.a; + #endif + #endif + + #ifdef ALPHAMAP_2 + #ifdef NORMALMAP_8 + n = getTriPlanarBlend(coords, blending, m_NormalMap_8, m_DiffuseMap_8_scale).xyz; + normal += n * alphaBlend2.r; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.r; + #endif + + #ifdef NORMALMAP_9 + n = getTriPlanarBlend(coords, blending, m_NormalMap_9, m_DiffuseMap_9_scale).xyz; + normal += n * alphaBlend2.g; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.g; + #endif + + #ifdef NORMALMAP_10 + n = getTriPlanarBlend(coords, blending, m_NormalMap_10, m_DiffuseMap_10_scale).xyz; + normal += n * alphaBlend2.b; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.b; + #endif + + #ifdef NORMALMAP_11 + n = getTriPlanarBlend(coords, blending, m_NormalMap_11, m_DiffuseMap_11_scale).xyz; + normal += n * alphaBlend2.a; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.a; + #endif + #endif + + normal = (normal.xyz * vec3(2.0) - vec3(1.0)); + return normalize(normal); + } + #endif + +#endif + +void main(){ + + //---------------------- + // diffuse calculations + //---------------------- + #ifdef DIFFUSEMAP + #ifdef ALPHAMAP + #ifdef TRI_PLANAR_MAPPING + vec4 diffuseColor = calculateTriPlanarDiffuseBlend(wNormal, wVertex, texCoord); + #else + vec4 diffuseColor = calculateDiffuseBlend(texCoord); + #endif + #else + vec4 diffuseColor = texture2D(m_DiffuseMap, texCoord); + #endif + #else + vec4 diffuseColor = vec4(1.0); + #endif + + + //--------------------- + // normal calculations + //--------------------- + #if defined(NORMALMAP) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(NORMALMAP_5) || defined(NORMALMAP_6) || defined(NORMALMAP_7) || defined(NORMALMAP_8) || defined(NORMALMAP_9) || defined(NORMALMAP_10) || defined(NORMALMAP_11) + #ifdef TRI_PLANAR_MAPPING + vec3 normal = calculateNormalTriPlanar(wNormal, wVertex, texCoord); + #else + vec3 normal = calculateNormal(texCoord); + #endif + mat3 tbnMat = mat3(normalize(vTangent.xyz) , normalize(vBinormal.xyz) , normalize(vNormal.xyz)); + #else + vec3 normal = vNormal; + #endif + + + //----------------------- + // lighting calculations + //----------------------- + gl_FragColor = AmbientSum * diffuseColor; + for( int i = 0;i < NB_LIGHTS; i+=3){ + vec4 lightColor = g_LightData[i]; + vec4 lightData1 = g_LightData[i+1]; + vec4 lightDir; + vec3 lightVec; + lightComputeDir(vPos, lightColor.w, lightData1, lightDir, lightVec); + + float spotFallOff = 1.0; + #if __VERSION__ >= 110 + // allow use of control flow + if(lightColor.w > 1.0){ + #endif + spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); + #if __VERSION__ >= 110 + } + #endif + + #ifdef NORMALMAP + //Normal map -> lighting is computed in tangent space + lightDir.xyz = normalize(lightDir.xyz * tbnMat); + vec3 viewDir = normalize(-vPos.xyz * tbnMat); + #else + //no Normal map -> lighting is computed in view space + lightDir.xyz = normalize(lightDir.xyz); + vec3 viewDir = normalize(-vPos.xyz); + #endif + + vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff, m_Shininess); + gl_FragColor.rgb += DiffuseSum.rgb * lightColor.rgb * diffuseColor.rgb * vec3(light.x) + + SpecularSum.rgb * vec3(light.y); + } + +} \ No newline at end of file diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/SPTerrainLighting.vert b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/SPTerrainLighting.vert new file mode 100644 index 000000000..78036c93c --- /dev/null +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/SPTerrainLighting.vert @@ -0,0 +1,66 @@ +uniform mat4 g_WorldViewProjectionMatrix; +uniform mat4 g_WorldViewMatrix; +uniform mat3 g_NormalMatrix; +uniform mat4 g_ViewMatrix; + +uniform vec4 g_AmbientLightColor; + +attribute vec3 inPosition; +attribute vec3 inNormal; +attribute vec2 inTexCoord; +attribute vec4 inTangent; + +varying vec3 vNormal; +varying vec2 texCoord; +varying vec3 vPos; +varying vec3 vTangent; +varying vec3 vBinormal; + +varying vec4 AmbientSum; +varying vec4 DiffuseSum; +varying vec4 SpecularSum; + +#ifdef TRI_PLANAR_MAPPING + varying vec4 wVertex; + varying vec3 wNormal; +#endif + + + +void main(){ + vec4 pos = vec4(inPosition, 1.0); + gl_Position = g_WorldViewProjectionMatrix * pos; + #ifdef TERRAIN_GRID + texCoord = inTexCoord * 2.0; + #else + texCoord = inTexCoord; + #endif + + vec3 wvPosition = (g_WorldViewMatrix * pos).xyz; + vec3 wvNormal = normalize(g_NormalMatrix * inNormal); + + //-------------------------- + // specific to normal maps: + //-------------------------- + #if defined(NORMALMAP) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(NORMALMAP_5) || defined(NORMALMAP_6) || defined(NORMALMAP_7) || defined(NORMALMAP_8) || defined(NORMALMAP_9) || defined(NORMALMAP_10) || defined(NORMALMAP_11) + vTangent = g_NormalMatrix * inTangent.xyz; + vBinormal = cross(wvNormal, vTangent)* inTangent.w; + #endif + + //------------------------- + // general to all lighting + //------------------------- + vNormal = wvNormal; + vPos = wvPosition; + + AmbientSum = g_AmbientLightColor; + DiffuseSum = vec4(1.0); + SpecularSum = vec4(0.0); + + +#ifdef TRI_PLANAR_MAPPING + wVertex = vec4(inPosition,0.0); + wNormal = inNormal; +#endif + +} \ No newline at end of file diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.frag b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.frag index 68bd2d236..8ab9b993b 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.frag +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.frag @@ -1,3 +1,5 @@ +#import "Common/ShaderLib/PhongLighting.glsllib" +#import "Common/ShaderLib/Lighting.glsllib" uniform float m_Shininess; uniform vec4 g_LightDirection; @@ -145,54 +147,6 @@ varying vec3 lightVec; varying vec3 wNormal; #endif - - -float tangDot(in vec3 v1, in vec3 v2){ - float d = dot(v1,v2); - #ifdef V_TANGENT - d = 1.0 - d*d; - return step(0.0, d) * sqrt(d); - #else - return d; - #endif -} - - -float lightComputeDiffuse(in vec3 norm, in vec3 lightdir, in vec3 viewdir){ - return max(0.0, dot(norm, lightdir)); -} - -float lightComputeSpecular(in vec3 norm, in vec3 viewdir, in vec3 lightdir, in float shiny){ - #ifdef WARDISO - // Isotropic Ward - vec3 halfVec = normalize(viewdir + lightdir); - float NdotH = max(0.001, tangDot(norm, halfVec)); - float NdotV = max(0.001, tangDot(norm, viewdir)); - float NdotL = max(0.001, tangDot(norm, lightdir)); - float a = tan(acos(NdotH)); - float p = max(shiny/128.0, 0.001); - return NdotL * (1.0 / (4.0*3.14159265*p*p)) * (exp(-(a*a)/(p*p)) / (sqrt(NdotV * NdotL))); - #else - // Standard Phong - vec3 R = reflect(-lightdir, norm); - return pow(max(tangDot(R, viewdir), 0.0), shiny); - #endif -} - -vec2 computeLighting(in vec3 wvPos, in vec3 wvNorm, in vec3 wvViewDir, in vec3 wvLightDir){ - float diffuseFactor = lightComputeDiffuse(wvNorm, wvLightDir, wvViewDir); - float specularFactor = lightComputeSpecular(wvNorm, wvViewDir, wvLightDir, m_Shininess); - - if (m_Shininess <= 1.0) { - specularFactor = 0.0; // should be one instruction on most cards .. - } - - float att = vLightDir.w; - - return vec2(diffuseFactor, specularFactor) * vec2(att); -} - - #ifdef ALPHAMAP vec4 calculateDiffuseBlend(in vec2 texCoord) { @@ -355,7 +309,7 @@ vec2 computeLighting(in vec3 wvPos, in vec3 wvNorm, in vec3 wvViewDir, in vec3 w vec4 getTriPlanarBlend(in vec4 coords, in vec3 blending, in sampler2D map, in float scale) { vec4 col1 = texture2D( map, coords.yz * scale); vec4 col2 = texture2D( map, coords.xz * scale); - vec4 col3 = texture2D( map, coords.xy * scale); + vec4 col3 = texture2D( map, coords.xy * scale); // blend the results of the 3 planar projections. vec4 tex = col1 * blending.x + col2 * blending.y + col3 * blending.z; return tex; @@ -627,7 +581,7 @@ void main(){ spotFallOff = clamp(spotFallOff, 0.0, 1.0); } } - + //--------------------- // normal calculations //--------------------- @@ -648,7 +602,7 @@ void main(){ vec4 lightDir = vLightDir; lightDir.xyz = normalize(lightDir.xyz); - vec2 light = computeLighting(vPosition, normal, vViewDir.xyz, lightDir.xyz)*spotFallOff; + vec2 light = computeLighting(normal, vViewDir.xyz, lightDir.xyz,lightDir.w*spotFallOff,m_Shininess); vec4 specularColor = vec4(1.0); diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md index 04470ca26..48c404da4 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md @@ -163,6 +163,70 @@ MaterialDef Terrain Lighting { } } + + Technique { + + LightMode SinglePass + + VertexShader GLSL100: Common/MatDefs/Terrain/SPTerrainLighting.vert + FragmentShader GLSL100: Common/MatDefs/Terrain/SPTerrainLighting.frag + + WorldParameters { + WorldViewProjectionMatrix + NormalMatrix + WorldViewMatrix + ViewMatrix + } + + Defines { + TRI_PLANAR_MAPPING : useTriPlanarMapping + TERRAIN_GRID : isTerrainGrid + WARDISO : WardIso + + DIFFUSEMAP : DiffuseMap + DIFFUSEMAP_1 : DiffuseMap_1 + DIFFUSEMAP_2 : DiffuseMap_2 + DIFFUSEMAP_3 : DiffuseMap_3 + DIFFUSEMAP_4 : DiffuseMap_4 + DIFFUSEMAP_5 : DiffuseMap_5 + DIFFUSEMAP_6 : DiffuseMap_6 + DIFFUSEMAP_7 : DiffuseMap_7 + DIFFUSEMAP_8 : DiffuseMap_8 + DIFFUSEMAP_9 : DiffuseMap_9 + DIFFUSEMAP_10 : DiffuseMap_10 + DIFFUSEMAP_11 : DiffuseMap_11 + NORMALMAP : NormalMap + NORMALMAP_1 : NormalMap_1 + NORMALMAP_2 : NormalMap_2 + NORMALMAP_3 : NormalMap_3 + NORMALMAP_4 : NormalMap_4 + NORMALMAP_5 : NormalMap_5 + NORMALMAP_6 : NormalMap_6 + NORMALMAP_7 : NormalMap_7 + NORMALMAP_8 : NormalMap_8 + NORMALMAP_9 : NormalMap_9 + NORMALMAP_10 : NormalMap_10 + NORMALMAP_11 : NormalMap_11 + SPECULARMAP : SpecularMap + ALPHAMAP : AlphaMap + ALPHAMAP_1 : AlphaMap_1 + ALPHAMAP_2 : AlphaMap_2 + DIFFUSEMAP_0_SCALE : DiffuseMap_0_scale + DIFFUSEMAP_1_SCALE : DiffuseMap_1_scale + DIFFUSEMAP_2_SCALE : DiffuseMap_2_scale + DIFFUSEMAP_3_SCALE : DiffuseMap_3_scale + DIFFUSEMAP_4_SCALE : DiffuseMap_4_scale + DIFFUSEMAP_5_SCALE : DiffuseMap_5_scale + DIFFUSEMAP_6_SCALE : DiffuseMap_6_scale + DIFFUSEMAP_7_SCALE : DiffuseMap_7_scale + DIFFUSEMAP_8_SCALE : DiffuseMap_8_scale + DIFFUSEMAP_9_SCALE : DiffuseMap_9_scale + DIFFUSEMAP_10_SCALE : DiffuseMap_10_scale + DIFFUSEMAP_11_SCALE : DiffuseMap_11_scale + } + } + + Technique PreShadow { VertexShader GLSL100 : Common/MatDefs/Shadow/PreShadow.vert diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.vert b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.vert index a3a1cc24e..e03f03f7f 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.vert +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.vert @@ -1,3 +1,5 @@ +#import "Common/ShaderLib/Lighting.glsllib" + uniform mat4 g_WorldViewProjectionMatrix; uniform mat4 g_WorldViewMatrix; uniform mat3 g_NormalMatrix; @@ -34,16 +36,6 @@ varying vec4 SpecularSum; varying vec3 wNormal; #endif -// JME3 lights in world space -void lightComputeDir(in vec3 worldPos, in vec4 color, in vec4 position, out vec4 lightDir){ - float posLight = step(0.5, color.w); - vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight); - lightVec.xyz = tempVec; - float dist = length(tempVec); - lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0); - lightDir.xyz = tempVec / vec3(dist); -} - void main(){ vec4 pos = vec4(inPosition, 1.0); @@ -66,35 +58,30 @@ void main(){ // specific to normal maps: //-------------------------- #if defined(NORMALMAP) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(NORMALMAP_5) || defined(NORMALMAP_6) || defined(NORMALMAP_7) || defined(NORMALMAP_8) || defined(NORMALMAP_9) || defined(NORMALMAP_10) || defined(NORMALMAP_11) - vec3 wvTangent = normalize(g_NormalMatrix * inTangent.xyz); - vec3 wvBinormal = cross(wvNormal, wvTangent); + vec3 wvTangent = normalize(g_NormalMatrix * inTangent.xyz); + vec3 wvBinormal = cross(wvNormal, wvTangent); - mat3 tbnMat = mat3(wvTangent, wvBinormal * -inTangent.w,wvNormal); + mat3 tbnMat = mat3(wvTangent, wvBinormal * inTangent.w,wvNormal); - vPosition = wvPosition * tbnMat; - vViewDir = viewDir * tbnMat; - lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir); - vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz; - #else + vPosition = wvPosition * tbnMat; + vViewDir = viewDir * tbnMat; - //------------------------- - // general to all lighting - //------------------------- - vNormal = wvNormal; + lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); + vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz; + #else + //------------------------- + // general to all lighting + //------------------------- + vNormal = wvNormal; - vPosition = wvPosition; - vViewDir = viewDir; + vPosition = wvPosition; + vViewDir = viewDir; - lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir); + lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); #endif - //computing spot direction in view space and unpacking spotlight cos - // spotVec=(g_ViewMatrix *vec4(g_LightDirection.xyz,0.0) ); - // spotVec.w=floor(g_LightDirection.w)*0.001; - // lightVec.w = fract(g_LightDirection.w); - - AmbientSum = vec4(0.2, 0.2, 0.2, 1.0) * g_AmbientLightColor; // Default: ambient color is dark gray + AmbientSum = g_AmbientLightColor; // Default: ambient color is dark gray DiffuseSum = lightColor; SpecularSum = lightColor;