Facepunch / garrysmod-requests

Feature requests for Garry's Mod
86 stars 24 forks source link

Add GetVGUIAbsoluteCoordinates() #2394

Closed Jaffies closed 5 months ago

Jaffies commented 6 months ago

Basically this function should return convert realtive VGUI coordinates to absolute screen coordinates. Further notice: panel:LocalToScreen(0,0) is bad because it needs panel object In cases where you have a custom draw function, you can't hold a panel object, because it can be used everywhere.

robotboy655 commented 6 months ago

I am really confused as to why you'd need this, or how you'd even expect this to work.

You want a global function that converts relative VGUI coordinates, which would be relative to a panel, to screen-space coordinates without using a panel object? Do you see the problem here, or did I misunderstand your intention?

Also, what do you mean "In cases where you have a custom draw function, you can't hold a panel object, because it can be used everywhere."?

You do realize you can pass arguments to a function, yes? The default Panel paint function provides 3: the panel itself (becomes self when using with PANEL:Paint calling convention), width and height. No matter what, you have the panel object.

Jaffies commented 6 months ago

I am really confused as to why you'd need this, or how you'd even expect this to work.

You want a global function that converts relative VGUI coordinates, which would be relative to a panel, to screen-space coordinates without using a panel object? Do you see the problem here, or did I misunderstand your intention?

Also, what do you mean "In cases where you have a custom draw function, you can't hold a panel object, because it can be used everywhere."?

You do realize you can pass arguments to a function, yes? The default Panel paint function provides 3: the panel itself (becomes self when using with PANEL:Paint calling convention), width and height. No matter what, you have the panel object.

The problem is that i DO NOT have access to panel:Paint function or whatever. I have only draw functions which are default replacement to draw. functions. They cant have a panel object inside argument because no any coder will provide this panel object to draw.RoundedBox() for an example. I have to manually make my own panels and forget about replacing default draw. functions in VGUI. I have my own function: function draw.roundedBoxEx(radius, x, y, w, h, color, leftTop, rightTop, rightBottom, leftBottom, materialOverride, outlineColor, outlineLeft, outlineTop, outlineRight, outlineBottom) in idea it should just replace the default one, but i can't do it because it draws figures in screen space coordinates, not VGUI relative ones. And there's no thing as "pass the self object". Tell that to 100% coders of gmod which use that function, and change 1 million lines of gmod code to pass the goddamn self argument. So there's why there should be a global function which converts VGUI relative coordinates.

garryspins commented 6 months ago

Still doesnt explain how this is at all an issue unless you are using meshes (even then you should be fine if you render to a rt then (0, 0)).

If your functions replace draw and only you are using them (aka, libname.draw.RoundedBox) then just pass the argument or create another function libname.draw.RoundedBoxPanel

if your functions replace draw and are overriding _G.draw, you are doing something wrong if you cannot do exactly what you want. Its not exactly complicated to replace roundedbox with something better, i just think youre going about it in a horrific way.

Please, send your fn decl, id love to see what weird stuff you have going on to need this.

I'm not entirely opposed to having something like this, but this seems like its for the wrong reasons, something like vgui.CurrentRenderingPanel or GM:PreRenderPanel GM:PostRenderPanel would be more useful.

A1steaksa commented 6 months ago

Please correct me if I'm wrong, but I believe the idea here is that in order to create mesh- or IMesh-based drop-in replacements for surface and draw library functions, you need to be able to determine what the currently active screen origin is.

Inside of PANEL:Paint(), something is being done to shift the (0,0) origin point of the screen to the top-left corner of the PANEL being painted. That shifting only seems to affect the surface library and its derivatives (Namely draw.) Because of that, if you're creating a 2D drawing function that uses something like mesh or IMesh and the model matrix for positioning, scaling, etc. you have no "good" way to find out where on the screen the (0,0) origin point currently is to mimic it with whatever drawing method you're using.

You can pass the PANEL as an argument to the function and then use PANEL:LocalToScreen( 0, 0 ) to figure it out, but that's inconvenient and requires passing around the PANEL object which is not required for the surface library. The goal here is to achieve usage parity between how you call a custom draw function and a function from the surface library.

That's my understanding of the issue but, again, I could be wrong. Please correct me if I am.

WardenPotato commented 5 months ago

In the engine it looks like these surface calls are done through surface()->surfaceFunctionHere and surface() just returns g_pVGuiSurface which looks like a global reference to the current vgui surface being drawn to? There also seems to be some sort of stack kept in surface to keep track of the currently drawn panel which this could maybe use?

        // draw the front of the panel with the inset
        if ( _flags.IsFlagSet( PAINT_ENABLED ) )
        {
            surface()->PushMakeCurrent( vpanel, true );
            Paint();
            surface()->PopMakeCurrent( vpanel );
        }
Jaffies commented 5 months ago
local function drawQuad(x, y, w, h, color)
    --[[
                if rubat will add it, then.......
        local absoluteX, absoluteY = GetVGUIAbsoluteCoordinates()
        x = x + absoluteX
        y = y + absoluteY
    ]]
    render.SetColorMaterial()
    mesh.Begin(MATERIAL_QUADS, 1)
        mesh.Color(color.r, color.g, color.b, color.a)
        mesh.Position(Vector(x, y + h))

        mesh.AdvanceVertex()

        mesh.Color(color.r, color.g, color.b, color.a)
        mesh.Position(Vector(x, y))

        mesh.AdvanceVertex()

        mesh.Color(color.r, color.g, color.b, color.a)
        mesh.Position(Vector(x + w, y))

        mesh.AdvanceVertex()

        mesh.Color(color.r, color.g, color.b, color.a)
        mesh.Position(Vector(x + w, y + h))

        mesh.AdvanceVertex()
    mesh.End()
end

function PANEL:Paint(w, h)
    local startX, startY = self:LocalToScreen(0, 0) -- if you do not set startX, startY coordinates, then drawQuad will be rendered in left-top corner of screen. BAAD
    drawQuad(startX, startY, w, h, color_white)
end

Basically this is the code that reproduces the issue. Therefore, my recent convo in wayvo encountered my to make a separate issue.

I am really confused as to why you'd need this, or how you'd even expect this to work.

You want a global function that converts relative VGUI coordinates, which would be relative to a panel, to screen-space coordinates without using a panel object? Do you see the problem here, or did I misunderstand your intention?

Also, what do you mean "In cases where you have a custom draw function, you can't hold a panel object, because it can be used everywhere."?

You do realize you can pass arguments to a function, yes? The default Panel paint function provides 3: the panel itself (becomes self when using with PANEL:Paint calling convention), width and height. No matter what, you have the panel object.