Best way to have a background panel?

Just getting my feet wet with running code… so forgive me if this is a FAQ.

I want a static background panel with a thin black outline (i.e. a one-pixel border or equivalent) and a background RGBA color.
I have seen Panel, but I suspect it’s using the style xml, i.e. it will always look as if it were draggable and irritate the user.

I just need a quick answer where to look first, to avoid spending too much time looking in the wrong places.

Have you tried passing custom defaultImage to constructor? This should take care about the borders look. Regarding RGBA color - I think it just uses image contents as base color (so you would need to prepare separate image for each color), but maybe one of the effects can colorize it?

Ah, I missed that constructor. Didn’t see what defaultImgPath would do on any wiki page.
Still doesn’t deal with the border line, unfortunately.

Rolling my own control would be an option, but I didn’t want to dive THAT deep into the lib with my first attempts :-/

If you check toneGod’s lib, you will find default images that are used for the windows, panels etc. Looking at them, it seems that the images are “stretched” (well, more complex than that) and so if you use an image with a border, you will end up with a border around your panels… if I’m not wrong, which is always very possible.

Sorry for the delay in response. My husband and I went on a small vacation.

Lets see.

Backgrounds:

Yes on using the constructor that passes in the border and imagePath. So, a 1 pixel bordered panel would be: (using an Element in the example)

Element el = new Element(screen, someUID, Vector2f.ZERO, new Vector2f(someWidth, someHeight), new Vector4f(1,1,1,1), “someImagePath”);

To alter the color… you could do the following:

el.getElementMaterial().setColor(“Color”, newColorRGBA(1,0,0,1));

That should blend red into the image.

As for rolling your own control… very simple process:

  1. Extend the control that is closest to what you want.
  2. Cut & paste the 3 constructors from that control into your new control and refactor the name.
  3. Make sure the final constuructor calls super
  4. Ad new child elements, alter existing control elements, add methods for functionality.
  5. Use your new control.

It reaaaaaalllllly is super simple to put together new controls.

1 Like

Wow. Awesome.
Thanks!

I think I’ll add that as an example to the wiki if you don’t mind.
It’s trivial enough to fit into a wiki page, yet shows the general process of making your own control.
And it would complement the existing example I think.

P.S.: Don’t worry about delays, any project should survive if its benevolent dictator isn’t available for a while :slight_smile:
(and I hope you had fun!)

1 Like

Sorry for the late report back, I was held up by a week of Gradle wrangling.

Now… it all works, except for a tiny thing: It doesn’t have the black border I’d like to have.
How should I proceed? I can live without the border, but it would look much better.

Here’s what I’m doing currently:
[java] @Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
// background panel
// centered, inset by windowMargins from outerWindow, background #0007
float screenW = screen.getWidth();
float screenH = screen.getHeight();
float w = screenW - 2f * padding;
float h = screenH - 2f * padding;
float x = padding;
float y = padding;
Element backgroundPanel = new Element(screen, newId(), // UID
new Vector2f(x, y), // position
new Vector2f(w, h), // dimensions
new Vector4f(1f, 1f, 1f, 1f), // resizeBorders
null); // texturePath
backgroundPanel.getElementMaterial().setColor(“Color”,
new ColorRGBA(0f, 0f, 0f, 0.1f));
backgroundPanel.setIgnoreMouse(true);
screen.addElement(backgroundPanel);
}
[/java]

You have a few options here.

  1. A small square 1 pixel border image (I would use this)
  2. use: element.getModel().setColorBuffer(); and pass in a custom (16 vert) FloatBuffer with the assigned vert colors.

P.S. If the background is supposed to cover the screen and you want to exclude it from the Z-reorder, use:

[java]
element.setGlobalModel(true); // Exclude from z-order reorder calls
element.move(0,0,-20); /// put the element WAY behind everything else
[/java]

Thanks :slight_smile:

Just some feedback and a few questions:

  1. I’m having trouble loading the one-pixel bitmap because I want to have it in the same classpath as the class that’s using it. AssetManager is more a problem than a solution when such requirements arise… ah well, I’ll get that sorted out on my own and move on.
  2. Is the GUI bucket always in front of the scene graph? -20.0f might already be farther away than in-scene spatials.
  3. I don’t see Element#setGlobalModel. Is that planned to be published? Is it an optimization or essential for some logic?
@toolforger said: Thanks :-)

Just some feedback and a few questions:

  1. I’m having trouble loading the one-pixel bitmap because I want to have it in the same classpath as the class that’s using it. AssetManager is more a problem than a solution when such requirements arise… ah well, I’ll get that sorted out on my own and move on.
  2. Is the GUI bucket always in front of the scene graph? -20.0f might already be farther away than in-scene spatials.
  3. I don’t see Element#setGlobalModel. Is that planned to be published? Is it an optimization or essential for some logic?

The guiNode is in a separate viewport so it’s always drawn after. Furthermore, the Gui Bucket always flattens Z in the Z buffer.

Ah thanks, that nicely deals with question #2.

Hm. Texture loading works after shaking out trivial bugs, yet I don’t see the border.
[java] // the png is in the same package as the class using it
// I know it works, I saw the exceptions before I had the path right
String borderAssetName =
getClass().getPackage().getName().replace(’.’, ‘/’) + “/background-panel-border.png”;
// creating the panel
Element backgroundPanel = new Element(screen, newId(), // UID
new Vector2f(x, y), // position
new Vector2f(w, h), // dimensions
new Vector4f(1f, 1f, 1f, 1f), // resizeBorders
borderAssetName); // texturePath
// black with 10% transparency - clearly visible
backgroundPanel.getElementMaterial().setColor(“Color”, new ColorRGBA(0f, 0f, 0f, 0.1f));
backgroundPanel.setIgnoreMouse(true);
screen.addElement(backgroundPanel);
[/java]

Is a border somehow incompatible with modifying the material for the background texture?
Am I even feeding the border pixel to the right function?

I hope I answer this correctly.

The resizeBorder is not a visible aspect of the Element. It is used to calculated the distance between vertices and map the appropriate texture coordinates to ensure what you define as a border for your image is rendered at the actual pixel scale, as apposed to resampling and stretching the texture.

Here is the vertex layout (flipped to make the description a bit easier to follow)

01   02   03   04
05   06   07   08
09   10   11   12
13   14   15   16

The x value of resizeBorder is the distance/texCoord distance between vertices 1,2,3,4 and the next row 5,6,7,8 (top border)
The y value is the distance/texCoord distance between vertices 1,5,9,13 and 2,6,10,14 (left border)
The z value is the distance/texCoord distance between vertices 3,7,11,15 and 4,8,12,16 (right border)
And the w value is the distance/texCoord distance between vertices 9,10,11,12 and 13,14,15,16 (bottom border)

Once the resize border is defined, the distance between the verts never changes. The mesh is modified in a way that keeps these constance… stretching the rest of the sampled texture (or everything between verts 6,7,10,11)

If I follow what you are trying to do, you would need a 9 pixel image to keep a constant colored 1 pixel border around the panel(element)

Actually… only the corners remain constant…

Vert groupings 5,6,9,10 and 7,8,11,12 stretch vertically
And vert groupings 2,3,6,7 and 10,11,14,15 stretch horizontally

Let me rephrase that to check whether I understood everything:
The texture is applied to the Element and stretched to fit, NOT stretching the borders that are defined as left=resizeBorders.x, top=resizeBorders.y, right=resizeBorders.z, and bottom = resizeBorders.w.
Right?

I want to have a 0,0,0,0.1f interior and 1-pixel black border, so resizeBorder=(1,1,1,1) and a 3x3 texture that is black except for a 10%-opacity center pixel should do the trick, that matches what you’re saying.

It’s sort-of working now - I get the black border, but the interior is an intransparent gradient (WTF?).
Code:
[java] String texturePath =
getClass().getPackage().getName().replace(’.’, ‘/’) +
“/background-panel-texture.png”;
Element backgroundPanel = new Element(
screen,
newId(), // UID
new Vector2f(x, y), // position
new Vector2f(w, h), // dimensions
new Vector4f(1f, 1f, 1f, 1f), // resizeBorders
texturePath);
// backgroundPanel.getElementMaterial().setColor(
// “Color”, new ColorRGBA(0f, 0f, 0f, 0.1f));
backgroundPanel.setIgnoreMouse(true);
screen.addElement(backgroundPanel);[/java]
Result:

If I reactivate the commented-out setColor call, I get the intended transparency but no black border (look at the center bottom, the border of the 10%-opacity black is visible on the stem of the tree):

Whats the actual background image look like?

The texture?
3x3 pixels.
Border pixels are black with an alpha of 1.0 (RGBA = 0/0/0/1).
Center pixel is black with an alpha of 0.1 (RGBA=0/0/0/0.1).