One of the big frustrations I have over and over again is that I need to provide a texture input for SpriteBatch.Draw() even if I just want a colored quad to be drawn.
I think almost everyone who worked with Mono or XNA can relate to this problem and creating a white 1x1 texture everytime is bothersome, and needless to say it's useless GPU overhead to need a texture read for every pixel.
At the same time spritebatch is super accessible, especially for beginners, and probably a better implementation of quad batching than most are willing to implement themselves.
I would therefore propose an implementation of a draw function with only
(Rectangle destinationRectangle, Color color)
inputs, with a simplified pixel shader along the lines of
PixelShader(...)
{
return input.Color;
}
Of course a different overload with stuff like SpriteEffects, Rotation etc. could also be provided.
Alternatively it could be called DrawColor or DrawQuad to make it distinct from the normal Draw();
What do you think?
EDIT: I haven't thought about the batching actually, i just thought about convenience. But it obviously can't work with the batching. I still think it would be nice to provide a function to draw colored quads by default, even if not with the default spritebatch.
Or have a 1x1 texture provided internally so this function can be done.
Sounds nice.
How would the appropriate pixel shader be selected for coloured quads and sprites?
I'd like this. Not sure how best to implement it though.
Why did you close this @UncleThomy?
Because there is no way to implement this in spritebatch, since it can't be batched if some elements use a different shader.
I can reopen though, since it's maybe a worthy discussion on whether or not we implement this some other way, or just provide a 1x1 texture in the background, so it's still using a texture, but user's don't have to provide their own and can simply specify a color
Having the framework provide a 1x1 white texture would be the least impact
approach that fits in with the existing batching process.
As for the API, the two approaches are to supply a null value for the
texture parameter and have the internals supply the white texture, or
duplicate the Draw APIs as DrawUntextured which calls the internals with
the white texture. I would likely prefer the first, unless the added check
for a null texture parameter was measurable.
Both approaches would break backward compatibility (code would not be able
to be shared with XNA), so that is also something to keep in mind.
Is this the first thing that breaks backwards compatibility?
I like the null version, I actually tried that when I started out
With the first approach, passing null for the texture parameter would break
XNA at runtime. With the second approach, the new APIs don't exist in XNA,
so would break compiling in XNA. Not an issue for any code moving forward
only in MonoGame though.
I understand, but would this set a precedent? Is there nothing else in Monogame that doesn't work in XNA?
Probably best to ditch SpriteBatch for this then in favour of a new class?
I understand, but would this set a precedent? Is there nothing else in Monogame that doesn't work in XNA?
KonajuGames said things that break at runtime in XNA. I don't think there's many cases were it's not a compilation failure (at least I can't think of any off the top of my head).
Probably best to ditch SpriteBatch for this then in favour of a new class?
I don't think it's an issue that people can't move from MG to XNA as long as the other direction is not broken.
but would this set a precedent? Is there nothing else in Monogame that doesn't work in XNA?
It would be following a precedent as we already have some APIs in MonoGame that don't exist in XNA, and plans to extend some APIs such as GraphicsProfile. As for this change, it would have to be noted in the documentation that a null texture renders a solid white quad and this is a difference from XNA.
Will it have it's own overload? Because if it uses the Draw(Texture2D, Rectangle, Color) one it could be confusing to new users: for example, all the times I've debugged a ContentLoadException on my Texture2D, it ended up being me specifying a wrong path to the content file. Now instead of throwing an exception and letting the user know their Texture2D is null, they would see a 1x1 white pixel image. Is this behavior acceptable? Of course, if there will be a new overload this won't be a problem...
Of course, if there will be a new overload this won't be a problem...
That makes a lot of sense from a usability point of view. It is probably not a good idea to change what was an error condition into a valid condition.
On #5348 @tomspilman proposed to initialize SpriteBatch with a default texture/srcRect and then draw with a new method, Draw(destinationPos, color) that draws the default texture.
I think @UncleThomy answered the question what happens when you use the new .Draw() but you initialized SpriteBatch from the old .Begin(). Instead of validating on each draw, we just assign a 1x1 White texture as default in the old .Begin().
A while ago someone proposed to embed a basic SpriteFont in MonoGame for debug purposes.
We can use the same login and add a .DrawString(destinationPos, color).
On #5348 @tomspilman proposed to initialize SpriteBatch with a default texture/srcRect and then draw with a new method, Draw(destinationPos, color) that draws the default texture.
drawing with a default scrRect would defeat the purpose.
@energyuser great point
So the only viable solution then would be to either create new overloads that make it obvious only a color is drawn (for example if we set .draw( Color, destRect ... ) ) or a different function all together (eg drawUntextured(...)
Since both would fail at compile time in XNA the second one might be a better, more clear variant, but the first one may be easier to find for people that just start out with monogame, know about spritebatch.draw() and want to draw a colored quad and find the function from the provided overloads.
Not sure.
Actually about my original problem: The uncolored pixel using a 1x1 texture.
Everytime the texture changes spritebatcher has to make a new batch, change the texture in the shader and draw the batch.
So the question then would be - is it more expensive to change the technique in the shader (to use an untextured pixelshader without texture sampling) or changing the texture.
So the question then would be - is it more expensive to change the technique in the shader (to use an untextured pixelshader without texture sampling) or changing the texture.
That's a good point. Maybe an experiment for @nkast? :p
but the first one may be easier to find for people that just start out with monogame, know about spritebatch.draw() and want to draw a colored quad and find the function from the provided overloads.
The precedent here is XNA itself where they provided DrawText() rather than yet another overload of Draw(). Draw() is overloaded enough already. For a newcomer it would be easier to find DrawUntextured() in code completion than one of ten or more overloads of Draw().
One of the big frustrations I have over and over again is that I need to provide a texture input for SpriteBatch.Draw() even if I just want a colored quad to be drawn.
I think almost everyone who worked with Mono or XNA can relate to this problem and creating a white 1x1 texture everytime is bothersome, and needless to say it's useless GPU overhead to need a texture read for every pixel.
You guys are way overthinking this, while worded well and a fine petition this can be solved far more simply by providing a set of helper classes for either quad drawing in orthographic or simply providing a easy to access White dot texture.
For example...
Make a Texture2D helper class that creates a single pixel at game start via set data and can be called or passes easily in some way like TextureHelper.WhiteDot
To be honest. This isn't even a real problem, its just a inconvenience and we need more convenience items where they wont cause problems but can be found easily like when you start Typing Textur ... then you see TexureHelper in intellisense :).
it's useless GPU overhead to need a texture read for every pixel.
It maybe useless cpu reference passing but i doubt this affects the gpu at all.
What reading is there if all the vertices texture coordinates point to a white pixel at the same uv postion in the vertice shader or earlier. Id say this is nothing to the gpu at all at least this part. The only bad part is setting the texture each call here and that is just a single pixel.
Besides were talking about the gpu nitty gritty rasterization level stuff, but its the same as a color, if the same texel needed to be interpolated across all pixels of a triangle with 3 vertices with equal texel positions then so would a color with equal values across those same vertices.
I honestly wouldn't be surprised to find out the gpu turns single texel textures into a color reference via some internal table as a optimization.
I would therefore propose an implementation of a draw function with only
(Rectangle destinationRectangle, Color color)
inputs, with a simplified pixel shader along the lines of
Separate class new functionalty new name QuadBatch or something.
@willmotil - QuadBatch sounds good to me. A separate class allows adding more than just one helper method. I would really like to see an overload that allows specifying different tint colors for each vertex of the quad. This makes drawing gradients super easy.
separate batch class is i think a bad idea, since you won't be able to play with the depth anymore with other entities of the game
maybe just take the 1st pixel of the current texture of the batch, then colorize it?
Well i suppose its not breaking if its new funtionallity. But if you want it in spritebatch then why not just make or ask for a fully customizable raw method one that takes vertices LT LB RT RB instead of a rectangle and all 4 colors per vertice and all the other parameters possible. Then you can really just make your own draw method calling to it however you like.
This way we never need to worry about a additional function request, as that would be the fully capable version that anyone can wrap like the end all be all single full method.
It is kind of annoying to be honest that we don't have full version. If we could alter the vertices also we could use shapes other then rectangles and i could imagine some really cool things being made possible with that.
Most helpful comment
KonajuGames said things that break at runtime in XNA. I don't think there's many cases were it's not a compilation failure (at least I can't think of any off the top of my head).
I don't think it's an issue that people can't move from MG to XNA as long as the other direction is not broken.