简体   繁体   中英

OpenGL with c++ classes

I've been trying to write something that will let me easily manage OpenGL using classes.

I took an approach of having a Drawable class [which shapes/etc would inherit from, and override a draw function], and then using a Controller class to iterate through a table of Drawable classes and draw them all. The only issue that I've noticed that the draw() method is being called from the Drawable class, instead of the Rectangle class. ??

    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
    }

[if there are minor typing errors in that, it is because it was written as a summary of the method.] This method that I've tried to use has not been very successful, and I'm pretty sure it has to do with inheritance. Any ideas? Entire source code:

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

As others have mentioned, it would be best to try to use some of the existing wrappers.

That said, you need to use pointers for your list of entities. You are having issues with slicing .

As some of the comments mentioned, you need to make Drawable::draw() virtual so calling draw() on a Drawable will call through to the child implementation. That said, because you are adding your Drawable s to a an list of objects, instead of a list of pointers to objects, the objects are being sliced. This means that they are being converted from the child type back into Drawable objects, removing the extra information about specific types.

So instead of this:

Drawable ents[200];

You should do something like this:

std::vector<Drawable*> ents;

or if you have C++11 or Boost:

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

And your append method would take a reference.

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

or

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

or

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

And your render loop would be like this:

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

This loop could also be cleaned up to use iterator .

I've been trying to write something that will let me easily manage OpenGL using classes.

Newbies often try this. But OpenGL really doesn't translate well into OOP. The problem is, that it's a finite state machine and to map properly to OOP you'd have to to a lot of state tracking between the different classes and instances.

I myself tried at least 3 times to abstract OpenGL into a OOP scheme. It always broke in some way.

Which is not to say that you can not use OOP with OpenGL. You can't just map OpenGL concepts 1:1 into classes.


Regarding your actual problem: Use virtual functions.

You might want to have a look at Coin3D . It is a large rich set of C++ class wrappers around OpenGL. You clould either look at how they do things of just use it. There are libraries for integration with various windowing systems (Qt, Windows, Cocoa, ...).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM