markaren / threepp

C++20 port of three.js (r129)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Window does not resize correctly

yammelvin opened this issue · comments

Ran several demos. All has the same issue.
Rendering is fine. However, when I try to resize the window, the window does not resize correctly.
The window keeps getting bigger when I drag the mouse and stop responding to the minimize, maximize and close button.
Had to press Ctrl-C at the terminal to close the window.
I'm using Ubuntu 22.04 LTS.

Strange. I have not encountered this issue, so more info would be helpful.

I added a line in examples/demo.cpp to print the width, height and aspect in the canvas.OnWindowResize()

    canvas.onWindowResize([&](WindowSize size) {
        std::cout << "w:" << size.width << ",h:" << size.height << ",a:" << size.getAspect() << std::endl;
        camera->aspect = size.getAspect();
        camera->updateProjectionMatrix();
        renderer.setSize(size);
        handle.setPosition(canvas.getSize().width - 130, 0);
    });

Attached is the output.
The size keeps growing regardless of the direction of the mouse drag.
Occasionally it will suddenly jump to w:474,h:311,a:1.52412 and then back.

sizes.zip

As far as I know, you are the only one experiencing this. It should not be an issue on Mac and Windows (nor MinGW).
I'm assuming you are using vcpkg to get the glfw library?

Yes. I am using vcpkg.
Am I the only one using Ubuntu 22.04 LTS?
btw, I am also using latest nvidia drivers version 470.182.03

I commented the following line in Canvas.cpp:

// glfwSetWindowSizeCallback(window, window_size_callback);

Then, the window resizes correctly.
But the canvas does not resize.

You are the first to raise this issue. I would think this is a screen issue rather than a OS issue, however.

A quick fix would be to set the canvas size once of course.

Could you attach a gif showing the issue in action?

Not sure how to capture animated gif.
Anyway below is what the window looks like without the glfwSetWindowSizeCallback()

Screenshot from 2023-04-11 00-41-56

OK. I commented the following line in GLRenderer.cpp:

void GLRenderer::setSize(WindowSize size) {

    pimpl_->_size = size;

    int canvasWidth = pimpl_->_size.width * pimpl_->_pixelRatio;
    int canvasHeight = pimpl_->_size.height * pimpl_->_pixelRatio;

    std::cout << "canvasWidth:" << canvasWidth << ",canvasHeight:" << canvasHeight << ",pixelRatio:" << pimpl_->_pixelRatio << std::endl;
    //pimpl_->canvas_.setSize({canvasWidth, canvasHeight});

    this->setViewport(0, 0, size.width, size.height);
}

Both the window and the canvas resizes correctly.
Seems like there is something wrong with this line.
But the text position is wrong.
See attached screenshot.

Screenshot from 2023-04-11 01-08-29

Canvas::setSize() calls glfwSetWindowSize()

    void setSize(WindowSize size) const {
        glfwSetWindowSize(window, size.width, size.height);
    }

In demo.cpp, onWindowResize() calls renderer setSize() which calls canvas setSize() which in turn calls glfwSetWindowSize(), would that not trigger the window resize event again?

In demo.cpp, onWindowResize() calls renderer setSize() which calls canvas setSize() which in turn calls glfwSetWindowSize(), would that not trigger the window resize event again?

Apparantly not.
The reason it is called again has to do with the extra pixelRatio information that is passed (have not used that feature myself)

But the text position is wrong.

In that case, the text is correct here.

My apologies. My bad.
Earlier, I commented the following line:

    canvas.onWindowResize([&](WindowSize size) {
        std::cout << "w:" << size.width << ",h:" << size.height << ",a:" << size.getAspect() << std::endl;
        camera->aspect = size.getAspect();
        camera->updateProjectionMatrix();
        renderer.setSize(size);
        // handle.setPosition(canvas.getSize().width - 130, 0);
    });

That's why the position is wrong.

Now, I've uncommented the above line
and with the following line commented in GLRenderer::SetSize

void GLRenderer::setSize(WindowSize size) {

    pimpl_->_size = size;

    int canvasWidth = pimpl_->_size.width * pimpl_->_pixelRatio;
    int canvasHeight = pimpl_->_size.height * pimpl_->_pixelRatio;

    std::cout << "canvasWidth:" << canvasWidth << ",canvasHeight:" << canvasHeight << ",pixelRatio:" << pimpl_->_pixelRatio << std::endl;
    // pimpl_->canvas_.setSize({canvasWidth, canvasHeight});

    this->setViewport(0, 0, size.width, size.height);
}

Now, everything works fine. The window and the canvas resizes correctly. Text position is correct.
Seems like the glfwSetWindowSize() does trigger the window resize event again.
That's why the window size does not resize correctly.
See attached screenshot.

Screenshot from 2023-04-11 01-53-44

Seems like the glfwSetWindowSize() does trigger the window resize event again.

Then it's possible that the beaviour is different on Linux systems. Will make a PR, and you can test it.

Please have a go at: https://github.com/markaren/threepp/tree/fix/window_resize

It should not trigger an event if the originating call is from GLRenderer::setSize.

Nope. The fix does not work.
The window does not resize correctly.

I added 4 cout lines in Canvas.cpp:

    void setSize(WindowSize size, bool internal) {
        if (internal) manualWindowResizeState = true;
        std::cout << "Before setting window size" << std::endl;
        glfwSetWindowSize(window, size.width, size.height);
        std::cout << "After Setting window size" << std::endl;
        if (internal) manualWindowResizeState = false;
    }
    static void window_size_callback(GLFWwindow* w, int width, int height) {
        std::cout << "window_size_callback" << std::endl;
        auto p = static_cast<Canvas::Impl*>(glfwGetWindowUserPointer(w));
        p->size_ = {width, height};
        if (!p->manualWindowResizeState && p->resizeListener) {
            std::cout << "calling listener" << std::endl;
            p->resizeListener.value().operator()(p->size_);
        }
    }

Output is:

Before setting window size
After Setting window size
window_size_callback
calling listener
Before setting window size
After Setting window size
window_size_callback
calling listener
Before setting window size
After Setting window size
window_size_callback
calling listener
. . .

Apparently, glfwSetWindowSize() returns immediately and then the window resize callback is triggered.
therefore manualWindowResizeState is always false.

Nope. Still not working.

Added following couts:

    static void window_size_callback(GLFWwindow* w, int width, int height) {
        std::cout << "window_size_callback" << std::endl;
        auto p = static_cast<Canvas::Impl*>(glfwGetWindowUserPointer(w));
        p->size_ = {width, height};
        if (!p->manualWindowResizeState && p->resizeListener) {
            std::cout << "before calling listener" << std::endl;
            p->resizeListener.value().operator()(p->size_);
            std::cout << "after calling listener" << std::endl;
        }
        std::cout << "setting manualWindowResizeState=false" << std::endl;
        p->manualWindowResizeState = false;
    }
    void setSize(WindowSize size, bool internal) {
        if (internal) {
            std::cout << "setting manualWindowResizeState=true" << std::endl;
            manualWindowResizeState = true;
        }
        std::cout << "before glfwSetWindowSize" << std::endl;
        glfwSetWindowSize(window, size.width, size.height);
        std::cout << "after glfwSetWindowSize" << std::endl;
    }

Output is:

window_size_callback
before calling listener
setting manualWindowResizeState=true
before glfwSetWindowSize
after glfwSetWindowSize
after calling listener
setting manualWindowResizeState=false
window_size_callback
before calling listener
setting manualWindowResizeState=true
before glfwSetWindowSize
after glfwSetWindowSize
after calling listener
setting manualWindowResizeState=false
. . .

Well, then I dunno. Not sure what causes this on your end... Anyway, make a fork (I want the pixel ratio thing to be there since that's how three.js works) or avoiding resizing seems to be the solution for now.

I made the following changes.
And tested working.

Added to Canvas.cpp

bool toSetGlfwWindowSize = true;
    void setSize(WindowSize size, bool internal) {
        if (toSetGlfwWindowSize) {
            glfwSetWindowSize(window, size.width, size.height);
        }
    }
    static void window_size_callback(GLFWwindow* w, int width, int height) {
        auto p = static_cast<Canvas::Impl*>(glfwGetWindowUserPointer(w));
        p->toSetGlfwWindowSize = false;
        p->size_ = {width, height};
        if (p->resizeListener) {
            p->resizeListener.value().operator()(p->size_);
        }
        p->toSetGlfwWindowSize = true;
    }

the parameter internal in SetSize() is not needed anymore.