Trying to extend Lemur's BackgroundComponent has run into some problems

/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package GUI;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.math.Vector4f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.image.ImageRaster;
import com.jme3.texture.Image;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.core.GuiMaterial;
import com.simsilica.lemur.core.VersionedReference;
import java.nio.FloatBuffer;


/**
 * 裁剪处理UI的PNG图像
 * @author Icyboxs
 */
public final class LemurQuadBackgroundComponentEnhanced extends QuadBackgroundComponent{
    private Geometry background;
    private ColorRGBA color;
    private float alpha = 1f;
    private Texture texture;
    private Vector2f textureCoordinateScale;
    private GuiMaterial material;
    private float xMargin = 0;
    private float yMargin = 0;
    private float zOffset = 0.01f;
    private float alphaDiscard = 0;
    private boolean lit = false;
    private Vector2f tiling= new Vector2f();
    private Vector2f offset= new Vector2f();
    private Vector2f Resolution= new Vector2f();

    private imgResolutionData resolutionData = new imgResolutionData(); // 初始化 resolutionData;
    
    private Vector2f appliedTextureScale = new Vector2f(1, 1);
    public LemurQuadBackgroundComponentEnhanced() {
        this(ColorRGBA.Gray, 0, 0, 0.01f, false);
    }

    public LemurQuadBackgroundComponentEnhanced( ColorRGBA color ) {
        this(color, 0, 0, 0.01f, false);
    }

    public LemurQuadBackgroundComponentEnhanced( ColorRGBA color, float xMargin, float yMargin ) {
        this(color, xMargin, yMargin, 0.01f, false);
    }

    public LemurQuadBackgroundComponentEnhanced( ColorRGBA color,
                                    float xMargin, float yMargin, float zOffset,
                                    boolean lit ) {
        this.xMargin = xMargin;
        this.yMargin = yMargin;
        this.zOffset = zOffset;
        this.lit = lit;
        setColor(color);
        createMaterial();
    }

    public LemurQuadBackgroundComponentEnhanced( Texture texture ) {
        this(texture, 0, 0, 0.01f, false);
    }

    public LemurQuadBackgroundComponentEnhanced( Texture texture, float xMargin, float yMargin ) {
        this(texture, xMargin, yMargin, 0.01f, false);
    }

    public LemurQuadBackgroundComponentEnhanced( Texture texture,
                                    float xMargin, float yMargin, float zOffset,
                                    boolean lit ) {
        this.xMargin = xMargin;
        this.yMargin = yMargin;
        this.zOffset = zOffset;
        this.lit = lit;
        setTexture(texture);
        setColor(ColorRGBA.White);
        createMaterial();
    }
        public LemurQuadBackgroundComponentEnhanced( Texture texture,
                                    float xMargin, float yMargin, float zOffset,
                                    boolean lit,
                                    int xResolution,int yResolution,
                                    int xCropResolution,int yCropResolution,
                                    int xOffsetResolution,int yOffsetResolution) {

        this.resolutionData.setxResolution(xResolution);
        this.resolutionData.setyResolution(yResolution);
        this.resolutionData.setxCropResolution(xCropResolution);
        this.resolutionData.setyCropResolution(yCropResolution);
        this.resolutionData.setxOffsetResolution(xOffsetResolution);
        this.resolutionData.setyOffsetResolution(yOffsetResolution);
        this.xMargin = xMargin;
        this.yMargin = yMargin;
        this.zOffset = zOffset;
        this.lit = lit;
        setTexture(texture);
        setColor(ColorRGBA.White);
        createMaterial();
    }
    public LemurQuadBackgroundComponentEnhanced( Texture texture,
                                    float xMargin, float yMargin, float zOffset,
                                    boolean lit ,imgResolutionData IRD) {
        this.resolutionData=IRD;
        this.xMargin = xMargin;
        this.yMargin = yMargin;
        this.zOffset = zOffset;
        this.lit = lit;
        setTexture(texture);
        setColor(ColorRGBA.White);
        createMaterial();
    }
    
    @Override
    protected void refreshBackground( Vector3f size ) {
        if( background == null ) {
            Quad q = new Quad(size.x, size.y);
            if( lit ) {
                // Give the quad some normals
                q.setBuffer(VertexBuffer.Type.Normal, 3,
                            new float[] {
                                        0, 0, 1,
                                        0, 0, 1,
                                        0, 0, 1,
                                        0, 0, 1
                            });
            }
            background = new Geometry("background", q);
            // Can't do this even though it seems logical because it
            // is just as likely that we are in bucket.gui.  It is up to
            // the caller to put the main 3D ui in the transparent bucket
            //background.setQueueBucket(Bucket.Transparent);
            if( material == null ) {
                createMaterial();
            }
             background.setMaterial(material.getMaterial());
            refreshMesh(background,resolutionData);
           
            
            getNode().attachChild(background);

            // If we've recreated the spatial then the applied scale
            // should be reset also.  We could either move slightly different
            // scaling logic into the branch and the else branch... or just
            // reset appliedTextureScale here so that the if branch below
            // rescales things properly.
            appliedTextureScale.set(1, 1);
        } else {
            // Else reset the size of the quad
            Quad q = (Quad)background.getMesh();
            if( size.x != q.getWidth() || size.y != q.getHeight() ) {
                q.updateGeometry(size.x, size.y);
                q.clearCollisionData();
            }
        }

        Vector2f effectiveScale = textureCoordinateScale == null ? Vector2f.UNIT_XY : textureCoordinateScale;
        if( !appliedTextureScale.equals(effectiveScale) ) {

            // Need to apply new texture coordinate scaling
            Mesh m = background.getMesh();
            
            // Unscale what we already scaled
            m.scaleTextureCoordinates(new Vector2f(1/appliedTextureScale.x, 1/appliedTextureScale.y));

            appliedTextureScale.set(effectiveScale);

            // And now apply the latest coordinate scaling.
            m.scaleTextureCoordinates(appliedTextureScale);
            
        
          
           
   
            // Note: it's probably safer to have just applied the scale value directly to
            // the quad's texture coordinate values instead of multiplying.  The above may
            // accumulate errors.  Still, I thought this would be more future proof and
            // transferable to other things since it works with any mesh and not just quads.
        }
        
         
    }
    
 
        private void refreshMesh(Geometry geom,imgResolutionData resolutionData) {
        this.tiling.x=resolutionData.getxCropResolution()/resolutionData.getxResolution();
        this.tiling.y=resolutionData.getyCropResolution()/resolutionData.getyResolution();
        this.offset.x=resolutionData.getxOffsetResolution()/resolutionData.getxResolution();
        this.offset.y=resolutionData.getyOffsetResolution()/resolutionData.getyResolution();
            
        Quad mesh = (Quad) geom.getMesh();
        VertexBuffer tc = mesh.getBuffer(VertexBuffer.Type.TexCoord);

        float[] uv = new float[]{
                0, 0,
                1, 0,
                1, 1,
                0, 1};

        FloatBuffer fb = (FloatBuffer) tc.getData();
        fb.clear();
        for (int i = 0; i < uv.length; i += 2) {
            
            System.err.println("L:"+i);
            float x = uv[i];
            float y = uv[i + 1];
            x = x * tiling.getX() + offset.getX();
            y = y * tiling.getY() + offset.getY();
            fb.put(x).put(y);
        }
        fb.clear();
        tc.updateData(fb);

    }
        
    public void  setimgResolutionData(int xResolution,int yResolution,int xCropResolution,int yCropResolution,int xOffsetResolution,int yOffsetResolution) {
        this.resolutionData.setxResolution(xResolution);
        this.resolutionData.setyResolution(yResolution);
        this.resolutionData.setxCropResolution(xCropResolution);
        this.resolutionData.setyCropResolution(yCropResolution);
        this.resolutionData.setxOffsetResolution(xOffsetResolution);
        this.resolutionData.setyOffsetResolution(yOffsetResolution);
    
    }
    @Override
        protected void createMaterial() {
        material = GuiGlobals.getInstance().createMaterial(color, lit);
        if( texture != null ) {
            material.setTexture(texture);
        }
        material.getMaterial().getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
        material.getMaterial().setFloat("AlphaDiscardThreshold", alphaDiscard);
    }

    
    @Override
    public QuadBackgroundComponent clone() {
        LemurQuadBackgroundComponentEnhanced result = (LemurQuadBackgroundComponentEnhanced)super.clone();
        result.material = material.clone();
        result.background = null;
        return result;
    }
        
}


import com.simsilica.lemur.*;
import com.simsilica.lemur.Button.ButtonAction;
import com.simsilica.lemur.component.*;
import GUI.*;
def gradient = TbtQuadBackgroundComponent.create( 
                                        texture( name:"/com/simsilica/lemur/icons/bordered-gradient.png", 
                                                 generateMips:false ),
                                                 1, 1, 1, 126, 126,
                                                 1f, false );

def bevel = TbtQuadBackgroundComponent.create( 
                                        texture( name:"/com/simsilica/lemur/icons/bevel-quad.png", 
                                                 generateMips:false ),
                                                 0.125f, 8, 8, 119, 119,
                                                 1f, false );
 
def border = TbtQuadBackgroundComponent.create(
                                        texture( name:"/com/simsilica/lemur/icons/border.png", 
                                                 generateMips:false ),
                                                 1, 1, 1, 6, 6,
                                                 1f, false );
def border2 = TbtQuadBackgroundComponent.create(
                                        texture( name:"/com/simsilica/lemur/icons/border.png", 
                                                 generateMips:false ),
                                                 1, 2, 2, 6, 6,
                                                 1f, false );
 
def doubleGradient = new QuadBackgroundComponent( color(0.5, 0.75, 0.85, 0.5) );  
doubleGradient.texture = texture( name:"/com/simsilica/lemur/icons/double-gradient-128.png", 
                                  generateMips:false )
                                  
selector( "myglass" ) {
    fontSize = 14
}
 
selector( "label", "myglass" ) {
    insets = new Insets3f( 2, 2, 0, 2 );
    color = color(0.5, 0.75, 0.75, 0.85)     
}

selector( "container", "myglass" ) {
    background = gradient.clone()
    background.setColor(color(0.25, 0.5, 0.5, 0.5))
}

selector( "slider", "myglass" ) {
    background = gradient.clone()
    background.setColor(color(0.25, 0.5, 0.5, 0.5))
} 

def pressedCommand = new Command<Button>() {
        public void execute( Button source ) {
            if( source.isPressed() ) {
                source.move(1, -1, 0);
            } else {
                source.move(-1, 1, 0);
            }
        }       
    };
    
def repeatCommand = new Command<Button>() {
        private long startTime;
        private long lastClick;
        
        public void execute( Button source ) {
            // Only do the repeating click while the mouse is
            // over the button (and pressed of course)
            if( source.isPressed() && source.isHighlightOn() ) {
                long elapsedTime = System.currentTimeMillis() - startTime;
                // After half a second pause, click 8 times a second
                if( elapsedTime > 500 ) {
                    if( elapsedTime - lastClick > 125 ) {  
                        source.click();
                        
                        // Try to quantize the last click time to prevent drift
                        lastClick = ((elapsedTime - 500) / 125) * 125 + 500;
                    }
                } 
            } else {
                startTime = System.currentTimeMillis();
                lastClick = 0;
            }
        }       
    };     
    
def stdButtonCommands = [
        (ButtonAction.Down):[pressedCommand], 
        (ButtonAction.Up):[pressedCommand]
    ];

def sliderButtonCommands = [
        (ButtonAction.Hover):[repeatCommand]
    ];

selector( "title", "myglass" ) {
    color = color(0.8, 0.9, 1, 0.85f)
    highlightColor = color(1, 0.8, 1, 0.85f)
    shadowColor = color(0, 0, 0, 0.75f)
    shadowOffset = new com.jme3.math.Vector3f(2, -2, -1);
    background = new QuadBackgroundComponent( color(0.5, 0.75, 0.85, 0.5) );
    background.texture = texture( name:"/com/simsilica/lemur/icons/double-gradient-128.png", 
                                  generateMips:false )
    insets = new Insets3f( 2, 2, 2, 2 );
    
    buttonCommands = stdButtonCommands;
}


selector( "button", "myglass" ) {
    background = new LemurQuadBackgroundComponentEnhanced( color(0.5, 0.75, 0.85, 0.5) );
    background.texture = texture( name:"/Textures/UI/Steampunk_UI_Alternative_Colors_1.png", 
                                  generateMips:false )                         
    background.setimgResolutionData(1920,1080,574,230,28,551)
    color = color(0.8, 0.9, 1, 0.85f)
    background.setColor(color(0, 0.75, 0.75, 0.5))
    insets = new Insets3f( 2, 2, 2, 2 );
    
    buttonCommands = stdButtonCommands;
}

selector( "slider", "myglass" ) {
    insets = new Insets3f( 1, 3, 1, 2 );    
}

selector( "slider", "button", "myglass" ) {
    background = doubleGradient.clone()
    background.setColor(color(0.5, 0.75, 0.75, 0.5))
    insets = new Insets3f( 0, 0, 0, 0 );
}

selector( "slider.thumb.button", "myglass" ) {
    text = "[]"
    color = color(0.6, 0.8, 0.8, 0.85)     
}

selector( "slider.left.button", "myglass" ) {
    text = "-"
    background = doubleGradient.clone()
    background.setColor(color(0.5, 0.75, 0.75, 0.5))
    background.setMargin(5, 0);
    color = color(0.6, 0.8, 0.8, 0.85)
         
    buttonCommands = sliderButtonCommands;
}

selector( "slider.right.button", "myglass" ) {
    text = "+"
    background = doubleGradient.clone()
    background.setColor(color(0.5, 0.75, 0.75, 0.5))
    background.setMargin(4, 0);
    color = color(0.6, 0.8, 0.8, 0.85)
         
    buttonCommands = sliderButtonCommands;
}

selector( "slider.up.button", "myglass" ) {
    buttonCommands = sliderButtonCommands;
}

selector( "slider.down.button", "myglass" ) {
    buttonCommands = sliderButtonCommands;
}

selector( "checkbox", "myglass" ) {
    def on = new IconComponent( "/com/simsilica/lemur/icons/Glass-check-on.png", 1f,
                                 0, 0, 1f, false );
    on.setColor(color(0.5, 0.9, 0.9, 0.9))
    on.setMargin(5, 0);
    def off = new IconComponent( "/com/simsilica/lemur/icons/Glass-check-off.png", 1f,
                                 0, 0, 1f, false );
    off.setColor(color(0.6, 0.8, 0.8, 0.8))
    off.setMargin(5, 0);
    
    onView = on;
    offView = off;    

    color = color(0.8, 0.9, 1, 0.85f)
}

selector( "rollup", "myglass" ) {
    background = gradient.clone()  
    background.setColor(color(0.25, 0.5, 0.5, 0.5))
}

selector( "tabbedPanel", "myglass" ) {
    activationColor = color(0.8, 0.9, 1, 0.85f)
}

selector( "tabbedPanel.container", "myglass" ) {
    background = null
}

selector( "tab.button", "myglass" ) {
    background = gradient.clone()
    background.setColor(color(0.25, 0.5, 0.5, 0.5))
    color = color(0.4, 0.45, 0.5, 0.85f)
    insets = new Insets3f( 4, 2, 0, 2 );
    
    buttonCommands = stdButtonCommands;
}



严重: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.NullPointerException: Cannot invoke "com.simsilica.lemur.core.GuiMaterial.clone()" because "this.material" is null
	at com.simsilica.lemur.component.QuadBackgroundComponent.clone(QuadBackgroundComponent.java:117)
	at GUI.LemurQuadBackgroundComponentEnhanced.clone(LemurQuadBackgroundComponentEnhanced.java:249)
	at GUI.LemurQuadBackgroundComponentEnhanced.clone(LemurQuadBackgroundComponentEnhanced.java:30)
	at com.simsilica.lemur.style.Styles.clone(Styles.java:520)
	at com.simsilica.lemur.style.Styles.applyStyles(Styles.java:470)
	at com.simsilica.lemur.Button.<init>(Button.java:129)
	at com.simsilica.lemur.Button.<init>(Button.java:105)
	at GUI.UI.onEnable(UI.java:86)
	at com.jme3.app.state.BaseAppState.initialize(BaseAppState.java:132)
	at com.jme3.app.state.AppStateManager.initializePending(AppStateManager.java:332)
	at com.jme3.app.state.AppStateManager.update(AppStateManager.java:362)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:258)
	at com.jme3.system.lwjgl.LwjglWindow.runLoop(LwjglWindow.java:628)
	at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:717)
	at java.base/java.lang.Thread.run(Thread.java:833)

·Cannot invoke “com.simsilica.lemur.core.GuiMaterial.clone()” because “this.material” is null·

I don’t quite understand why this value is empty.

I think the issue is with this line.

LemurQuadBackgroundComponentEnhanced result = (LemurQuadBackgroundComponentEnhanced)super.clone();

because here you are calling public QuadBackgroundComponent clone() of the parent class and it has its own private material that is null and wants to clone it.

Looking at your code I think it’s better to have your class declared like

public class LemurQuadBackgroundComponentEnhanced extends AbstractGuiComponent
                                     implements Cloneable, ColoredComponent {

and do what you need to do. It will not extend QuadBackgroundComponent but will be similar and enhanced as you want it to be.

1 Like

Thanks for the quick reply and tips!
I’ll give it a try. :+1:

Yes, exactly right. This was my suggestion in the other thread because some of the components classes are not as extensible as they should be.

For reference:

From: Questions about image cropping and image loading - #4 by pspeed

“Fork” means “copy the source code and change it”. Not “extend”.

2 Likes

I think I may have misunderstood you. :sweat:

hi~ pspeed
After some painful attempts, I need some help from you if you have the time.

/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package GUI;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.math.Vector4f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.image.ImageRaster;
import com.jme3.texture.Image;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.component.AbstractGuiComponent;
import com.simsilica.lemur.component.ColoredComponent;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.core.GuiControl;
import com.simsilica.lemur.core.GuiMaterial;
import com.simsilica.lemur.core.VersionedReference;
import java.nio.FloatBuffer;


/**
 * 裁剪处理UI的PNG图像
 * @author Icyboxs
 */
public final class LemurQuadBackgroundComponentEnhanced extends AbstractGuiComponent
                                     implements Cloneable, ColoredComponent {
    private Geometry background;
    private ColorRGBA color;
    private float alpha = 1f;
    private Texture texture;
    private Vector2f textureCoordinateScale;
    private GuiMaterial material;
    private float xMargin = 0;
    private float yMargin = 0;
    private float zOffset = 0.01f;
    private float alphaDiscard = 0;
    private boolean lit = false;
    private Vector2f tiling= new Vector2f();
    private Vector2f offset= new Vector2f();
    private Vector2f Resolution= new Vector2f();

    private imgResolutionData resolutionData = new imgResolutionData(); // 初始化 resolutionData;
    
    private Vector2f appliedTextureScale = new Vector2f(1, 1);
    public LemurQuadBackgroundComponentEnhanced() {
        this(ColorRGBA.Gray, 0, 0, 0.01f, false);
    }

    public LemurQuadBackgroundComponentEnhanced( ColorRGBA color ) {
        this(color, 0, 0, 0.01f, false);
    }

    public LemurQuadBackgroundComponentEnhanced( ColorRGBA color, float xMargin, float yMargin ) {
        this(color, xMargin, yMargin, 0.01f, false);
    }

    public LemurQuadBackgroundComponentEnhanced( ColorRGBA color,
                                    float xMargin, float yMargin, float zOffset,
                                    boolean lit ) {
        this.xMargin = xMargin;
        this.yMargin = yMargin;
        this.zOffset = zOffset;
        this.lit = lit;
        setColor(color);
        createMaterial();
    }

    public LemurQuadBackgroundComponentEnhanced( Texture texture ) {
        this(texture, 0, 0, 0.01f, false);
    }

    public LemurQuadBackgroundComponentEnhanced( Texture texture, float xMargin, float yMargin ) {
        this(texture, xMargin, yMargin, 0.01f, false);
    }

    public LemurQuadBackgroundComponentEnhanced( Texture texture,
                                    float xMargin, float yMargin, float zOffset,
                                    boolean lit ) {
        this.xMargin = xMargin;
        this.yMargin = yMargin;
        this.zOffset = zOffset;
        this.lit = lit;
        setTexture(texture);
        setColor(ColorRGBA.White);
        createMaterial();
    }
        public LemurQuadBackgroundComponentEnhanced( Texture texture,
                                    float xMargin, float yMargin, float zOffset,
                                    boolean lit,
                                    int xResolution,int yResolution,
                                    int xCropResolution,int yCropResolution,
                                    int xOffsetResolution,int yOffsetResolution) {

        this.resolutionData.setxResolution(xResolution);
        this.resolutionData.setyResolution(yResolution);
        this.resolutionData.setxCropResolution(xCropResolution);
        this.resolutionData.setyCropResolution(yCropResolution);
        this.resolutionData.setxOffsetResolution(xOffsetResolution);
        this.resolutionData.setyOffsetResolution(yOffsetResolution);
        this.xMargin = xMargin;
        this.yMargin = yMargin;
        this.zOffset = zOffset;
        this.lit = lit;
        setTexture(texture);
        setColor(ColorRGBA.White);
        createMaterial();
    }
    public LemurQuadBackgroundComponentEnhanced( Texture texture,
                                    float xMargin, float yMargin, float zOffset,
                                    boolean lit ,imgResolutionData IRD) {
        this.resolutionData=IRD;
        this.xMargin = xMargin;
        this.yMargin = yMargin;
        this.zOffset = zOffset;
        this.lit = lit;
        setTexture(texture);
        setColor(ColorRGBA.White);
        createMaterial();
    }
    
    
    protected void refreshBackground( Vector3f size ) {
        if( background == null ) {
            Quad q = new Quad(size.x, size.y);
            if( lit ) {
                // Give the quad some normals
                q.setBuffer(VertexBuffer.Type.Normal, 3,
                            new float[] {
                                        0, 0, 1,
                                        0, 0, 1,
                                        0, 0, 1,
                                        0, 0, 1
                            });
            }

//        VertexBuffer tc = q.getBuffer(VertexBuffer.Type.TexCoord);
//        float[] uv = new float[]{
//                0, 0,
//                1, 0,
//                1, 1,
//                0, 1};
//
//        FloatBuffer fb = (FloatBuffer) tc.getData();
//        fb.clear();
//        for (int i = 0; i < uv.length; i += 2) {
//            
//            System.err.println("L:"+i);
//            float x = uv[i];
//            float y = uv[i + 1];
//            x = x * tiling.getX() + offset.getX();
//            y = y * tiling.getY() + offset.getY();
//            fb.put(x).put(y);
//        }
//        fb.clear();
//        tc.updateData(fb);

            background = new Geometry("background", q);
            // Can't do this even though it seems logical because it
            // is just as likely that we are in bucket.gui.  It is up to
            // the caller to put the main 3D ui in the transparent bucket
            //background.setQueueBucket(Bucket.Transparent);
            if( material == null ) {
                createMaterial();
            }
             background.setMaterial(material.getMaterial());
            
           
            
            getNode().attachChild(background);
           
            // If we've recreated the spatial then the applied scale
            // should be reset also.  We could either move slightly different
            // scaling logic into the branch and the else branch... or just
            // reset appliedTextureScale here so that the if branch below
            // rescales things properly.
            appliedTextureScale.set(1, 1);
        } else {
            // Else reset the size of the quad
            Quad q = (Quad)background.getMesh();
            if( size.x != q.getWidth() || size.y != q.getHeight() ) {
                q.updateGeometry(size.x, size.y);
                q.clearCollisionData();
            }
        }

        Vector2f effectiveScale = textureCoordinateScale == null ? Vector2f.UNIT_XY : textureCoordinateScale;
        if( !appliedTextureScale.equals(effectiveScale) ) {

            // Need to apply new texture coordinate scaling
            Mesh m = background.getMesh();
            
            // Unscale what we already scaled
            m.scaleTextureCoordinates(new Vector2f(1/appliedTextureScale.x, 1/appliedTextureScale.y));

            appliedTextureScale.set(effectiveScale);

            // And now apply the latest coordinate scaling.
            m.scaleTextureCoordinates(appliedTextureScale);
            
        
          
           
   
            // Note: it's probably safer to have just applied the scale value directly to
            // the quad's texture coordinate values instead of multiplying.  The above may
            // accumulate errors.  Still, I thought this would be more future proof and
            // transferable to other things since it works with any mesh and not just quads.
        }
         refreshMesh(background,resolutionData);
         
    }
    
 
    private void refreshMesh(Geometry geom,imgResolutionData resolutionData) {
        this.tiling.x=resolutionData.getxCropResolution()/resolutionData.getxResolution();
        this.tiling.y=resolutionData.getyCropResolution()/resolutionData.getyResolution();
        this.offset.x=resolutionData.getxOffsetResolution()/resolutionData.getxResolution();
        this.offset.y=resolutionData.getyOffsetResolution()/resolutionData.getyResolution();
           Mesh q=geom.getMesh();
        VertexBuffer tc = q.getBuffer(VertexBuffer.Type.TexCoord);
        float[] uv = new float[]{
                0, 0,
                1, 0,
                1, 1,
                0, 1};

        FloatBuffer fb = (FloatBuffer) tc.getData();
        fb.clear();
        for (int i = 0; i < uv.length; i += 2) {
            
            System.err.println("L:"+i);
            float x = uv[i];
            float y = uv[i + 1];
            x = x * tiling.getX() + offset.getX();
            y = y * tiling.getY() + offset.getY();
            fb.put(x).put(y);
        }
        fb.clear();
        tc.updateData(fb);


        
    }
        
    public void  setimgResolutionData(int xResolution,int yResolution,int xCropResolution,int yCropResolution,int xOffsetResolution,int yOffsetResolution) {
        this.resolutionData.setxResolution(xResolution);
        this.resolutionData.setyResolution(yResolution);
        this.resolutionData.setxCropResolution(xCropResolution);
        this.resolutionData.setyCropResolution(yCropResolution);
        this.resolutionData.setxOffsetResolution(xOffsetResolution);
        this.resolutionData.setyOffsetResolution(yOffsetResolution);
    
    }


    @Override
    public LemurQuadBackgroundComponentEnhanced clone() {
        LemurQuadBackgroundComponentEnhanced result = (LemurQuadBackgroundComponentEnhanced)super.clone();
        result.material = material.clone();
        result.background = null;
        return result;
    }
        @Override
    public void attach( GuiControl parent ) {
        super.attach(parent);
    }

    @Override
    public void detach( GuiControl parent ) {
        if( background != null ) {
            getNode().detachChild(background);
        }
        super.detach(parent);
    }

    @Override
    public void setColor( ColorRGBA c ) {
        this.color = c;
        resetColor();
    }

    protected void resetColor() {
        if( material == null ) {
            return;
        }
        if( alpha >= 1 ) {
            // Just set it directly
            material.setColor(color);
        } else {
            // Need to calculate it
            ColorRGBA adjusted = color != null ? color.clone() : ColorRGBA.White.clone();
            adjusted.a *= alpha;
            material.setColor(adjusted);
        }
    }

    @Override
    public ColorRGBA getColor() {
        return color;
    }

    @Override
    public void setAlpha( float f ) {
        if( this.alpha == f ) {
            return;
        }
        this.alpha = f;
        resetColor();
    }

    @Override
    public float getAlpha() {
        return alpha;
    }

    public void setTexture( Texture t ) {
        if( this.texture == t )
            return;
        this.texture = t;
        if( material != null ) {
            material.setTexture(texture);
        }
    }

    public Texture getTexture() {
        return texture;
    }

    public void setTextureCoordinateScale( Vector2f scale ) {
        this.textureCoordinateScale = scale;
    }

    public Vector2f getTextureCoordinateScale() {
        return textureCoordinateScale;
    }

    public void setMargin( float x, float y ) {
        this.xMargin = x;
        this.yMargin = y;

        invalidate();
    }

    public void setMargin( Vector2f margin ) {
        if( margin == null ) {
            throw new IllegalArgumentException("Margin cannot be null");
        }
        setMargin(margin.x, margin.y);
    }

    public Vector2f getMargin() {
        return new Vector2f(xMargin, yMargin);
    }

    public void setZOffset( float z ) {
        this.zOffset = z;
        invalidate();
    }

    public float getZOffset() {
        return zOffset;
    }

    /**
     *  Sets the alphaDiscardThreshold for the image material.  If an
     *  alpha value is below this threshold then it will be discarded
     *  rather than being written to the color and zbuffers.  Set to 0
     *  to disable.  Defaults to 0.
     *
     *  <p>Note: for 2D UIs this threshold is not necessary as 2D GUIs
     *  will always sort purely back-to-front on Z.  For 3D UIs, this
     *  setting may prevent visual artifacts from certain directions
     *  for very transparent pixels (background showing through, etc.))</p>
     */
    public void setAlphaDiscard( float alphaDiscard ) {
        if( this.alphaDiscard == alphaDiscard ) {
            return;
        }
        this.alphaDiscard = alphaDiscard;
        if( material != null ) {
            material.getMaterial().setFloat("AlphaDiscardThreshold", alphaDiscard);
        }
    }

    public float getAlphaDiscard() {
        return alphaDiscard;
    }

    public GuiMaterial getMaterial() {
        return material;
    }

    @Override
    public void calculatePreferredSize( Vector3f size ) {
        size.x += xMargin * 2;
        size.y += yMargin * 2;
        size.z += Math.abs(zOffset);
    }

    @Override
    public void reshape( Vector3f pos, Vector3f size ) {
        refreshBackground(size);

        background.setLocalTranslation(pos.x, pos.y - size.y, pos.z);
        pos.x += xMargin;
        pos.y -= yMargin;
        pos.z += zOffset;

        size.x -= xMargin * 2;
        size.y -= yMargin * 2;
        size.z -= Math.abs(zOffset);
    }
    protected void createMaterial() {
        material = GuiGlobals.getInstance().createMaterial(color, lit);
        if( texture != null ) {
            material.setTexture(texture);
        }
        material.getMaterial().getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
        material.getMaterial().setFloat("AlphaDiscardThreshold", alphaDiscard);
    }

}

    private void refreshMesh(Geometry geom,imgResolutionData resolutionData) {
        this.tiling.x=resolutionData.getxCropResolution()/resolutionData.getxResolution();
        this.tiling.y=resolutionData.getyCropResolution()/resolutionData.getyResolution();
        this.offset.x=resolutionData.getxOffsetResolution()/resolutionData.getxResolution();
        this.offset.y=resolutionData.getyOffsetResolution()/resolutionData.getyResolution();
           Mesh q=geom.getMesh();
        VertexBuffer tc = q.getBuffer(VertexBuffer.Type.TexCoord);
        float[] uv = new float[]{
                0, 0,
                1, 0,
                1, 1,
                0, 1};

        FloatBuffer fb = (FloatBuffer) tc.getData();
        fb.clear();
        for (int i = 0; i < uv.length; i += 2) {
            
            System.err.println("L:"+i);
            float x = uv[i];
            float y = uv[i + 1];
            x = x * tiling.getX() + offset.getX();
            y = y * tiling.getY() + offset.getY();
            fb.put(x).put(y);
        }
        fb.clear();
        tc.updateData(fb);
    }

I’m using the method refreshMesh to control the uv so that it only shows a portion of the whole image but after running it the buttons don’t show anything I don’t understand why this is maybe I’m missing something?
Let me know if you need more from me.

Probably you should step back and do something not so complicated.

Open QuadBackgroundComponent.
Ctrl-a to select all.
Ctrl-c to copy all.
Open a new file called MyQuadBackgroundComponent.
Ctrl-v to paste the source.
Search and replace QuadBackgroundComponent to QuadBackgroundComponent
Change the package to wherever you made the class.
Add a Vector2f field for uv1 that defaults to new Vector2f(0, 0);
Add a Vector2f field for uv2 that defaults to new Vector2f(1, 1);
Add setters/getters for those.
Make sure the setters call invalidate()
In refreshBackground() replace everything after:

Vector2f effectiveScale = textureCoordinateScale == null ? Vector2f.UNIT_XY : textureCoordinateScale;
if( !appliedTextureScale.equals(effectiveScale) ) {
...and so on...
...all the way to the end of the method

With:

background.getMesh().setBuffer(Type.TexCoord, 2,
                    new float[] {
                                uv1.x, uv1.y,
                                uv2.x, uv1.y,
                                uv2.x, uv2.y,
                                uv1.x, uv2.y
                    });
1 Like

Thanks for the quick reply I will try it later! :smiling_face_with_three_hearts:

1 Like

Well, I seem to have made the problem more complicated, thank you for providing valuable advice to quickly understand what I should do,

2 Likes