绘制新矩形时如何避免重新启动矩形?

How to avoid restarting the rectangle when drawing a new one?

我想在这个程序中绘制多个矩形,但是每当我绘制一个新矩形时,旧矩形就消失了,如何在不丢失旧矩形的情况下绘制新矩形?这是我的程序:

struct Position
{
    Position() : x(0), y(0) {}
    float x, y;
};
Position start, finish;

void mouse(int button, int state, int x, int y)
{
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    {
        start.x = finish.x = x;
        start.y = finish.y = y;
    }
    if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
    {
        finish.x = x;
        finish.y = y;
    }
    glutPostRedisplay();
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);

    glBegin(GL_QUADS);
    glVertex2f(start.x, start.y);
    glVertex2f(finish.x, start.y);
    glVertex2f(finish.x, finish.y);
    glVertex2f(start.x, finish.y);
    glEnd();
    
    glFlush();
}

请注意,简单地删除 glClear 会导致 所有 个您曾经绘制的矩形持续显示在屏幕上 - 您将无法,例如只删除其中一个。它还可能导致 window 的初始内容包含一些垃圾像素(尽管这可以通过在程序开始时执行 glClear 来解决)。

一个典型的解决方案是,正如 jackw11111 所建议的那样,将所有矩形坐标存储在某些数据结构中(std::vector 如果您使用 C++,这是一个完美的选择),并且在您的 display 函数,您首先执行 glClear,然后遍历所有矩形并一个一个地绘制它们。像

struct Rectangle
{
    Position start, finish;
};
std::vector<Rectangle> rectangles;

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);

    glBegin(GL_QUADS);
    for (Rectangle const & r : rectangles)
    {
        glVertex2f(r.start.x, r.start.y);
        glVertex2f(r.finish.x, r.start.y);
        glVertex2f(r.finish.x, r.finish.y);
        glVertex2f(r.start.x, r.finish.y);
    }
    glEnd();
}

顺便说一句,你几乎肯定不需要 glFlush

创建一个类型来存储一个矩形:

struct Rect
{
    Rect(const Position& s, const Position& f) 
        : start(s), finish(f) {}
    Position start;
    Position finish;
};

使用std::vector<Rect>类型的容器来存储矩形

#include <vector>
std::vector<Rect> rects;

完成矩形后将其添加到容器中:

void mouse(int button, int state, int x, int y)
{
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    {
        start.x = finish.x = x;
        start.y = finish.y = y;
    }
    if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
    {
        finish.x = x;
        finish.y = y;
        rects.emplace_back(start, finish);
        start = finish;
    }
    glutPostRedisplay();
}

循环绘制所有矩形:

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);

    glBegin(GL_QUADS);
    for (auto& rect : rects)
    {
        glVertex2f(rect.start.x, rect.start.y);
        glVertex2f(rect.finish.x, rect.start.y);
        glVertex2f(rect.finish.x, rect.finish.y);
        glVertex2f(rect.start.x, rect.finish.y);
    }
    glVertex2f(start.x, start.y);
    glVertex2f(finish.x, start.y);
    glVertex2f(finish.x, finish.y);
    glVertex2f(start.x, finish.y);
    glEnd();
    
    glFlush();
}

此外,您还可以通过实现 glutMotionFunc 回调来获得不错的绘图效果:

void motion(int x, int y)
{
    finish.x = x;
    finish.y = y;
    glutPostRedisplay();
}
int main(int argc, char** argv)
{
    // [...]

    glutMotionFunc(motion);

    // [...]
}


GL_LINE_LOOP Primitive 的实施:

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);

    for (auto& rect : rects)
    {
        glBegin(GL_LINE_LOOP);
        glVertex2f(rect.start.x, rect.start.y);
        glVertex2f(rect.finish.x, rect.start.y);
        glVertex2f(rect.finish.x, rect.finish.y);
        glVertex2f(rect.start.x, rect.finish.y);
        glEnd();
    }

    glBegin(GL_LINE_LOOP);
    glVertex2f(start.x, start.y);
    glVertex2f(finish.x, start.y);
    glVertex2f(finish.x, finish.y);
    glVertex2f(start.x, finish.y);
    glEnd();
    
    glFlush();
}