2

我一直在尝试编写一些可以让我使用类轻松管理 OpenGL 的东西。

我采用了一种方法,即拥有一个 Drawable 类[形状/等将继承并覆盖绘图函数],然后使用 Controller 类遍历 Drawable 类表并将它们全部绘制出来。我注意到的唯一问题是从 Drawable 类而不是 Rectangle 类调用 draw() 方法。??

    class Drawable {
        public:
            void draw();
    };
    class Rectangle : public Drawable {
        public:
            void draw();
    };
    class Controller {
        public:
            Drawable ents[200];
            int ent_count;
            void frame();
            void append(Drawable item); // this will add an object onto the list
            Controller();
    };
    void Drawable::draw() {
        // this is the default drawing function, which should be overridden
    }
    void Rectangle::draw() {
        // gl functions here
    }
    void Controller::frame() {
        for(int i=0;i<ent_count,i++) {
            ents[i].draw(); // draw all entities on the list
        }
        // here, a timer would loop back the frame() function
    }
    void Controller::append(Drawable item) {
         ents[ent_count++]=item;
    }
    int main(void) {
         Controller main_controller; // create a controller
         Rectangle rect; // create a rectangle
         main_controller.append(rect); // insert rectangle into controller list
         main_controller.frame(); // start the frame loop
    }

[如果有轻微的打字错误,那是因为它是作为方法摘要写的。]我尝试使用的这种方法不是很成功,我很确定它与遗产。有任何想法吗?整个源代码:

#include <iostream>
#include <GL/glfw.h>
#include <GL/gl.h>
class Drawable {
      public:
             int x,y;
             void draw();
             void frame();
             void create();
             void destroy(); 
};
void Drawable::create() {

}
void Drawable::draw() {
}
class Rectangle : public Drawable {
      public:
      int w,h;
      unsigned short r,g,b;
      Rectangle(int x,int y, int w, int h, unsigned short r, unsigned short g, unsigned short b);
      void draw();
};
void Rectangle::draw() {
     glColor3ub(r,g,b);
     glBegin(GL_QUADS);
     glVertex2i(x,y);
     glVertex2i(x+w,y);
     glVertex2i(x+w,y+h);
     glVertex2i(x,y+h);
     glEnd();
}
Rectangle::Rectangle(int x,int y, int w, int h, unsigned short r, unsigned short g, unsigned short b) {
                         this->x=x;
                         this->y=y;
                         this->w=w;
                         this->r=r;
                         this->g=g;
                         this->b=b;
}
class Controller {
public:
       Controller(int w,int h,int fsaa,bool fs,bool vsync,const char* title);
       bool running;
       int frame_limit;
       Drawable entity[200];
       int entity_count;
       void fev();
       void begin();
       void bind();
       void append(Drawable item);
      };
Controller::Controller(int w,int h,int fsaa,bool fs,bool vsync,const char* title) {
                          int fullscreen= (fs ? GLFW_FULLSCREEN : GLFW_WINDOW);
                          bool window=glfwOpenWindow(w,h,0,0,0,0,10,10,fullscreen);
                          glfwSetWindowTitle(title);
                          frame_limit=120;
                          entity_count=0;
                          std::cout << (window ? "Successfully initialized a window.\n" : "Error initializing window!\n");
       }
void Controller::begin() {
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     glOrtho(0,640,480,0,0,5);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     glClearColor(0.4f,0.4f,0.4f,1.0f);
     running=true;
     fev();
}
void Controller::append(Drawable item) {
     entity[entity_count++]=item;
}
void Controller::fev() {
     glClear(GL_COLOR_BUFFER_BIT);
     for (int i=0;i<entity_count;++i) {
          entity[i].draw();
          }
     glfwSwapBuffers();
     if (frame_limit>0) {
        glfwSleep(1000/frame_limit*0.001);
     }
     if (running) {
        if (glfwGetKey(GLFW_KEY_ESC) || !glfwGetWindowParam(GLFW_OPENED)) {
           running=false;
        }
        fev();
     } else {
       std::cout << "terminated!";
}
}
int main(void) {
    glfwInit();
    Controller main(640,480,0,false,false,"WindTitle");
    Rectangle rect(50,50,50,50,50,50,50);
    main.append(rect);
    main.begin();
}
4

3 回答 3

4

我一直在尝试编写一些可以让我使用类轻松管理 OpenGL 的东西。

新手经常尝试这个。但是 OpenGL 确实不能很好地转化为 OOP。问题是,它是一个有限状态机,要正确映射到 OOP,您必须在不同类和实例之间进行大量状态跟踪。

我自己至少尝试了 3 次将 OpenGL 抽象为 OOP 方案。它总是以某种方式破裂。

这并不是说您不能将 OOP 与 OpenGL 一起使用。您不能只将 OpenGL 概念 1:1 映射到类中。


关于您的实际问题:使用虚拟功能。

于 2013-01-02T00:34:55.410 回答
3

正如其他人所提到的,最好尝试使用一些现有的包装器。

也就是说,您需要为实体列表使用指针。您在切片时遇到问题。

正如提到的一些评论,您需要进行Drawable::draw()虚拟化,因此调用draw()Drawable调用子实现。也就是说,因为您将Drawables 添加到对象列表而不是指向对象的指针列表中,所以正在对对象进行切片。这意味着它们正在从子类型转换回Drawable对象,从而删除有关特定类型的额外信息。

所以代替这个:

Drawable ents[200];

你应该这样做:

std::vector<Drawable*> ents;

或者如果你有 C++11 或 Boost:

std::vector<std::shared_ptr<Drawable>> ents;

并且您的附加方法将作为参考。

void Controller::append(Drawable &item) {
     ents[ent_count++] = &item;
}

或者

void Controller::append(Drawable &item) {
  ents.push_back(&item);
}

或者

void Controller::append(std::shared_ptr<Drawable> item) {
  ents.push_back(item);
}

你的渲染循环会是这样的:

for (int i = 0; i < ents.size(); ++i) {
  ents[i]->draw();
}

这个循环也可以清理使用iterator

于 2013-01-02T00:32:26.433 回答
0

您可能想看看Coin3D。它是围绕 OpenGL 的大量丰富的 C++ 类包装器。你可以看看他们是如何使用它的。有用于与各种窗口系统(Qt、Windows、Cocoa...)集成的库。

于 2013-01-02T00:54:49.427 回答