[SOLVED] Android Gradle 4.1.2 causes AssertionError At com.jme3.bounding.Intersection.intersect(Intersection.java:67)

Hi there, i have updated to gradle 4.1.2 recently in android , then i have got an AssertionError on trying to run my project , I am using custom container for jme game that’s similar to AndroidHarness but it runs on UI thread instead.

the Error :

2021-02-02 10:39:22.529 789-1295/com.myGame E/AndroidRuntime: FATAL EXCEPTION: GLThread 2865
    Process: com.myGame, PID: 789
    java.lang.AssertionError
        at com.jme3.bounding.Intersection.intersect(Intersection.java:67)
        at com.jme3.bounding.BoundingSphere.intersectsBoundingBox(BoundingSphere.java:683)
        at com.jme3.bounding.BoundingBox.intersects(BoundingBox.java:595)
        at com.jme3.shadow.ShadowUtil$OccludersExtractor.process(ShadowUtil.java:428)
        at com.jme3.shadow.ShadowUtil$OccludersExtractor.addOccluders(ShadowUtil.java:368)
        at com.jme3.shadow.ShadowUtil.updateShadowCamera(ShadowUtil.java:501)
        at com.jme3.shadow.DirectionalLightShadowRenderer.getOccludersToRender(DirectionalLightShadowRenderer.java:194)
        at com.jme3.shadow.AbstractShadowRenderer.renderShadowMap(AbstractShadowRenderer.java:427)
        at com.jme3.shadow.AbstractShadowRenderer.postQueue(AbstractShadowRenderer.java:412)
        at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:1103)
        at com.jme3.renderer.RenderManager.render(RenderManager.java:1158)
        at com.jme3.app.SimpleApplication.update(SimpleApplication.java:272)
        at com.scrappers.jmesurfaceview.JmESurfaceView.update(JmESurfaceView.java:189)
        at com.jme3.system.android.OGLESContext.onDrawFrame(OGLESContext.java:348)
        at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1571)
        at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1270)

My code (custom container) :

package com.scrappers.jmesurfaceview;

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;

import com.jme3.app.SimpleApplication;
import com.jme3.audio.AudioRenderer;
import com.jme3.input.JoyInput;
import com.jme3.input.android.AndroidSensorJoyInput;
import com.jme3.system.AppSettings;
import com.jme3.system.SystemListener;
import com.jme3.system.android.JmeAndroidSystem;
import com.jme3.system.android.OGLESContext;
import com.scrappers.jmesurfaceview.Dialog.OptionPane;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import androidx.core.content.ContextCompat;

/**
 * @author Pavly Gerges aka @pavl_g (A founder of Scrappers-glitch).
 * A CardView Class Holder that holds a #{{@link GLSurfaceView}} using #{{@link OGLESContext}} as a renderer to render
 * a JME game on an android view for custom xmL designs.
 */
public class JmESurfaceView extends RelativeLayout implements SystemListener {

    private SimpleApplication simpleApplication;
    protected String audioRendererType = AppSettings.ANDROID_OPENAL_SOFT;
    private AppSettings appSettings;
    private AppCompatActivity appCompatActivity;
    private int eglBitsPerPixel = 24;
    private int eglAlphaBits = 0;
    private int eglDepthBits = 16;
    private int eglSamples = 0;
    private int eglStencilBits = 0;
    private int frameRate = -1;
    private boolean emulateKeyBoard=true;
    private boolean emulateMouse=true;
    private boolean useJoyStickEvents=true;
    private ProgressBar progressBar;
    private boolean isGLThreadPaused;
    private ScheduledFuture<GLSurfaceView> glSurfaceViewFuture;

    public JmESurfaceView(@NonNull Context context) {
        super(context);
    }

    public JmESurfaceView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public JmESurfaceView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setJMEGame(SimpleApplication simpleApplication,AppCompatActivity appCompatActivity){
        this.simpleApplication=simpleApplication;
        this.appCompatActivity=appCompatActivity;
        showProgress();
    }
    public void showErrorDialog(String errorMessage){
        OptionPane optionPane=new OptionPane(appCompatActivity);
        optionPane.showDialog(R.layout.dialog_exception, Gravity.CENTER);
        optionPane.getAlertDialog().getWindow().setBackgroundDrawable(ContextCompat.getDrawable(this.getContext(),R.drawable.dialog_exception_background));
        EditText errorContainer=optionPane.getInflater().findViewById(R.id.errorText);
        errorContainer.setText(errorMessage);

        optionPane.getInflater().findViewById(R.id.closeApp).setOnClickListener(view -> {
           optionPane.getAlertDialog().dismiss();
           simpleApplication.stop(isGLThreadPaused());
           simpleApplication.destroy();
           appCompatActivity.finish();
        });
        optionPane.getInflater().findViewById(R.id.ignoreError).setOnClickListener(view -> optionPane.getAlertDialog().dismiss());
    }
    private void showProgress(){
        progressBar=new ProgressBar(this.getContext());
        DisplayMetrics displayMetrics=new DisplayMetrics();
        appCompatActivity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        progressBar.setLayoutParams(new LayoutParams(displayMetrics.widthPixels/4,displayMetrics.widthPixels/4));

        progressBar.setX((float) (displayMetrics.widthPixels/2 - progressBar.getLayoutParams().width/2));
        progressBar.setY((float)(displayMetrics.heightPixels/2 - progressBar.getLayoutParams().height/2));
        this.addView(progressBar,0);
    }
    private void hideProgress(){
        this.removeView(progressBar);
    }
    public void startRenderer(int delayMillis){
        /*enclosing the renderer thread in a FutureAsync task from the UI Thread*/
        ScheduledThreadPoolExecutor executor=new ScheduledThreadPoolExecutor(2);
        glSurfaceViewFuture= executor.schedule(new RendererThread(),delayMillis, TimeUnit.MILLISECONDS);
        try {
            if( glSurfaceViewFuture.get()!=null){
                /* add the openGL view to the cardView/FrameLayout from the future thread*/
                JmESurfaceView.this.addView(glSurfaceViewFuture.get(), 1);
            }
        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    private class RendererThread implements Callable<GLSurfaceView>{
        private GLSurfaceView glSurfaceView;
        @Override
        public GLSurfaceView call() {
            Looper.prepare();
            if ( simpleApplication != null ){
                try {
                    /*initialize App Settings & start the Game*/
                    appSettings = new AppSettings(true);
                    appSettings.setAudioRenderer(audioRendererType);
                    appSettings.setResolution(JmESurfaceView.this.getLayoutParams().width, JmESurfaceView.this.getLayoutParams().height);
                    appSettings.setAlphaBits(eglAlphaBits);
                    appSettings.setDepthBits(eglDepthBits);
                    appSettings.setSamples(eglSamples);
                    appSettings.setStencilBits(eglStencilBits);
                    appSettings.setBitsPerPixel(eglBitsPerPixel);
                    appSettings.setEmulateKeyboard(emulateKeyBoard);
                    appSettings.setEmulateMouse(emulateMouse);
                    appSettings.setUseJoysticks(useJoyStickEvents);
                    simpleApplication.setSettings(appSettings);
                    /*start jme game context*/
                    simpleApplication.start();
                    /*attach the game to JmE OpenGL.Renderer context */
                    OGLESContext oglesContext = (OGLESContext) simpleApplication.getContext();
                    /*create a glSurfaceView that will hold the renderer thread*/
                    glSurfaceView = oglesContext.createView(JmESurfaceView.this.getContext());
                    /*set the current view as the system engine thread view for future uses*/
                    JmeAndroidSystem.setView(JmESurfaceView.this);
                    /*set JME system Listener to initialize game , update , requestClose & destroy on closure*/
                    oglesContext.setSystemListener(JmESurfaceView.this);
                    /* set the glSurfaceView to fit the widget */
                    glSurfaceView.setLayoutParams(new LayoutParams(JmESurfaceView.this.getLayoutParams().width, JmESurfaceView.this.getLayoutParams().height));
                }catch (Exception e){
                    e.printStackTrace();
                }

            }
            return glSurfaceView;
        }
    }

    @Override
    public void initialize() {
        if(simpleApplication !=null){
            simpleApplication.initialize();
            hideProgress();
        }

    }

    @Override
    public void reshape(int width, int height) {
        if(simpleApplication !=null){
            simpleApplication.reshape(width, height);
        }
    }

    @Override
    public void update() {
        if(simpleApplication ==null){
            return;
        }
        try {
            if(glSurfaceViewFuture.get()!=null){
                simpleApplication.update();
            }
        } catch (ExecutionException | InterruptedException  e) {
            e.printStackTrace();
        }
    }

    @Override
    public void requestClose(boolean esc) {
        if(simpleApplication !=null){
            simpleApplication.requestClose(esc);
        }
    }

    @Override
    public void gainFocus() {
        if (simpleApplication != null) {
            /*resume the audio*/
            AudioRenderer audioRenderer = simpleApplication.getAudioRenderer();
            if (audioRenderer != null) {
                audioRenderer.resumeAll();
            }
            /*resume the sensors (aka joysticks)*/
            if (simpleApplication.getContext() != null) {
                JoyInput joyInput = simpleApplication.getContext().getJoyInput();
                if (joyInput != null) {
                    if (joyInput instanceof AndroidSensorJoyInput ) {
                        AndroidSensorJoyInput androidJoyInput = (AndroidSensorJoyInput) joyInput;
                        androidJoyInput.resumeSensors();
                    }
                }
                simpleApplication.gainFocus();
            }
        }
        setGLThreadPaused(false);
    }

    @Override
    public void loseFocus() {
        if (simpleApplication != null) {
            /*pause the audio*/
            simpleApplication.loseFocus();
            AudioRenderer audioRenderer = simpleApplication.getAudioRenderer();
            if (audioRenderer != null) {
                audioRenderer.pauseAll();
            }
            /*pause the sensors (aka joysticks)*/
            if (simpleApplication.getContext() != null) {
                JoyInput joyInput = simpleApplication.getContext().getJoyInput();
                if (joyInput != null) {
                    if (joyInput instanceof AndroidSensorJoyInput) {
                        AndroidSensorJoyInput androidJoyInput = (AndroidSensorJoyInput) joyInput;
                        androidJoyInput.pauseSensors();
                    }
                }
            }
        }
        setGLThreadPaused(true);
    }

    @Override
    public void handleError(String errorMsg, Throwable t) {
        System.out.println(errorMsg);
    }

    @Override
    public void destroy() {
        if (simpleApplication != null) {
            simpleApplication.stop(isGLThreadPaused());
            simpleApplication.destroy();
        }
    }

    public SimpleApplication getSimpleApplication() {
        return simpleApplication;
    }

    public void setSimpleApplication(SimpleApplication simpleApplication) {
        this.simpleApplication = simpleApplication;
    }

    public AppSettings getAppSettings() {
        return appSettings;
    }

    public void setAppSettings(AppSettings appSettings) {
        this.appSettings = appSettings;
    }

    public int getEglBitsPerPixel() {
        return eglBitsPerPixel;
    }

    public void setEglBitsPerPixel(int eglBitsPerPixel) {
        this.eglBitsPerPixel = eglBitsPerPixel;
    }

    public int getEglAlphaBits() {
        return eglAlphaBits;
    }

    public void setEglAlphaBits(int eglAlphaBits) {
        this.eglAlphaBits = eglAlphaBits;
    }

    public int getEglDepthBits() {
        return eglDepthBits;
    }

    public void setEglDepthBits(int eglDepthBits) {
        this.eglDepthBits = eglDepthBits;
    }

    public int getEglSamples() {
        return eglSamples;
    }

    public void setEglSamples(int eglSamples) {
        this.eglSamples = eglSamples;
    }

    public int getEglStencilBits() {
        return eglStencilBits;
    }

    public void setEglStencilBits(int eglStencilBits) {
        this.eglStencilBits = eglStencilBits;
    }

    public int getFrameRate() {
        return frameRate;
    }

    public void setFrameRate(int frameRate) {
        this.frameRate = frameRate;
    }

    public String getAudioRendererType() {
        return audioRendererType;
    }

    public void setAudioRendererType(String audioRendererType) {
        this.audioRendererType = audioRendererType;
    }

    public boolean isEmulateKeyBoard() {
        return emulateKeyBoard;
    }

    public void setEmulateKeyBoard(boolean emulateKeyBoard) {
        this.emulateKeyBoard = emulateKeyBoard;
    }

    public boolean isEmulateMouse() {
        return emulateMouse;
    }

    public void setEmulateMouse(boolean emulateMouse) {
        this.emulateMouse = emulateMouse;
    }

    public boolean isUseJoyStickEvents() {
        return useJoyStickEvents;
    }

    public void setUseJoyStickEvents(boolean useJoyStickEvents) {
        this.useJoyStickEvents = useJoyStickEvents;
    }

    public boolean isGLThreadPaused() {
        return isGLThreadPaused;
    }

    public void setGLThreadPaused(boolean GLThreadPaused) {
        isGLThreadPaused = GLThreadPaused;
    }
}

this was the main problem in SystemListener Update method :

  @Override
    public void update() {
        if(simpleApplication ==null){
            return;
        }
        try {
            if(glSurfaceViewFuture.get()!=null){
                simpleApplication.update();
            }
        } catch (ExecutionException | InterruptedException  e) {
            e.printStackTrace();
        }
    }

that is reflected from Intersection.java class that has assertion statement :

 public static boolean intersect(BoundingSphere sphere, Vector3f center, float radius) {
        assert Vector3f.isValidVector(center) && Vector3f.isValidVector(sphere.center);

        TempVars vars = TempVars.get();
        try {
            Vector3f diff = center.subtract(sphere.center, vars.vect1);
            float rsum = sphere.getRadius() + radius;
            return (diff.dot(diff) <= rsum * rsum);
        } finally {
            vars.release();
        }
    }

i think that gradle 4.1.2 has enabled assertion ,may be , but when try...catch AssertionError , it works fine , but hey i cannot catch a programmatical error or ignore it , can I ?

although it works fine on gradle 4.0.2 , but i would like to know where’s the problem.

Any clue ?

thanks.

NB i havenot tried AndroidHarness but i think it will lead to the same issue , since my custom container is already very similar.

1 Like

Just making a point… you should never catch assertion error. Just turn off assertions. It’s a super bad practice to catch them… it won’t just shoot you in the foot someday but will blow off your whole leg and kill anyone standing around you.

Just turn them off. “I don’t know how to turn them off.” Then focus on that… but never catch the error.

As to the actual error, most likely cause is a bad quaternion somewhere that’s making the bounds center go to NaN or Infinity. Maybe the shadow bounds stuff is unhappy with something you’ve done. I can only speculate.

Some careful logging might sort it out.

1 Like

I was predicting that reply , too :smile:

okay , i will see if i can do some logs , or create a bare-bone small game to discover the problem.

i cannot use command java -disableassertions className.java for android contextes , i get packges doesnot exist & compilation failure .

i am not sure about , what i can do , the very first thing is to look at my game code , skys , spatials , terrains , materials , its a simple demo anyway then i will reach for logging if i didnot find a clue .

This command doesn’t even make sense for regular Java.

…but there has to be a way to disable assertions in the andoid build that makes your app. Has to be.

1 Like
        ClassLoader classLoader=getClass().getClassLoader();
        classLoader.setDefaultAssertionStatus(false);
        classLoader.setClassAssertionStatus(this.getClass().getName(),false);

i have tried those at the constructor level of my custom app wrapper class , & it didnot work ;

https://docs.oracle.com/javase/7/docs/api/

I’m not going to google it for you but surely out of the millions of Java developers writing things for android… at least one person has solved this problem.

Lately I’ve been dealing with this particular assertion a lot! There are many potential root causes, and it’s not easy to trace back the failure back to the root cause. For instance, see jme-vehicles issue 1.

Here’s how I’ve been approaching it:

  1. Build the “jme3-core” library locally and install it to MavenLocal. Then build your application using the local version:
dependencies {
    implementation('org.jmonkeyengine:jme3-core') {
        version {
            strictly '3.3.2-SNAPSHOT'
        }
    }
  1. Starting from the assertion, add tests for invalid values, and set breakpoints to occur if such values are found, like so:
        if (!Vector3f.isValidVector(center)) {
            System.out.print(""); // set breakpoint here
        }
  1. Using a debugger, work backward until you find where the invalid value originated.
2 Likes

It’s likely to be the same exact error above , it’s reflected on the update(…tpf) too .

Okay I will try !

Thanks :+1:

1 Like

Hi ,
i have traced the problem using :

Arrays.toString(e.getStackTrace()); 

& i got an array of log errors showing that the problem lies with DLSR(DirectionalLightShadowRenderer) :


[com.jme3.bounding.Intersection.intersect(Intersection.java:67), com.jme3.bounding.BoundingSphere.intersectsBoundingBox(BoundingSphere.java:683), com.jme3.bounding.BoundingBox.intersects(BoundingBox.java:595), com.jme3.shadow.ShadowUtil$OccludersExtractor.process(ShadowUtil.java:428), com.jme3.shadow.ShadowUtil$OccludersExtractor.addOccluders(ShadowUtil.java:368), com.jme3.shadow.ShadowUtil.updateShadowCamera(ShadowUtil.java:501), com.jme3.shadow.DirectionalLightShadowRenderer.getOccludersToRender(DirectionalLightShadowRenderer.java:194), com.jme3.shadow.AbstractShadowRenderer.renderShadowMap(AbstractShadowRenderer.java:427), com.jme3.shadow.AbstractShadowRenderer.postQueue(AbstractShadowRenderer.java:412), com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:1103), com.jme3.renderer.RenderManager.render(RenderManager.java:1158), com.jme3.app.SimpleApplication.update(SimpleApplication.java:272), com.scrappers.superiorExtendedEngine.jmeSurfaceView.JmESurfaceView.update(JmESurfaceView.java:196), com.jme3.system.android.OGLESContext.onDrawFrame(OGLESContext.java:348), android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1571), android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1270)]


So, when i have my DLSR block commented , AssertionError Resolves :
this is my DLSR code , may be there’s a wrong value , but i cannot find it, if it’s not the problem , then can it be the DirectionalLight problem ? :

        DirectionalLightShadowRenderer dlsr=new DirectionalLightShadowRenderer(assetManager,512,1);
        dlsr.setLight(directionalLight);
        dlsr.setShadowIntensity(0.2f);
        dlsr.setLambda(0.55f);
        dlsr.setShadowCompareMode(CompareMode.Hardware);
        dlsr.setShadowZExtend(23f);
        dlsr.setShadowZFadeLength(8f);
        floorGeometry.setShadowMode(RenderQueue.ShadowMode.Receive);
        viewPort.addProcessor(dlsr);

The code is taking the shadow volume and trying to intersect it with the objects in your scene.

Of the set of “shadow volume” and “all objects in your scene”… which do you think is more likely to have a bad bounding volume?

If you can add some logging there, I think you will know.

Edit: that being said, I think you described a weird setup and maybe the camera is not valid at some point where this is called… so it really could be that the shadow volume cannot be calculated because the camera setup is junk at the time of the call.

2 Likes

Doing a subsurface division modification in blender to the terrain may have caused overlapped faces which cannot intersect correctly with the shadow volume , would overlapped faces be really the cause ?!, I can relate only if I have replaced the terrain with anything tested before.

eom.

1 Like

I disabled the assertion through in gradle :

//runtime
tasks.withType(JavaExec){
    enableAssertions false
}

Source :

It may not be the real fix for this problem , but at least i know how to disable/enable assertions , thanks @pspeed & @sgold , & i will try to trace the problem as well to understand what’s wrong with my code.

1 Like