Holy crap. Do you realize how much work you've done for
nothing ?
For starters, here are your rectangle and triangle types. I have added GL-related functions to them so that they're easier to use.
struct point2d { float x, y; point2d(float x, float y) : x(x), y(y) {} void gl() const { glVertex2f(x,y); }};struct point3d { float x, y, z; point3d(float x, float y, float z) : x(x), y(y), z(z) {} void gl() const { glVertex3f(x,y,z); }};struct color { float r, g, b; color(float r, float g, float b) : r(r), g(g), b(b) {} void gl() const { glColor3f(r,g,b); }}template<typename Point, int N>struct polygon{ Point vertices[N]; color colors[N]; void set(unsigned i, const Point &p, const color &c) { assert (i < N); vertices = p; colors = c; } void gl() const { for (int i = 0; i < N; ++i) { vertices.gl(); colors.gl(); } } // copy constructor is implemented by the compiler automatically. // operator= is implemented by the compiler automatically.};typedef polygon<point2d,4> rectangle2d;typedef polygon<point3d,3> triangle;typedef polygon<point3d,4> rectangle;template<typename T> void gl(const T & t) { t.gl(); }
Then, there's your API_COM1, which contains several errors:
struct API_COM1 // What does that name mean?{triangle* mesh; // Use 'std::vector' !rectangle* bmesh;int tri; int rect;float tx,ty,tz; // Use 'point3d' !float ax,ay,az;void operator=(API_COM1 com) // Pass argument by reference!{if(mesh!=NULL) // You can delete null pointers!{delete mesh; // Do you really own this pointer?}if(bmesh!=NULL){delete bmesh;}mesh=com.mesh; // What if you assign an object to itself?bmesh=com.bmesh;rect=com.rect;tri=com.tri;tx=com.tx;ty=com.ty;tz=com.tz;ax=com.ax;ay=com.ay;az=com.az;}};
And the corrected version, including GL rendering.
struct mesh3d{ std::vector<triangle> tris; std::vector<rectangle> quads; point3d angle, position; void gl() const { const point3d & a = angle, & t = position; glLoadIdentity(); glTranslatef(t.x, t.y, t.z); glRotatef(a.x,1.0f,0.0f,0.0f); glRotatef(a.y,0.0f,1.0f,0.0f); glRotatef(a.z,0.0f,0.0f,1.0f); glBegin(GL_TRIANGLES); std::for_each(tris.begin(), tris.end(), gl); glEnd(); glBegin(GL_QUADS); std::for_each(quads.begin(), quads.end(), gl); glEnd(); } // operator= and copy constructor are automatically // implemented.};std::vector<rectangle2d> mesh2d;void gl(const mesh2d &m){ glLoadIdentity(); glBegin(GL_QUADS); std::for_each(m.begin(), m.end(), gl); glEnd();}
Of course, this is completely ignoring any design issues you have here, for instance the complete lack of encapsulation, or the fact that you are designing objects in terms of "what data they contain" instead of "how they are used and what they do".
Then, there's the issue of your main API class...
class API{ SQL_Surface *window;public: std::vector<mesh3d> meshes3d; std::vector<mesh2d> meshes2d; API(int w, int h, int depth) { meshes3d.resize(10000); meshes2d.resize(1000); if (h == 0) h = 1; SDL_Init(SDL_INIT_VIDEO); try { const SDL_VideoInfo* vinf = SDL_GetVideoInfo(); const int vid = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE | (vinf -> hwavailable ? SDL_HWSURFACE : SDL_SWSURFACE) | (vinf -> blit_hw ? SDL_HWACCEL : 0); this->window = SDL_SetVideoMode(h,w,depth,vid); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); glShadeModel(GL_SMOOTH); glClearColor(0.0f,0.0f,0.5f,0.0f); glClearDepth(5.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); glViewport(0,0,(GLsizei)h,(GLsizei)w); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,(float)x/(float)y,0.1f,100.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } catch(...) { SQL_Quit(); throw; } } ~API() { SDL_QUIT(); } void render() const { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); std::for_each(meshes3d.begin(), meshes3d.end(), gl); std::for_each(meshes2d.begin(), meshes2d.end(), gl); glFlush(); SDL_GL_SwapBuffers(); }};
I've forcibly moved "waiting" out of there. Plus, I have added no error-checking.
struct EventScanner{ bool QUIT, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MOVE; struct { int x, y } MOUSE; EventScanner() { QUIT = KEY_UP = KEY_DOWN = KEY_LEFT = KEY_RIGHT = MOUSE_LEFT = MOUSE_RIGHT = MOUSE_MOVE = false; MOUSE.x = MOUSE.y = 0; } void scan() { MOUSE_MOVE = false; SDL_Event event; bool down; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: QUIT = true; break; case SDL_KEYDOWN: case SDL_KEYUP: down = (event.type == SDL_KEYDOWN); switch (event.key.keysym.sym) { case SDLK_UP: KEY_UP = down; break; case SDLK_DOWN: KEY_DOWN = down; break; case SDLK_LEFT: KEY_LEFT = down; break; case SDLK_RIGHT: KEY_RIGHT = down; break; } break; case SDL_MOUSEMOTION: MOUSE_MOVE = true; MOUSE.x = event.motion.x; MOUSE.y = event.motion.y; break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: down = (event.type == SDL_MOUSEBUTTONDOWN); switch(event.button.button) { case SDL_BUTTON_LEFT: MOUSE_LEFT = down; break; case SDL_BUTTON_RIGHT: MOUSE_RIGHT = down; break; } break; default: break; } } }};
I've factored similar cases using a "down" boolean variable, and also used chain assignment. You could consider using an integer point2d to represent the mouse position, or convert it to floating-point.
When your source gets to "GL_Object", things are starting to get confused. There's a lot of work being done that is completely useless (such as reinventing std::vector several times), objects not being destroyed properly, temporary values, confusions between buffers and single pointed objects, and so on, and I wonder if you actually know, yourself, what the code is meant to do. Though, I'll use:
class mesh3d_ref { API & api; index i;public: mesh3d_ref(API & api, unsigned index) : api(api), i(index) {} mesh3d* operator ->() { return &api.meshes3d; }};
Of course, this is suboptimal (how do you handle object removal?) but I'm not trying to write an entire engine here.
Which brings us to the test file:
int main(){ API api(500,500,32); api.meshes3d.resize(1); mesh3d_ref mesh(api, 0); triangle t1 = { { { -1f, 0f, 0f }, { 0f, 1f, 0f }, { 1f, 0f, 0f } }, { { 1f, 0f, 0f }, { 0f, 1f, 0f }, { 0f, 0f, 1f } } }; triangle t2 = { { { -1f, 0f, -2f }, { 0f, 1f, -2f }, { 1f, 0f, -2f } }, { { 1f, 0f, 0f }, { 0f, 1f, 0f }, { 0f, 0f, 1f } } }; mesh -> tris.push_back(t1); mesh -> tris.push_back(t2); rectangle r1 = { { { -1f,0f,0f }, { -1f,0f,-2f }, { 1f,0f,-2f }, { 1f,0f,0f } }, { { 1f,0f,0f }, { 1f,0f, 0f }, { 0f,0f, 1f }, { 0f,0f,1f } } }; rectangle r2 = { { { 0f,1f,0f }, { 0f,1f,-2f }, { 1f,0f,-2f }, { 1f,0f,0f } }, { { 0f,1f,0f }, { 0f,1f, 0f }, { 0f,0f, 1f }, { 0f,0f,1f } } }; rectangle r3 = { { { -1f,0f,0f }, { -1f,0f,-2f }, { 0f,1f,-2f }, { 0f,1f,0f } }, { { 1f,0f,0f }, { 1f,0f, 0f }, { 0f,1f, 0f }, { 0f,1f,0f } } }; mesh -> quads.push_back(r1); mesh -> quads.push_back(r2); mesh -> quads.push_back(r3); EventScanner scanner; float rot = 0f, rotx = 0f, pos = 0f, dpos = -0.01; do { mesh -> position = point3d(pos, -0.1f, -10.0f); mesh -> angle = point3d(rotx, rot, 0.0f); rot += 1f; rotx += 0.5f; pos += dpos; dpos = (pos < -2f) ? 0.01f : (pos > 2f) ? -0.01f : dpos; api.render(); event.scan(); } while (!event.QUIT); }
Please note that this code contains exactly zero instances of 'new' and 'delete'.