//! This is a handy function that will break if at any point//! OpenGL signals an error.#define paint_check_error() plgl_checkerror_wrapped(__LINE__, __FILE__, __func__)void paint_check_error_wrapped(unsigned int line, const char* file, const char* function) { // see if we have an error GLenum error = glGetError(); if (!error) return; // print out a readable version const char* errorstr = "unrecognized error code"; switch (error) { case GL_INVALID_ENUM: errorstr = "GL_INVALID_ENUM"; break; case GL_INVALID_VALUE: errorstr = "GL_INVALID_VALUE"; break; case GL_INVALID_OPERATION: errorstr = "GL_INVALID_OPERATION"; break; case GL_STACK_OVERFLOW: errorstr = "GL_STACK_OVERFLOW"; break; case GL_STACK_UNDERFLOW: errorstr = "GL_STACK_UNDERFLOW"; break; case GL_OUT_OF_MEMORY: errorstr = "GL_OUT_OF_MEMORY"; break; default: break; } printf("OpenGL error %i = \"%s\" at %s:%u in %s()\n", (int)error, errorstr, file, line, function); // in DEBUG mode, halt the program here assert(0);}//! This is where we'll put the coordinates for whatever quad we//! are currently rendering. OpenGL will pull the coordinates from//! here every time we ask it to render a quad.static GLfloat paint_rect_vertices[8];static GLfloat paint_rect_texcoors[8];//! Sets up OpenGL for rendering 2D quads.void paint_setup(void) { float width = screen_width(); float height = screen_height(); // set up an orthographic projection glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthof(0, width, height, 0, -1000, 1000); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); paint_check_error(); // assign a texture quad glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glEnable(GL_TEXTURE_2D); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glVertexPointer (2, GL_FLOAT, 0, paint_rect_vertices); glTexCoordPointer(2, GL_FLOAT, 0, paint_rect_texcoors); paint_check_error(); // miscellaneous 2d stuff glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_LIGHTING); glDisable(GL_CULL_FACE); paint_check_error();}//! Paints a quad. The given source coordinates from the texture are//! painted onto the destination coordinates.void paint_rect(GLint textureid, float dx, float dy, float dw, float dh, float sx, float sy, float sw, float sh) { // bind our texture glBindTexture(GL_TEXTURE_2D, textureid); paint_check_error(); // set our destination coordinates paint_rect_vertices[0] = dx; paint_rect_vertices[1] = dy; paint_rect_vertices[2] = dx; paint_rect_vertices[3] = dy + dh; paint_rect_vertices[4] = dx + dw; paint_rect_vertices[5] = dy; paint_rect_vertices[6] = dx + dw; paint_rect_vertices[7] = dy + dh; // set our source texture coordinates paint_rect_texcoors[0] = sx; paint_rect_texcoors[1] = sy; paint_rect_texcoors[2] = sx; paint_rect_texcoors[3] = sy + sh; paint_rect_texcoors[4] = sx + sw; paint_rect_texcoors[5] = sy; paint_rect_texcoors[6] = sx + sw; paint_rect_texcoors[7] = sy + sh; // draw it glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); paint_check_error();}GLint paint_load_texture(const char* filename) { // this is often provided by your window abstraction layer, like // SDL or SFML, so just wrap their function for loading textures // here. if not it's easy to just wrap libpng. // // remember that texture sizes have to be power of 2, and your // texture coordinates have to reflect that. what i do is i have // some extra code to pad your textures at load time, and when such // a texture is bound, a matrix is pushed onto GL_TEXTURE to // correct for the padding.}