Note: I am NOT referring to
CullMode
when I say “culling”. I’m referring to the simple principal of not drawing a 2D object if it is off-screen or covered by another 2D object.
Alright, so I have some code I am working on, from my game’s engine.
foreach (var ctrl in _topLevels)
{
if (!ctrl.Visible)
continue;
if(ctrl.Opacity>0)
ctrl.Draw(time, ctx);
}
ctx.Device.SetRenderTarget(_plexgate.GameRenderTarget);
ctx.BeginDraw();
foreach (var ctrl in _topLevels)
{
if (!ctrl.Visible)
continue;
if (ctrl.BackBuffer != null && ctrl.Opacity > 0)
{
if (IgnoreControlOpacity)
{
ctx.Batch.Draw(ctrl.BackBuffer, new Rectangle(ctrl.X, ctrl.Y, ctrl.Width, ctrl.Height), Color.White * _uiFadeAmount);
}
else
{
ctx.Batch.Draw(ctrl.BackBuffer, new Rectangle(ctrl.X, ctrl.Y, ctrl.Width, ctrl.Height), (Color.White * ctrl.Opacity) * _uiFadeAmount);
}
}
else
{
ctrl.Invalidate();
}
}
ctx.EndDraw();
Note:
ctx
is of typeGraphicsContext
, a class I wrote that wraps various functions inSpriteBatch
andGraphicsDevice
. Documentation is not yet available, but the code should seem pretty trivial to most MonoGame users.
Now let’s assume a few things about this code.
_topLevels
is class member of typeList<Control>
.Control
is an abstract class that represents a UI element, with a parent UI element and child UI elements.Control.Draw(GameTime, GraphicsContext)
is a virtual method that handles painting child controls to the control’s surface as well as painting the control’s UI to its own surface.- Controls can overlap eachother, can respond to mouse/keyboard events, and can be dragged around.
- Thing #4 applies to top level controls (what this code above is rendering).
- This code is run every frame.
There is a slight problem. This problem affects the rendering of child controls as well as handling of mouse events, but I want to deal with the simplest part of the problem, rendering of toplevels.
The problem isn’t something visual. It’s simply the fact that this code’s approach to rendering does not handle overlapping controls very well. Let’s say you have two objects, a circle and a square. Both are in the same exact spot as far as coordinates go, and both are the same size. The square is sitting ontop of the circle in the Z-coordinate (you should only see the circle if the square is translucent or invisible).
How does one, in that case, prevent the circle from rendering completely? Of course, as far as rendering goes you would switch that off if the square was translucent, but let’s say they’re both solid. How can I adjust this code so that it doesn’t render UI elements that are completely covered by other UI elements?
The reason I ask this is because we currently have a framerate issue that although it wouldn’t bug most people, it’s really irking me. I want to apply a similar culling optimization to the mouse handler so that only controls that aren’t covered by other ones receive mouse events, that’ll help out a lot, but let’s solve the visual stuff first.
Any help is greatly appreciated