[SOLVED] NiftyGUI - Some controls have bad rendering in android having batch enabled

Hi,

If using niftygui batch rendering in android some controls (like buttons and dropdowns) are not rendered correctly. Their background images are not show at all as shown in the following screenshot:

Imgur

BtnTest is supposed to be a button, the “Pre-scroll” is a label and then there should be a dropdown control. If creating the nifty display as previous default:

    niftyDisplay = new NiftyJmeDisplay(
            assetManager,
            inputManager,
            audioRenderer,
            guiViewPort);

The controls are properly rendered:

Imgur

I noticed that some images in nifty default style were not RGBA like most of them:

$ find . | grep png | xargs file | grep -v RGBA
./button/button.png:                    PNG image data, 100 x 69, 8-bit/color RGB, non-interlaced
./imageselect/background-focus.png:     PNG image data, 23 x 80, 8-bit/color RGB, non-interlaced
./imageselect/background-hover.png:     PNG image data, 23 x 80, 8-bit/color RGB, non-interlaced
./imageselect/background.png:           PNG image data, 23 x 80, 8-bit/color RGB, non-interlaced
./tabs/tab-background-border.png:       PNG image data, 3 x 3, 8-bit gray+alpha, non-interlaced
./tabs/tabs.png:                        PNG image data, 93 x 23, 8-bit colormap, non-interlaced

In fact, all those were failing rendering in my tests, so I converted them all to RGBA inside my project and created a new style file to overwrite them as follows:

<?xml version="1.0" encoding="UTF-8"?>
<nifty-styles xmlns="http://nifty-gui.lessvoid.com/nifty-gui">

    <!-- +++++++++++++++++++++++++++++++++++++ -->
    <!-- style for the button background panel -->
    <!-- +++++++++++++++++++++++++++++++++++++ -->
    <style id="nifty-button#panel">
        <attributes backgroundImage="nifty-override/button.png" imageMode="sprite-resize:100,23,0,2,96,2,2,2,96,2,19,2,96,2,2"
                    paddingLeft="7px" paddingRight="7px" width="120px" height="28px" childLayout="center"
                    visibleToMouse="true"/>
        <effect>
            <onHover name="border" color="#822f" post="true"/>
            <onFocus name="imageOverlay" filename="nifty-override/button.png"
                     imageMode="sprite-resize:100,23,1,2,96,2,2,2,96,2,19,2,96,2,2" post="true"/>
            <onEnabled name="renderQuad" startColor="#2228" endColor="#2220" post="true" length="150"/>
            <onDisabled name="renderQuad" startColor="#2220" endColor="#2228" post="true" length="150"/>
        </effect>
    </style>

    <!-- +++++++++++++++++++++++++++++++++++++ -->
    <!-- style for the button text -->
    <!-- +++++++++++++++++++++++++++++++++++++ -->
    <style id="nifty-button#text" base="button-font">
        <attributes align="center" valign="center" textHAlign="center" textVAlign="center" visibleToMouse="false"/>
        <effect>
            <onEnabled name="textColorAnimated" startColor="#8886" endColor="#eeef" post="false" length="150"/>
            <onDisabled name="textColorAnimated" startColor="#eeef" endColor="#8886" post="false" length="150"/>
        </effect>
    </style>

    <style id="nifty-image-select#back-button">
        <attributes backgroundImage="nifty-override/background.png" imageMode="resize:2,19,2,2,2,19,2,76,2,19,2,2"
                    width="23px" height="100%" childLayout="center"/>
        <interact onClick="backClick()"/>
        <effect>
            <onClick name="focus" targetElement="#parent"/>
            <onFocus name="imageOverlay" filename="nifty-override/background-focus.png"
                     imageMode="resize:2,19,2,2,2,19,2,76,2,19,2,2" post="true"/>
        </effect>
    </style>

    <style id="nifty-image-select#forward-button">
        <attributes backgroundImage="nifty-override/background.png" imageMode="resize:2,19,2,2,2,19,2,76,2,19,2,2"
                    width="23px" height="100%" childLayout="center"/>
        <interact onClick="forwardClick()"/>
        <effect>
            <onClick name="focus" targetElement="#parent"/>
            <onFocus name="imageOverlay" filename="nifty-override/background-focus.png"
                     imageMode="resize:2,19,2,2,2,19,2,76,2,19,2,2" post="true"/>
        </effect>
    </style>

    <!-- This style is applied to the panel that holds the button -->
    <style id="nifty-tabs#tab-button-panel">
        <attributes width="100%" backgroundImage="nifty-override/tab-background-border.png"
                    imageMode="resize:0,3,0,0,0,3,0,2,0,3,0,1"/>
    </style>

    <style id="nifty-tab-button">
        <attributes backgroundImage="nifty-override/tabs.png"
                    imageMode="sprite-resize:31,23,2,15,1,15,11,15,1,15,1,15,1,15,11" paddingLeft="11px"
                    paddingRight="11px" width="100px" height="23px" childLayout="center" visibleToMouse="true"/>
        <effect>
            <onHover name="imageOverlay" filename="nifty-override/tabs.png"
                     imageMode="sprite-resize:31,23,1,15,1,15,11,15,1,15,1,15,1,15,11" post="true"/>
        </effect>
    </style>

    <!-- The style of a tab button that is the activated one. -->
    <style id="nifty-tab-button-active">
        <attributes backgroundImage="nifty-override/tabs.png"
                    imageMode="sprite-resize:31,23,0,15,1,15,11,15,1,15,1,15,1,15,11" paddingLeft="11px"
                    paddingRight="11px" width="100px" height="23px" childLayout="center" visibleToMouse="true"/>
        <effect>
            <!-- weiss noch net :)
           <onHover name="imageOverlay" filename="nifty-override/tabs.png"
                    imageMode="sprite-resize:31,23,0,15,1,15,11,15,1,15,1,15,1,15,11" post="true"/>
            -->
        </effect>
    </style>

</nifty-styles>

And in my nifty xml file I included it just after the default styles:

<useStyles filename="nifty-default-styles.xml" />
<useStyles filename="nifty-style-override.xml" />
<useControls filename="nifty-default-controls.xml" />

So all controls are fixed except the dropdown that keeps failing and I don’t understand why

Imgur

Side note… desktop renders properly always even using batched mode

Any ideas?

Thanks

1 Like

I don’t know much about Android, but I do know that Desktop loads PNG texture assets using Java’s Abstract Window Toolkit (AWT):

https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-desktop/src/main/java/com/jme3/texture/plugins/AWTLoader.java#L179

Android appears to use BitmapFactory:

https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidBufferImageLoader.java#L88

I hope that helps.

Thanks for the comment @sgold I started debugging my project checking the AndroidBufferImageLoader class but it was really the AndroidNativeImageLoader the one loading the images. Then I realized the file “de/lessvoid/nifty/render/batch/nifty.png” was being loaded whe using batch rendering for no reason, it was not defined in any style or anywhere in my code. Finally I found it at de/lessvoid/nifty/render/batch/BatchRenderDevice.java:565

  @Nonnull
  private BatchRenderImage getPlainImage() {
    if (thePlainImage == null) {
      thePlainImage = (BatchRenderImage) createImage("de/lessvoid/nifty/render/batch/nifty.png", true);
      if (thePlainImage == null) {
        throw new RuntimeException("The batch renderer requires the plain image in the resources, but its not there.");
      }
    }
    uploadImageInternal(thePlainImage);
    return thePlainImage;
  }

That image is rgb si it’s the same issue as the other but as it’s in nifty code I cannot override it with styles like I was doing with the other. I changed it in nifty, recompiled it, tried the app and it works same way it does in desktop.

I’ll propose to change the file formats directly in nifty (although this will still be an issue for prople having their own styles and files not in rgba format using batch in android) unless I find a way to solve this in the jme3 side.

1 Like

More information, it’s the call to glTexSubImage2D because internal format of the atlas and the format of the texture to add don’t match:

From: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexSubImage2D.xhtml

GL_INVALID_OPERATION is generated if the combination of internalFormat of the previously specified texture array, format and type is not valid. See glTexImage2D.

This issue will happen to any other usage of Renderer.modifyTexure being run in GLES devices

Maybe we could Include code in GLRenderer.modifyTexture that checks if it’s running GLES and convert the image to the format of the atlas in which it’ll be included

What do you think?

1 Like

Just created a PR to fix this. Maybe not my best code but fully working for the cases I found the issue --> https://github.com/jMonkeyEngine/jmonkeyengine/pull/1235

1 Like