#dashboard screen pixel imprecision on draw_line and _rect

1 messages · Page 1 of 1 (latest)

inner osprey
#

Drawing on dashboard screens is imprecise on 2nd set of coorcinates in draw_line() and _rect() functions.

Following code shows the issue, where second set of coords is limiting for drawn object, where said object should reach those coordinates instead.

    $Screen.draw_line(5, 0, 5, 5, $dgreen) ;left vertical helper
    $Screen.draw_line(12, 0, 12, 5, $dgreen) ;right vertical helper
    $Screen.draw_line(0, 9, 4, 9, $dgreen) ;left horizontal helper
    $Screen.draw_rect(5, 6, 12, 9, $dgreen) ;test rect
bright cosmos
#

I had trouble understanding the precise bug report here, until I read this precise line from the discussion in the thread: #game-discussions message

inner osprey
#

This?
basically i draw two vertical lines on X 5 and 12 to see where those coords are
then i draw line between X 5 and 12, yet said line is not drawn on 12, but ends on 11
and the same applies on other axis, as shown with rect

sacred juniper
#

Not a bug.
This is expected behaviour.
From documentation:

; draw_rect(x1, y1, x2, y2, color [, fillcolor])
draw_rect(50, 50, 60, 60, red) ; draw a red square starting at coordinates 50,50 inclusive through 60,60 exclusive, it will effectively have a size of 10x10.

Note the start inclusive / end exclusive.

The reason is that pixel indices start at 0, not 1, and most use cases you would use a start + width idiom to define the end, or use the screen_w directly as the end, maybe with a - offset.

#

Example: You would expect a rect with coords 1 and screen_w - 1 to be the size of the screen but have a single pixel margin around it.

#

Now I understand that the bug report was related to lines, not rect, but they work the same way as rect for consistency.

#

From the example on the wiki:

draw_line(0, 0, screen_w, screen_h, yellow) ; draw a yellow line going from top left to bottom right of the screen

so if you were to do draw_line(1, 1, screen_w-1, screen_h-1, yellow)
You would also expect a 1px margin around the line

#

Overall I think it's clearer this way.
The use case where you'd use it with hardcoded coords you would typically trial and error anyways until it looks good and it doesn't have to make sense lexically in the code

#

@vagrant timber any thoughts?

#

@bright cosmos @inner osprey

inner osprey
#

well, from geometry standpoint, if i am to draw a line between two points, said line would end in those points

#

not just shy of one of them

#

it would make sense, if you didn't use two sets of coordinates, but start point & dimension. But if i define two coordinates, i kinda expect the line to reach it...

#

because now
$screen.draw_rect(0, 0, 10, 10, white)
will be different than
$screen.draw_rect(10, 10, 0, 0, white)
even tho those two sets of coordinates are identical.

#

it would be completely different, if said function would be draw_rect(X,Y,width,height,color,fill), because then, if i did
$screen.draw_rect(0, 0, 10, 10, white)
it would indeed go 10 points - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

#

but it is defined as two sets of coordinates...

#

sure, docu says exclusive, but that's the point, the logic of that is somewhat ... faulty

#

width vs endpoint are two different things

vagrant timber
# sacred juniper <@481507402911318016> any thoughts?

From where I'm standing, the documented behavior is what's expected. That's not necessarily true for everyone else's expectations though..

Personally I'd prefer to leave it as is, to be consistent with the opengl/vulkan implementation

#

That said.. Over on the Stormworks discord this question comes up from time to time

inner osprey
#

it makes 0 sense from matematics standpoint...

#

if it were dimensions, sure, that would be different story. But those functions expect two sets of X/Y coordinates and one of those sets is treated differently than the other

vagrant timber
#

Nah it makes perfect mathematically since a zero-length segment is a special case of a line segment, where the distance between the endpoints is 0, which makes it a point. You're asking it to draw a line segment, not a point. 😅 Not here to debate that again though..

sacred juniper
inner osprey
#

not just line, rect / triangle as well

#

yea, draw was dimensions and there's where it most probably originates from

#

but new functions are described differently

#

problem is you can't just rename it in docs, as it is not dimension, but mix of dimension and end point

#

its basically neither

sacred juniper
#

Think of it this way:
Your coords are actually positioned on the top left corner of pixels.
Then it makes perfect sense as is.

vagrant timber
#

I see this question pop up from time to time, but that's not a sufficient indication of what behavior people expect.

You could have 6 people expecting it to be a pixel short because of previous experience with graphics programming.. And only one person expecting it to draw the "full line"

That 1/7 person might mean a hundred people ask that question, skewing the expected value, leading one to believe they're in the majority..

In reality, I think the minority will expect it to be a pixel short (as implemented)

#

Like 9/10 will have little to no experience with it, and expect a line from 0 to 1 to be 2 pixels long

#

Expert snarky comments (from the 1/10) about breaking convention for the sake of not having to deal with the question though 😅

sacred juniper
#

either way we have to leave it as is, because otherwise it would break everyone's stuff, but also I personally think it makes sense as is.

vagrant timber
#

Yes it'd definitely break stuff

#

I totally get where Andy is coming from though

sacred juniper
#

I think with the other way of doing it we would have had just as many (or more) complaints, because of my examples above

vagrant timber
#

I didn't like it when I first encountered it, and just accepted it as "that's how computers work"

#

Yea I'd leave it as it is, and deal with the questions when they arrive. You're less likely to be pulled into arguments over how opengl/vulkan line rasterisation (should) work 😄

#

Might be an idea to clarify the behavior in the documentation, beyond what's already there. The language is kinda technical. Visuals would work wonders

sacred juniper
#

the documentation is open source 😉

vagrant timber
#

It's not as technical as "> When pa and pb lie on fragment centers, this characterization of fragments reduces to Bresenham’s algorithm with one modification: lines produced in this description are “half-open”, meaning that the final fragment (corresponding to pb) is not drawn." of course heh

inner osprey
#

and not just in doccu

#

but in function description as well

#

(in doccu ... right )

#

if i have function, that does not differentiate in variable names, i expect those variables to be treated equally

#

i am talking about these
; draw_line(x1, y1, x2, y2, color)
; draw_rect(x1, y1, x2, y2, color [, fillcolor])
; draw_triangle(x1, y1, x2, y2, x3, y3, color [, fillcolor])

#

there is 0 indication in those names they will be treated differently

#

and again, from geometry perspective it's just wrong ...

vagrant timber
#

Yup, you sort of have to know in advance. I don't like saying it, but "that's just how it is" because of rasterisation

inner osprey
#

sad fact, that some other APIs do it this way, because XYZ, does not make it right...

vagrant timber
#

I don't think there are any that do it differently. DirectX, OpenGL, Vulkan etc all do it like this

inner osprey
#

because there are other APIs that do it properly 😛

#

TK

vagrant timber
#

tkinter?

inner osprey
#

mhm

#

i can try it if you want me to, bit worried that i will break my weatherstation tho

vagrant timber
#

I wouldn't call that a graphics API

#

It's a GUI toolkit

inner osprey
#

well, so is xenoncode

#

(or atleast part of it)

vagrant timber
inner osprey
#

tis 7:20am here and i didn't sleep yet

vagrant timber
#

Same

#

Well no, I slept for 3 hours

inner osprey
#

lucky. 0 for me.

#

so i won't touch it rn

#

but i may try in WSL ...

#

if i get tkinter to work

#

not naming your script tkinter.py helps ... 😄

#

*le sigh* does not work over RDP

vagrant timber
#

test.py 😅

inner osprey
#

but as i said, does not work over RDP

#

_tkinter.TclError: couldn't connect to display "192.168.0.10:0"

#

holdup ... that's not right

#

i have different IP for a long time now

#

idk ... 😴

bright cosmos
# sacred juniper <@233294218028777477> <@456538086453805068>

I would expect 0,0 and screen_w -1, otherwise it doesn't feel consistent. This feels like, C/C++ example incoming:

for(i =0; i <= sizeof(myArray)h;i++)
cout << myArray[i]

This would be bad, and potentially invoke reality-breaking nasal demons, or undefined behavior.

Why? Why would you be inconsistent in your use of zero-basedness. Yes I understand the reasoning from the perspective of the end-user and I immediately thought about the "up to but exlcuding" logic, but it breaks pre-existing logic to existing programmers. It does to me at least.

Anyone that's done drawing and thinks about pixels as an array, who addresses the first pixel using 0, will want to avoid using pixel[width].. obviously that doesnt exist, you must have meant pixel[width-1]; yes annoyingly with a check to see if width > 0 to avoid crashes.. but yeah