#include #include #include #include #include #include #include "graphics.h" #include "core.h" using namespace std; namespace gp2d { // The one and only instance of the window. // Firstly initialized to NULL, or else we get some errors :) GP2DWindow* GP2DWindow::m_instance = NULL; GP2DWindow* GP2DWindow::getInstance() { if(m_instance == NULL) { // instance not already created? // then create it! m_instance = new GP2DWindow(); // Set the default video API to SDL m_instance->setRenderMode(GP2DWindow::GL2D_OPENGL); } // and return it. return m_instance; } /** * Create a window instance. Done by using GP2DWindow::getInstance(). */ GP2DWindow::GP2DWindow() { m_fullScreen = false; // initially, fullscreen mode is OFF. m_videoAPI = GP2DWindow::GL2D_OPENGL; // defaults to opengl rendering, rox more. } /** * Destructor. Deletes some resources occupied by this object. */ GP2DWindow::~GP2DWindow() { SDL_FreeSurface(m_surfaceScreen); } /** * Toggles fullscreen mode on, or off. Internally, a bool will be set stating * whether the screen is currently in fullscreen mode. */ void GP2DWindow::toggleFullScreen() throw(GP2DException) { m_fullScreen = !m_fullScreen; // flip the fullscreen boolean indication if(m_surfaceScreen != NULL) { SDL_WM_ToggleFullScreen(m_surfaceScreen); } else { throw GP2DException("Fullscreen toggle failed"); } } /** * Returns the height of the window. */ int GP2DWindow::getHeight() const { return m_screenHeight; } /** * Returns the width of the window. */ int GP2DWindow::getWidth() const { return m_screenWidth; } /** * Input grabbing of events. */ void GP2DWindow::setInputGrabEnabled(bool enabled) { if(enabled) { SDL_WM_GrabInput(SDL_GRAB_ON); } else { SDL_WM_GrabInput(SDL_GRAB_OFF); } } /** * Graphic defaults. Can be called at any time. */ void GP2DWindow::setGraphicsDefaults() { if(m_videoAPI == GP2D_SDL){ } else { glShadeModel(GL_SMOOTH); // smooth shading. glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // black is the default clearing color. glEnable(GL_LINE_SMOOTH); // smooth lining (anti aliasing?) glEnable(GL_POINT_SMOOTH); // point smoothing glEnable(GL_POLYGON_SMOOTH); // polygon smoothing glEnable(GL_TEXTURE_2D); // enable 2D texturisation. glEnable(GL_BLEND); // enable (alpha) blending. } } /** * Sets the window title. */ void GP2DWindow::setWindowTitle(string title) { SDL_WM_SetCaption(title.c_str(), NULL); } /** * Sets the no-frame flag. */ void GP2DWindow::setFlagNoFrame() { m_videoFlags |= SDL_NOFRAME; } /** * Sets resizable flag. */ void GP2DWindow::setFlagResizable() { m_videoFlags |= SDL_RESIZABLE; } /** * Clear the screen. */ void GP2DWindow::clearScreen() { GP2DWindow* window = GP2DWindow::getInstance(); if(window->getRenderMode() == GP2DWindow::GP2D_SDL){ } else { glClear(GL_COLOR_BUFFER_BIT); } } /** * Synchronize buffers. */ void GP2DWindow::sync() { GP2DWindow* window = GP2DWindow::getInstance(); if(window->getRenderMode() == GP2DWindow::GP2D_SDL){ } else { glFlush(); // for single buffer only SDL_GL_SwapBuffers(); // for double buffer only. } } /** * Check the status of the window if it is opened or not. */ bool GP2DWindow::isCreated() { return m_surfaceScreen != NULL ? true : false; } /** * Does the actual work. Will throw an exception if GP2DEngine::initVideo() or * GP2DEngine::initAll() was not called first. */ void GP2DWindow::createWindow(int width, int height, int bpp) throw(GP2DException) { const SDL_VideoInfo* m_videoInfo = SDL_GetVideoInfo(); if(m_videoInfo == NULL) { throw GP2DException("Unable to create a window: video was not initialized."); } if(m_videoAPI == GP2D_SDL){ m_videoFlags = SDL_HWPALETTE; // set default flags for SDL only } else { m_videoFlags = SDL_OPENGL | SDL_HWPALETTE; // set default flags for // OpenGL } // check to see if a surface can be stored in mem: if (m_videoInfo->hw_available) { m_videoFlags |= SDL_HWSURFACE; } else { m_videoFlags |= SDL_SWSURFACE; } // check to see if hardware blits can be done if (m_videoInfo->blit_hw) { m_videoFlags |= SDL_HWACCEL; } if(m_videoAPI == GP2D_SDL){ } else { // Sets up OpenGL double buffering SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true); } // check whether the video mode is supported. int modeOK = SDL_VideoModeOK(width, height, bpp, m_videoFlags); if(modeOK != 0) { // this next function actually OPENS the window too! m_surfaceScreen = SDL_SetVideoMode(width, height, bpp, m_videoFlags); m_screenWidth = width; m_screenHeight = height; m_screenDepth = bpp; } else { // video mode here is not supported. Throw up an exception so we know // it is not supported. stringstream s; s << "Video mode " << width << "x" << height << "x" << bpp << " is not supported. Bitmask video flags: " << m_videoFlags; throw GP2DException(s.str()); } } void GP2DWindow::setRenderMode(const GP2DRenderMode mode) { m_videoAPI = mode; } GP2DWindow::GP2DRenderMode GP2DWindow::getRenderMode() const { return m_videoAPI; } //============================================================================== /** * Create! */ GP2DCamera::GP2DCamera(int range) { initializeCamera(range); } /** * Destroy! */ GP2DCamera::~GP2DCamera() { } /** * Initializes the camera. */ void GP2DCamera::initializeCamera(int range) throw(GP2DException) { GP2DWindow* window = GP2DWindow::getInstance(); if(window->getRenderMode() == GP2DWindow::GP2D_SDL){ } else { m_range = range; if(!window->isCreated()) { // well, the window cannot be allocated. Be sure to notify the // programmer by throwing an exception. throw GP2DException("Window cannot be allocated."); } int height = window->getHeight(); int width = window->getWidth(); // no division by zeroes, plx! if (height == 0) { height = 1; } // the aspect ratio of the 'window' GLfloat aspectRatio = (GLfloat) width / (GLfloat)height; glViewport(0, 0, (GLsizei) width, (GLsizei) height); // make sure to change the projection matrix. glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width <= height) { glOrtho(-range, range, -range / aspectRatio, range / aspectRatio, -range, range); } else { glOrtho(-range * aspectRatio, range * aspectRatio, -range, range, -range, range); } // this translates the orthographic projection to the desired x and y. // don't know why exactly this works, but some website refer to it as 'working'. glTranslatef((float) getX(), (float) getY(), 0.0f); // change the modelview matrix, and load it. glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } } /** * Updates the camera view. */ void GP2DCamera::updateCamera() throw(GP2DException){ try { initializeCamera(m_range); } catch(GP2DException) { throw; // re-throw the exception. } } /** * Set range. */ void GP2DCamera::setRange(int range) { m_range = range; } /** * Get range. */ int GP2DCamera::getRange() const { return m_range; } /** * Sets x, y positions. */ void GP2DCamera::setPosition(float x, float y) { m_posX = x; m_posY = y; updateCamera(); } float GP2DCamera::getX() const { return m_posX; } float GP2DCamera::getY() const { return m_posY; } //============================================================================== GP2DTexture::GP2DTexture(string file) throw(GP2DException) { GP2DWindow* window = GP2DWindow::getInstance(); SDL_Surface* surf = IMG_Load(file.c_str()); if(surf != NULL) { if(window->getRenderMode() == GP2DWindow::GP2D_SDL){ m_surface = SDL_DisplayFormatAlpha(surf); m_width = m_surface->w; m_height = m_surface->h; m_pixels = m_surface->pixels; cout << "Texture loaded: " << file << ", " << m_width << "x" << m_height << endl; } else { m_surface = SDL_DisplayFormatAlpha(surf); glGenTextures(1, &m_texID); glBindTexture(GL_TEXTURE_2D, m_texID); glTexImage2D(GL_TEXTURE_2D, 0, 4, m_surface->w, m_surface->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, m_surface->pixels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); m_width = m_surface->w; m_height = m_surface->h; m_pixels = m_surface->pixels; cout << "Texture loaded (OGL): " << file << ", " << m_width << "x" << m_height << endl; // free the OLD surface, but do not free the alpha surface m_surface. SDL_FreeSurface(surf); } } else { // Something bad happened. IMG_GetError probably returns some useful // information, so throw an exception indicating the problem. It might // for instance be a file which can not be found. throw GP2DException("Texture creation failed", IMG_GetError()); } } /** * Deletes texture resources. */ GP2DTexture::~GP2DTexture() { GP2DWindow* window = GP2DWindow::getInstance(); if(window->getRenderMode() == GP2DWindow::GP2D_SDL){ SDL_FreeSurface(m_surface); } else { SDL_FreeSurface(m_surface); glDeleteTextures(1, &m_texID); } } unsigned int GP2DTexture::getId() const { return m_texID; } string GP2DTexture::getName() const { return m_texName; } float GP2DTexture::getWidth() const { return m_width; } float GP2DTexture::getHeight() const { return m_height; } void* GP2DTexture::getPixels() { return m_pixels; } SDL_Surface* GP2DTexture::getSurface() { return m_surface; } //============================================================================== /** * GP2DObject constructor. */ GP2DObject::GP2DObject() { m_x = 0.0f; // initialize the coordinates and all that to 0.0f. m_y = 0.0f; m_z = 0.0f; init(); } GP2DObject::GP2DObject(float x, float y) { m_x = x; m_y = y; m_z = 0.0f; init(); } GP2DObject::GP2DObject(float x, float y, float z) { m_x = x; m_y = y; m_z = z; init(); } /** * Destroy the object. Virtual destructor. */ GP2DObject::~GP2DObject() { } /** * Do some initializing here of local class members. */ void GP2DObject::init() { m_height = 0.0f; m_width = 0.0f; m_x_velocity = 0.0f; m_y_velocity = 0.0f; m_angle_X = 0.0f; m_angle_Y = 0.0f; m_angle_Z = 0.0f; } /* * Shitload of getters functions over here. */ float GP2DObject::getX() const { return m_x; } float GP2DObject::getY() const { return m_y; } float GP2DObject::getZ() const { return m_z; } float GP2DObject::getWidth() const { return m_width; } float GP2DObject::getHeight() const { return m_height; } float GP2DObject::getVelocity_X() const { return m_x_velocity; } float GP2DObject::getVelocity_Y() const { return m_y_velocity; } float GP2DObject::getRotation_X() const { return m_angle_X; } float GP2DObject::getRotation_Y() const { return m_angle_Y; } float GP2DObject::getRotation_Z() const { return m_angle_Z; } /* * Shitload of setter methods right here. */ void GP2DObject::setX(float x) { m_x = x; } void GP2DObject::setY(float y) { m_y = y; } void GP2DObject::setZ(float z) { m_z = z; } void GP2DObject::setWidth(float w) { m_width = w; } void GP2DObject::setHeight(float h) { m_height = h; } void GP2DObject::setVelocity_X(float xvel) { m_x_velocity = xvel; } void GP2DObject::setVelocity_Y(float yvel) { m_y_velocity = yvel; } void GP2DObject::setRotation_X(float angle) { m_angle_X = angle; } void GP2DObject::setRotation_Y(float angle) { m_angle_Y = angle; } void GP2DObject::setRotation_Z(float angle) { m_angle_Z = angle; } //============================================================================== GP2DSprite::GP2DSprite(GP2DTexture* texture) { m_texture = texture; setWidth(m_texture->getWidth()); setHeight(m_texture->getHeight()); } GP2DSprite::~GP2DSprite() { } void GP2DSprite::draw() { GP2DWindow* window = GP2DWindow::getInstance(); if(window->getRenderMode() == GP2DWindow::GP2D_SDL){ } else { // blending function, used to make alpha parts transparent or some sort. glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindTexture(GL_TEXTURE_2D, m_texture->getId()); // set the x and y positions based on the current velocity. setX(getX() + getVelocity_X()); setY(getY() + getVelocity_Y()); glMatrixMode(GL_MODELVIEW_MATRIX); glLoadIdentity(); glTranslatef(getX(), getY(), getZ()); glRotatef(getRotation_X(), 1.0f, 0.0f, 0.0f); glRotatef(getRotation_Y(), 0.0f, 1.0f, 0.0f); glRotatef(getRotation_Z(), 0.0f, 0.0f, 1.0f); float A=getWidth(); float B=getHeight(); float C=getZ(); glBegin(GL_QUADS); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // Set the sprite's alpha (for PNG) /* * The following texture coordinate mappings look retarded. This is * because SDL flips the textures, vertically. * * Vertices: Texture coordinates: * 1--4 2--3 * | | | | * 2--3 1--4 */ glTexCoord2f(0.0f, 0.0f); glVertex3f(0, 0, getZ()); glTexCoord2f(0.0f, 1.0f); glVertex3f(0, 0 - getHeight(), getZ()); glTexCoord2f(1.0f, 1.0f); glVertex3f(0 + getWidth(), 0 - getHeight(), getZ()); glTexCoord2f(1.0f, 0.0f); glVertex3f(0 + getWidth(), 0, getZ()); // Right face glTexCoord2f(1.0f, 0.0f); glVertex3f( A, -B, C-5.0); // Bottom Right Of The Texture and Quad glTexCoord2f(1.0f, 1.0f); glVertex3f( A, B, C-5.0); // Top Right Of The Texture and Quad glTexCoord2f(0.0f, 1.0f); glVertex3f( A, B, C); // Top Left Of The Texture and Quad glTexCoord2f(0.0f, 0.0f); glVertex3f( A, -B, C); // Bottom Left Of The Texture and Quad glEnd(); glDisable(GL_BLEND); // glBegin(GL_QUADS); // begin drawing a cube // // // Front Face (note that the texture's corners have to match the quad's corners) // // glTexCoord2f(0.0f, 0.0f); glVertex3f(-A, -B, C); // Bottom Left Of The Texture and Quad // // glTexCoord2f(1.0f, 0.0f); glVertex3f( A, -B, C); // Bottom Right Of The Texture and Quad // // glTexCoord2f(1.0f, 1.0f); glVertex3f( A, B, C); // Top Right Of The Texture and Quad // // glTexCoord2f(0.0f, 1.0f); glVertex3f(-A, B, C); // Top Left Of The Texture and Quad // // glColor3ub(255, 0, 0); // glVertex3f(-A, -B, C); // Bottom Left Of The Texture and Quad // glVertex3f( A, -B, C); // Bottom Right Of The Texture and Quad // glVertex3f( A, B, C); // Top Right Of The Texture and Quad // glVertex3f(-A, B, C); // Top Left Of The Texture and Quad // // // // /* // Back Face // glTexCoord2f(1.0f, 0.0f); glVertex3f(-A, -B, -C); // Bottom Right Of The Texture and Quad // glTexCoord2f(1.0f, 1.0f); glVertex3f(-A, B, -C); // Top Right Of The Texture and Quad // glTexCoord2f(0.0f, 1.0f); glVertex3f( A, B, -C); // Top Left Of The Texture and Quad // glTexCoord2f(0.0f, 0.0f); glVertex3f( A, -B, -C); // Bottom Left Of The Texture and Quad // // // Top Face // glTexCoord2f(0.0f, 1.0f); glVertex3f(-A, B, -C); // Top Left Of The Texture and Quad // glTexCoord2f(0.0f, 0.0f); glVertex3f(-A, B, C); // Bottom Left Of The Texture and Quad // glTexCoord2f(1.0f, 0.0f); glVertex3f( A, B, C); // Bottom Right Of The Texture and Quad // glTexCoord2f(1.0f, 1.0f); glVertex3f( A, B, -C); // Top Right Of The Texture and Quad // // // Bottom Face // glTexCoord2f(1.0f, 1.0f); glVertex3f(-A, -B, -C); // Top Right Of The Texture and Quad // glTexCoord2f(0.0f, 1.0f); glVertex3f( A, -B, -C); // Top Left Of The Texture and Quad // glTexCoord2f(0.0f, 0.0f); glVertex3f( A, -B, C); // Bottom Left Of The Texture and Quad // glTexCoord2f(1.0f, 0.0f); glVertex3f(-A, -B, C); // Bottom Right Of The Texture and Quad // // // // Left Face // glTexCoord2f(0.0f, 0.0f); glVertex3f(-A, -B, -C); // Bottom Left Of The Texture and Quad // glTexCoord2f(1.0f, 0.0f); glVertex3f(-A, -B, C); // Bottom Right Of The Texture and Quad // glTexCoord2f(1.0f, 1.0f); glVertex3f(-A, B, C); // Top Right Of The Texture and Quad // glTexCoord2f(0.0f, 1.0f); glVertex3f(-A, B, -C); // Top Left Of The Texture and Quad*/ // // glEnd(); // done with the polygon. // for debugging purposes, indicate a border of the sprite. glLineWidth(0.125f); glBegin(GL_LINES); // top left to right glColor3f(0.5f, 0.5f, 0.5f); glVertex3f(0.0f, 0.0f, -5.0f); glColor3f(0.5f, 0.5f, 0.5f); glVertex3f(getWidth(), 0.0f, -5.0f); // top left to bottom left glColor3f(0.5f, 0.5f, 0.5f); glVertex3f(0.0f, 0.0f, -5.0f); glColor3f(0.5f, 0.5f, 0.5f); glVertex3f(0.0f, -getHeight(), -5.0f); // bottom left to bottom right glColor3f(0.5f, 0.5f, 0.5f); glVertex3f(0.0f, -getHeight(), -5.0f); glColor3f(0.5f, 0.5f, 0.5f); glVertex3f(getWidth(), -getHeight(), -5.0f); // bottom right to top right glColor3f(0.5f, 0.5f, 0.5f); glVertex3f(getWidth(), -getHeight(), -5.0f); glColor3f(0.5f, 0.5f, 0.5f); glVertex3f(getWidth(), 0, -5.0f); glEnd(); // and some points. glColor3f(1.0f, 1.0f, 1.0f); glPointSize(4.125f); glBegin(GL_POINTS); glVertex3f(0.0f, 0.0f, -4.0f); glVertex3f(getWidth(), 0.0f, -4.0f); glVertex3f(0.0f, -getHeight(), -4.0f); glVertex3f(getWidth(), -getHeight(), -4.0f); glEnd(); } } } // namespace gp2d