• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Windows draw_rectangle_color with outline is off

vdweller

Member
Bros,

I have the following issue: I am working on a list menu where essentially the elements (buttons with text) are packed together in vertical columns. I want to use a rectangle shape as a border for each element. So I am using

draw_rectangle_color(x1,y1,x2,y2,cba,cba,cba,cba,1);

Buuut...as you can see, the rectangle is bloated by 1 pixel or so:

upload_2019-12-15_14-51-28.png

I am *perfectly* sure the coordinates are correct: using a draw_sprite_ext to stretch a white pixel across an element's dimensions and 0.5 alpha fills the area perfectly. If each box coordinates overlapped then doing that would produce "lines" across the box borders, where two 0.5 alphas overlap.

So, instead of draw-rectangle_color, I try
draw_set-color(color); draw_rectangle(blah);

And the display is, this time, correct:

upload_2019-12-15_14-54-52.png

Sooo...I am aware from older posts that when it comes to shapes, you can't please every graphics driver. Sure, I could probably manually alter the offset, but will this be consistent across all other PCs? I tested these methods on my older PC too, the result is the same, but this isn't a large enough sample to be sure that draw_rectangle_color behaves like that at all times across all systems.

Moreover...it's a matter of speed: I have no problem setting the color then drawing a rectangle like in my second method, but I am not sure it's the faster way and I don't want to benchmark this on my (rather fast) GPU since results will probably vary with each GPU implementation of drawing such shapes. I want to use this menu on a very resource intensive environment (a colony simulation game) so every batch break counts...

So do you have any insight on this? Is this a universal thing? Should I abandon draw_rectangle_color altogether? Should I use it with manually correcting the coords because it behaves the same across all systems? Any alternatives?

EDIT: For the sake of reference, on my system draw_rectangle color appears to be ~2x faster than { draw_set_color(); draw_rectangle(); }. Moreover, the second method takes 1 vertex batch more than the first (25 batches for 10 menu boxes in method #1 became 35 in method #2).

EDIT2: I am using only integer coordinates and no views.

EDIT3: OK my PC is probably on drugs but drawing 4 stretched pixel as rectangle borders is faster even than draw_rectangle_color(), about 2 times faster.... wtf
 
Last edited:

Yal

🐧 *penguin noises*
GMC Elder
The 1-pixel-off effect you see has been around for a while, it's a side effect of all vector drawing functions drawing screen pixels instead of surface pixels. Another fun side effect is that you can't draw a rectangle with a width/height of zero (which is especially relevant for healthbars and similar), so you manually need to explicitly not draw something for width = zero case (or you'll get a visible sliver). It might be possible to fix it by manually adjusting a coordinate by 1, but I think the "draw a stretched pixel texture" method has more merit; since the border pixels will be 1 surface pixel big instead of 1 screen pixel, they will be a consistent size no matter the player's screen resolution.
 

CloseRange

Member
Yal is correct and I'd also like to add that 99% of the time drawing a gradiant is slower than drawing a solid color.
That's what draw_rectangle_color does, draws a gradient. Now maybe GML is smart enough to know when you're drawing a gradiant of all same colors, but I wouldn't give it that much credit...
Code:
show_debug_overlay(true);

var c = c_white;
for(var i=0; i<10000; i++) {
    draw_rectangle_color(100, 100, 200, 100, c, c,c, c, false);
}
this code resulted in a fps of about 150
Code:
show_debug_overlay(true);

var c = c_white;
for(var i=0; i<10000; i++) {
    draw_set_color(c);
    draw_rectangle(100, 100, 200, 100, false);
}
this one using draw_set_color gave me about 300-350
so twice as fast.
 

vdweller

Member
Yal is correct and I'd also like to add that 99% of the time drawing a gradiant is slower than drawing a solid color.
That's what draw_rectangle_color does, draws a gradient. Now maybe GML is smart enough to know when you're drawing a gradiant of all same colors, but I wouldn't give it that much credit...
Code:
show_debug_overlay(true);

var c = c_white;
for(var i=0; i<10000; i++) {
    draw_rectangle_color(100, 100, 200, 100, c, c,c, c, false);
}
this code resulted in a fps of about 150
Code:
show_debug_overlay(true);

var c = c_white;
for(var i=0; i<10000; i++) {
    draw_set_color(c);
    draw_rectangle(100, 100, 200, 100, false);
}
this one using draw_set_color gave me about 300-350
so twice as fast.
That's the exact opposite of my benchmark, but I have a surprise for you: Both are correct. It just depends on your CPU/GPU balance, and VM/YYC setting. On some PCs, breaking that extra vertex batch may be more expensive. For others, having to execute these 2 lines instead of one may be the bottleneck. It depends.
 

CloseRange

Member
so why the heck do you care?.... according to you it's slower on some computers but faster on others. So shouldn't that mean it's basically a 50/50 so that small, small, small performance boost is not gonna matter in the long run unless you are running this code 10,000 times and even then won't have a noticeable enough radiance.

draw_set_color is most likely just a variable swap. no slower than saying y = 25; it's an order 1 operation. No function can beat an order 1 operation. doesn't matter if it's ran through gpu or cpu or any-pu. Now of course this function is a black box so it's possible that it might do a little more under the hood but I doubt it.
Howerver my computer is good but I treat it like trash so it's not good so here are my tests with vertex batches
Code:
show_debug_overlay(true);

var c = c_white;
for(var i=0; i<10000; i++) {
    draw_set_color(c);
    draw_rectangle(100, 100, 200, 100, false);
}
using 2 lines I have a whopping total of 6 vertex batches
Code:
show_debug_overlay(true);
var c = c_white;
for(var i=0; i<10000; i++) {
    draw_rectangle_color(100, 100, 200, 100, c, c, c, c, false);
}
with draw_rectangle_color? 10003 vertex batches.

So either your breaking the batches somehow when running the draw code (Idk cus you didn't show much of the code) or our computers are wildly differant so much so that draw_rectangle is dog doodoo on yours.
So what do you do? Say to heck with gpu and cpu and GML and throw all the things into a surface not caring how much spaghetti is on it and then throwing that at the screen.
 

Yal

🐧 *penguin noises*
GMC Elder
So what do you do? Say to heck with gpu and cpu and GML and throw all the things into a surface not caring how much spaghetti is on it and then throwing that at the screen.
Could work as long as the contents of all the boxes don't need updating every step. Also, surfaces are stored in volatile VRAM and are lost easily, so there needs to be a system to detect them being dead and re-drawing...


Also, unrelated, you could potentially speed up the box drawing even more than the 4-pixels approach. Draw two stretched pixels: first one with the outline size/color, then one with the box contents size and the black background color on top.

...but I think the text drawing will eat the most resources, since it draws 2 vertices per character. Drawing 4 or 8 vertices to make the box doesn't matter if you draw dozens of letters. They'll all be from the same texture (if the font texture fits on one texture page), but it'll still require a pretty substantial amount of textured polygons.
 
Top