【问题标题】:How to avoid restarting the rectangle when drawing a new one?绘制新矩形时如何避免重新启动矩形?
【发布时间】:2021-07-24 22:08:49
【问题描述】:

我试图在这个程序中绘制多个矩形,但是每当我绘制一个新矩形时,旧矩形就会消失,我怎样才能在不丢失旧矩形的情况下绘制一个新矩形?这是我的程序:

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();
}

【问题讨论】:

  • 保留开始和结束位置的数据结构(可能是vector<pair<Position>>),当您单击时添加到该列表中,然后使用绘图代码glBegin(GL_QUADS) 等遍历此列表...
  • 我建议你接受@lisyarus 的回答,因为他的回答是第一个(即使我做了一些额外的工作)

标签: c++ opengl glut


【解决方案1】:

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

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_LOOPPrimitive 的实现:

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();
}

【讨论】:

  • 它适用于GL_QUADS,但如果我将其更改为GL_LINE_LOOP 来绘制未填充的矩形,这些矩形会一直连接到另一个矩形,我不知道为什么。
  • @user 当然可以,因为在这种情况下,您必须在循环中移动 glBegin/glEnd。然而,这是一个新问题。无论如何,我已经扩展了答案(见最后一段)
【解决方案2】:

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

按照 jackw11111 的建议,一个典型的解决方案是将所有矩形坐标存储在某个数据结构中(如果您使用 C++,std::vector 是一个完美的选择),并在您的 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

【讨论】:

    猜你喜欢
    • 2021-07-18
    • 1970-01-01
    • 2013-03-09
    • 2014-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多