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 b52f4ac08e..70911d855a 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2023 jMonkeyEngine + * Copyright (c) 2009-2025 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -247,10 +247,19 @@ protected void deinitInThread() { } listener.destroy(); - + // releases the view holder from the Android Input Resources + // releasing the view enables the context instance to be + // reclaimed by the GC. + // if not released; it leads to a weak reference leak + // disabling the destruction of the Context View Holder. + androidInput.setView(null); + + // nullifying the references + // signals their memory to be reclaimed listener = null; renderer = null; timer = null; + androidInput = null; // do android specific cleaning here logger.fine("Display destroyed."); diff --git a/jme3-android/src/main/java/com/jme3/view/surfaceview/JmeSurfaceView.java b/jme3-android/src/main/java/com/jme3/view/surfaceview/JmeSurfaceView.java index d364ab0923..67d73f4b5c 100644 --- a/jme3-android/src/main/java/com/jme3/view/surfaceview/JmeSurfaceView.java +++ b/jme3-android/src/main/java/com/jme3/view/surfaceview/JmeSurfaceView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2022 jMonkeyEngine + * Copyright (c) 2009-2025 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -239,11 +239,7 @@ public void startRenderer(int delayMillis) { } private void removeGLSurfaceView() { - ((Activity) getContext()).runOnUiThread(() -> { - if (glSurfaceView != null) { - JmeSurfaceView.this.removeView(glSurfaceView); - } - }); + ((Activity) getContext()).runOnUiThread(() -> JmeSurfaceView.this.removeView(glSurfaceView)); } @Override @@ -265,19 +261,34 @@ public void handleError(String errorMsg, Throwable throwable) { public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { switch (event) { case ON_DESTROY: - /*destroy only if the policy flag is enabled*/ - if (destructionPolicy == DestructionPolicy.DESTROY_WHEN_FINISH) { - legacyApplication.stop(!isGLThreadPaused()); - } + // activity is off the foreground stack + // activity is being destructed completely as a result of Activity#finish() + // this is a killable automata state! + jmeSurfaceViewLogger.log(Level.INFO, "Hosting Activity has been destructed."); break; case ON_PAUSE: - loseFocus(); + // activity is still on the foreground stack but not + // on the topmost level or before transition to stopped/hidden or destroyed state + // as a result of dispatch to Activity#finish() + // activity is no longer visible and is out of foreground + if (((Activity) getContext()).isFinishing()) { + if (destructionPolicy == DestructionPolicy.DESTROY_WHEN_FINISH) { + legacyApplication.stop(!isGLThreadPaused()); + } else if (destructionPolicy == DestructionPolicy.KEEP_WHEN_FINISH) { + jmeSurfaceViewLogger.log(Level.INFO, "Context stops, but game is still running."); + } + } else { + loseFocus(); + } break; case ON_RESUME: + // activity is back to the topmost of the + // foreground stack gainFocus(); break; case ON_STOP: - jmeSurfaceViewLogger.log(Level.INFO, "Context stops, but game is still running"); + // activity is out off the foreground stack or being destructed by a finishing dispatch + // this is a killable automata state! break; } } @@ -404,13 +415,13 @@ public void loseFocus() { @Override public void destroy() { - /*skip the destroy block if the invoking instance is null*/ - if (legacyApplication == null) { - return; + if (glSurfaceView != null) { + removeGLSurfaceView(); + } + if (legacyApplication != null) { + legacyApplication.destroy(); } - removeGLSurfaceView(); - legacyApplication.destroy(); - /*help the Dalvik Garbage collector to destruct the pointers, by making them nullptr*/ + /*help the Dalvik Garbage collector to destruct the objects, by releasing their references*/ /*context instances*/ legacyApplication = null; appSettings = null; @@ -430,10 +441,10 @@ public void destroy() { onRendererCompleted = null; onExceptionThrown = null; onLayoutDrawn = null; - /*nullifying the static memory (pushing zero to registers to prepare for a clean use)*/ GameState.setLegacyApplication(null); GameState.setFirstUpdatePassed(false); - jmeSurfaceViewLogger.log(Level.INFO, "Context and Game have been destructed"); + JmeAndroidSystem.setView(null); + jmeSurfaceViewLogger.log(Level.INFO, "Context and Game have been destructed."); } @Override @@ -516,11 +527,13 @@ public void bindAppStateToActivityLifeCycle(final boolean condition) { /*register this Ui Component as an observer to the context of jmeSurfaceView only if this context is a LifeCycleOwner*/ if (getContext() instanceof LifecycleOwner) { ((LifecycleOwner) getContext()).getLifecycle().addObserver(JmeSurfaceView.this); + jmeSurfaceViewLogger.log(Level.INFO, "Command binding SurfaceView to the Activity Lifecycle."); } } else { /*un-register this Ui Component as an observer to the context of jmeSurfaceView only if this context is a LifeCycleOwner*/ if (getContext() instanceof LifecycleOwner) { ((LifecycleOwner) getContext()).getLifecycle().removeObserver(JmeSurfaceView.this); + jmeSurfaceViewLogger.log(Level.INFO, "Command removing SurfaceView from the Activity Lifecycle."); } } } @@ -917,7 +930,7 @@ public void setShowErrorDialog(boolean showErrorDialog) { } /** - * Determines whether the app context would be destructed + * Determines whether the app context would be destructed as a result of dispatching {@link Activity#finish()} * with the holder activity context in case of {@link DestructionPolicy#DESTROY_WHEN_FINISH} or be * spared for a second use in case of {@link DestructionPolicy#KEEP_WHEN_FINISH}. * Default value is : {@link DestructionPolicy#DESTROY_WHEN_FINISH}. @@ -926,12 +939,14 @@ public void setShowErrorDialog(boolean showErrorDialog) { */ public enum DestructionPolicy { /** - * Finishes the game context with the activity context (ignores the static memory {@link GameState#legacyApplication}). + * Finishes the game context with the activity context (ignores the static memory {@link GameState#legacyApplication}) + * as a result of dispatching {@link Activity#finish()}. */ DESTROY_WHEN_FINISH, /** * Spares the game context inside a static memory {@link GameState#legacyApplication} - * when the activity context is destroyed, but the app stills in the background. + * when the activity context is destroyed dispatching {@link Activity#finish()}, but the {@link android.app.Application} + * stills in the background. */ KEEP_WHEN_FINISH } diff --git a/jme3-core/src/main/java/com/jme3/anim/tween/action/BlendSpace.java b/jme3-core/src/main/java/com/jme3/anim/tween/action/BlendSpace.java index a88be7529c..17b66f8b07 100644 --- a/jme3-core/src/main/java/com/jme3/anim/tween/action/BlendSpace.java +++ b/jme3-core/src/main/java/com/jme3/anim/tween/action/BlendSpace.java @@ -1,10 +1,95 @@ +/* + * Copyright (c) 2009-2025 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.anim.tween.action; +/** + * A provider interface which provides a value {@link BlendSpace#getWeight()} to control the blending between 2 successive actions in a {@link BlendAction}. + * The blending weight is a read-only value, and it can be manipulated using the arbitrary value {@link BlendSpace#setValue(float)} during the application runtime. + * + *

+ * Notes about the blending action and its relations with the blending weight: + *

+ *

+ * + *

+ * Different blending weight case scenarios managed by {@link BlendAction} internally: + *

+ *

+ * + *

+ * Notes about the blending weight value: + *

+ *

+ * + * Created by Nehon. + * @see LinearBlendSpace an example of blendspace implementation + */ public interface BlendSpace { + /** + * Adjusts the target blend action instance that will utilize the blend weight value provided by this blend-space implementation. + * + * @param action the blend action instance that will utilize this blend-space (not null). + */ public void setBlendAction(BlendAction action); + /** + * Provides the blend weight value to the assigned {@link BlendAction} instance, + * this value will be used for interpolating a collection of actions' transformations (i.e., keyframes). + * + * @return the blending weight value in the range from 0 to 1, + * negative values and values above 1 aren't allowed. + * @see LinearBlendSpace#getWeight() + */ public float getWeight(); + /** + * An arbitrary value used for adjusting the blending weight value. + * + * @param value the value in floats. + * @see LinearBlendSpace#setValue(float) + */ public void setValue(float value); } 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 f65b08c2ed..adf4268810 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag @@ -6,25 +6,9 @@ #import "Common/ShaderLib/Lighting.glsllib" #endif -// fog - jayfella #ifdef USE_FOG -#import "Common/ShaderLib/MaterialFog.glsllib" -varying float fog_distance; -uniform vec4 m_FogColor; - -#ifdef FOG_LINEAR -uniform vec2 m_LinearFog; -#endif - -#ifdef FOG_EXP -uniform float m_ExpFog; -#endif - -#ifdef FOG_EXPSQ -uniform float m_ExpSqFog; -#endif - -#endif // end fog + #import "Common/ShaderLib/MaterialFog.glsllib" +#endif varying vec2 texCoord; #ifdef SEPARATE_TEXCOORD @@ -231,21 +215,11 @@ void main(){ SpecularSum2.rgb * specularColor.rgb * vec3(light.y); #endif - // add fog after the lighting because shadows will cause the fog to darken // which just results in the geometry looking like it's changed color #ifdef USE_FOG - #ifdef FOG_LINEAR - gl_FragColor = getFogLinear(gl_FragColor, m_FogColor, m_LinearFog.x, m_LinearFog.y, fog_distance); - #endif - #ifdef FOG_EXP - gl_FragColor = getFogExp(gl_FragColor, m_FogColor, m_ExpFog, fog_distance); - #endif - #ifdef FOG_EXPSQ - gl_FragColor = getFogExpSquare(gl_FragColor, m_FogColor, m_ExpSqFog, fog_distance); - #endif - #endif // end fog - + gl_FragColor = MaterialFog_calculateFogColor(vec4(gl_FragColor)); + #endif gl_FragColor.a = alpha; } diff --git a/jme3-core/src/main/resources/Common/ShaderLib/MaterialFog.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/MaterialFog.glsllib index 141565539a..473835b0ce 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/MaterialFog.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/MaterialFog.glsllib @@ -1,7 +1,7 @@ +//author @jayfella #ifndef __MATERIAL_FOG_UTIL__ #define __MATERIAL_FOG_UTIL__ - vec4 getFogLinear(in vec4 diffuseColor, in vec4 fogColor, in float start, in float end, in float distance) { float fogFactor = (end - distance) / (end - start); @@ -39,8 +39,7 @@ #ifdef FOG_EXPSQ uniform float m_ExpSqFog; - #endif - + #endif vec4 MaterialFog_calculateFogColor(in vec4 fragColor){ #ifdef FOG_LINEAR @@ -54,7 +53,7 @@ #endif return fragColor; - } + } #endif #endif diff --git a/jme3-core/src/main/resources/Common/ShaderLib/module/pbrlighting/PBRLightingUtils.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/module/pbrlighting/PBRLightingUtils.glsllib index f5136cbe74..d30388e62c 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/module/pbrlighting/PBRLightingUtils.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/module/pbrlighting/PBRLightingUtils.glsllib @@ -236,7 +236,7 @@ Math_lengthAndNormalize(light.vector,dist,L); float invRange=light.invRadius; // position.w - const float light_threshold=0.01; + const float light_threshold = 0.01; #ifdef SRGB light.fallOff = (1.0 - invRange * dist) / (1.0 + invRange * dist * dist); // lightDir.w @@ -272,11 +272,26 @@ PBRSurface PBRLightingUtils_createPBRSurface(in vec3 wViewDir){ - PBRSurface surface; + PBRSurface surface; //creates a new PBRSurface + surface.position = wPosition; surface.viewDir = wViewDir; surface.geometryNormal = normalize(wNormal); + //set default values + surface.hasTangents = false; + surface.hasBasicLightMap = false; + surface.albedo = vec3(1.0); + surface.normal = surface.geometryNormal; + surface.emission = vec3(0.0); + surface.ao = vec3(1.0); + surface.lightMapColor = vec3(0.0); + surface.alpha = 1.0; + surface.roughness = 1.0; + surface.metallic = 0.0; + surface.alpha = 1.0; + surface.exposure = 1.0; + return surface; } @@ -285,9 +300,9 @@ void PBRLightingUtils_readPBRSurface(inout PBRSurface surface){ - surface.bakedLightContribution = vec3(0); - surface.directLightContribution = vec3(0); - surface.envLightContribution = vec3(0); + surface.bakedLightContribution = vec3(0.0); + surface.directLightContribution = vec3(0.0); + surface.envLightContribution = vec3(0.0); #ifdef ENABLE_PBRLightingUtils_getWorldTangent vec3 tan = normalize(wTangent.xyz); @@ -297,7 +312,7 @@ #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) - vec3 vViewDir = wViewDir * surface.tbnMat; + vec3 vViewDir = surface.viewDir * surface.tbnMat; #ifdef STEEP_PARALLAX #ifdef NORMALMAP_PARALLAX //parallax map is stored in the alpha channel of the normal map @@ -429,7 +444,7 @@ #endif surface.emission = emissive.rgb * pow(emissive.a, m_EmissivePower) * m_EmissiveIntensity; #else - surface.emission = vec3(0); + surface.emission = vec3(0.0); #endif PBRLightingUtils_readSunLightExposureParams(surface); @@ -573,8 +588,8 @@ #if NB_PROBES > 0 - float probeNdfSum=0; - float invProbeNdfSum=0; + float probeNdfSum = 0.0; + float invProbeNdfSum = 0.0; #for i=1..4 ( #if NB_PROBES >= $i $0 #endif ) vec3 probeColor$i; @@ -607,7 +622,7 @@ #endfor #if NB_PROBES > 1 - float probeWeightSum=0; + float probeWeightSum = 0.0; #for i=1..4 ( #if NB_PROBES >= $i $0 #endif ) float probeWeight$i = ((1.0 - (probeNdf$i / probeNdfSum)) / (NB_PROBES - 1)) * ( probeInvNdf$i / invProbeNdfSum); probeWeightSum += probeWeight$i; @@ -650,6 +665,9 @@ else if(debugValuesMode == 7){ outputColorForLayer.rgb = vec3(surface.alpha); } + else if(debugValuesMode == 8){ + outputColorForLayer.rgb = vec3(surface.geometryNormal); + } if(debugValuesMode >= 0){ gl_FragColor.a = 1.0;