src/libUnuk/Sprite.cpp
Go to the documentation of this file.

    00001 #include <GL/glut.h>
    00002 #include <iostream>
    00003 #include <cstring>
    00004 #include "Sprite.h"
    00005 #include "ImageLoader.h"
    00006 #include "Debug.h"
    00007
    00008 Sprite::Sprite(string filename) {
    00009   image = new ImageLoader(filename.c_str());
    00010   angle = 0;
    00011   x     = 0.0f;
    00012   y     = 0.0f;
    00013   SetPivot(0.0f, 0.0f);
    00014   SetScale(1.0f, 1.0f);
    00015 }
    00016
    00017 Sprite::~Sprite(void) {
    00018   delete image;
    00019 }
    00020
    00021 // Enable 2D drawing mode to draw our sprites. This function MUST be
    00022 // called before any sprite is drawn on screen using the Draw method.
    00023 void Sprite::Enable2D(void) {
    00024   GLint iViewport[4];
    00025
    00026   // Get a copy of the viewport.
    00027   glGetIntegerv(GL_VIEWPORT, iViewport);
    00028   glPushMatrix();
    00029   glLoadIdentity();
    00030
    00031   // Save a copy of the projection atrix so that we can restore
    00032   // it when it's time to do 3D rendering again.
    00033   glMatrixMode(GL_PROJECTION);
    00034   glPushMatrix();
    00035   glLoadIdentity();
    00036
    00037   // Set upt the orthographic projection.
    00038   glOrtho( iViewport[0], iViewport[0] + iViewport[2],
    00039             iViewport[1] + iViewport[3], iViewport[1], -1, 1);
    00040   glMatrixMode(GL_MODELVIEW);
    00041   glPushMatrix();
    00042   glLoadIdentity();
    00043
    00044   // Make sure depth testing and lighting are disabled for 2D rendering
    00045   //until we are finished rendering in 2D.
    00046   glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT);
    00047   glDisable(GL_DEPTH_TEST);
    00048   glDisable(GL_LIGHTING);
    00049 }
    00050
    00051 // Disables the 2D drawing. This can be called before you are done
    00052 // drawing all 2D sprites on screen using the Draw method.
    00053 void Sprite::Disable2D(void) {
    00054   glPopAttrib();
    00055   glMatrixMode(GL_PROJECTION);
    00056   glPopMatrix();
    00057   glMatrixMode(GL_MODELVIEW);
    00058   glPopMatrix();
    00059 }
    00060
    00061 // Initializes extensions, textures, render states, etc. before rendering.
    00062 void Sprite::InitScene(void) {
    00063   // Disable lighting.
    00064   glDisable(GL_LIGHTING);
    00065   // Disable dithering.
    00066   glDisable(GL_DITHER);
    00067   // Disable blending (for now).
    00068   glDisable(GL_BLEND);
    00069   // Disable depth testing.
    00070   glDisable(GL_DEPTH_TEST);
    00071
    00072   // Is the extension supported on this driver/card?
    00073   if(!IsExtensionSupported("GL_ARB_texture_rectangle")) {
    00074     Debug::logger->message("\nERROR: Texture rectangles not supported on this video card!");
    00075     exit(-1);
    00076   }
    00077
    00078   // TODO:
    00079   // If your machine does not support GL_NV_texture_rectangle, you can try
    00080   // using GL_EXT_texture_rectangle. Maybe I will run a test so I can support both.
    00081
    00082   // Enable the texture rectangle extension.
    00083   glEnable(GL_TEXTURE_RECTANGLE_ARB);
    00084
    00085   // Generate one texture ID.
    00086   glGenTextures(1, &textureID);
    00087   // Bind the texture using GL_TEXTURE_RECTANGLE_NV
    00088   glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textureID);
    00089   // Enable bilinear filtering on this texture.
    00090   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    00091   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    00092
    00093   // Write the 32-bit RGBA texture buffer to video memory.
    00094   glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, image->GetWidth(), image->GetHeight(),
    00095                 0, GL_RGBA, GL_UNSIGNED_BYTE, image->GetPixelData());
    00096 }
    00097
    00098 // =================================================================
    00099 // Set the pivot point in relation to the sprite itself, that is
    00100 // using the object coordinates system. In this coordinate system
    00101 // the bottom left point of the object is at (0,0) and the top
    00102 // right is at (1,1).
    00103 //
    00104 // Example: To set the pivot to be in the middle of the sprite use
    00105 // (0.5, 0.5) default values are (1,1).
    00106 // pivotX can be any value, but when x is in the range [0,1] the
    00107 // pivot is inside the sprite where 0 is the left edge of the sprite
    00108 // and 1 is the right edge of the sprite.
    00109 // pivotY is the same as pivotX but when y is in the range of [0,1]
    00110 // the pivot is inside the sprite where 0 is the bottom edge of the
    00111 // sprite and 1 is the top edge of the sprite.
    00112 // =================================================================
    00113 void Sprite::SetPivot(GLfloat pivotX, GLfloat pivotY) {
    00114   GLfloat deltaPivotX = pivotX - GetPivotX();
    00115   GLfloat deltaPivotY = pivotY - GetPivotY();
    00116
    00117   this->pivotX = pivotX;
    00118   this->pivotY = pivotY;
    00119
    00120   x += deltaPivotX * image->GetWidth();
    00121   y += deltaPivotY * image->GetHeight();
    00122 }
    00123
    00124 // =================================================================
    00125 // Sets the pivot to be at the point where object's pivot is set.
    00126 // obj is the reference object to whose pivot we will set this pivot
    00127 // to be.
    00128 // Note: If the obj pivot changes or the obj moves after the SetPivot
    00129 // call has been issued, the pivot of this object will not reflect these
    00130 // changes. You must call SetPivot again with that object to update the
    00131 // pivot information.
    00132 // =================================================================
    00133 void Sprite::SetPivot(const Sprite &obj) {
    00134   // This x location if the pivot was at SetPivot(0, 0);
    00135   GLint worldX;
    00136   // This y location it the pivot was at SetPivot(0, 0);
    00137   GLint worldY;
    00138   GLfloat newPivotX;
    00139   GLfloat newPivotY;
    00140
    00141   worldX = x - GetPivotX() * image->GetWidth();
    00142   worldY = y - GetPivotY() * image->GetHeight();
    00143
    00144   newPivotX = (float)(obj.x - worldX) / image->GetWidth();
    00145   newPivotY = (float)(obj.y - worldY) / image->GetHeight();
    00146
    00147   SetPivot(newPivotX, newPivotY);
    00148 }
    00149
    00150 // Help determine if an OpenGL extension is supported on the target machine
    00151 // at runtime.
    00152 bool Sprite::IsExtensionSupported(const char *extension) const {
    00153   const GLubyte *extensions = NULL;
    00154   const GLubyte *start;
    00155   GLubyte *where, *terminator;
    00156
    00157   // Extension names should not have spaces.
    00158   where = (GLubyte *) strchr(extension, ' ');
    00159
    00160   if (where || *extension == '\0')  {
    00161     return false;
    00162   }
    00163
    00164   extensions = glGetString(GL_EXTENSIONS);
    00165
    00166   // It takes a bit of care to be fool-proof about parsing the
    00167   // OpenGL extensions string. Don't be fooled by sub-strings, etc.
    00168   start = extensions;
    00169
    00170   for (;;)  {
    00171     where = (GLubyte *) strstr((const char *) start, extension);
    00172
    00173     if (!where) {
    00174        break;
    00175     }
    00176
    00177     terminator = where + strlen(extension);
    00178     if (where == start || *(where - 1) == ' ') {
    00179       if (*terminator == ' ' || *terminator == '\0') {
    00180         return true;
    00181       }
    00182     }
    00183
    00184     start = terminator;
    00185   }
    00186
    00187   return false;
    00188 }
    00189
    00190 void Sprite::Render(void) {
    00191   InitScene();
    00192
    00193   glEnable(GL_BLEND);
    00194   glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    00195   glEnable(GL_TEXTURE_2D);
    00196
    00197   // Set the primitive color to white
    00198   glColor3f(1.0f, 1.0f, 1.0f);
    00199   // Bind the texture to the polygons
    00200   glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textureID);
    00201
    00202   glPushMatrix();
    00203
    00204   GLfloat transX = 1;
    00205   GLfloat transY = 1;
    00206
    00207   if(x != 0.0) {
    00208     transX = x;
    00209   }
    00210
    00211   if(y != 0.0) {
    00212     transY = y;
    00213   }
    00214
    00215   glLoadIdentity();
    00216   glTranslatef(transX, transY, 0);
    00217   glScalef(scaleX, scaleY, 1.0);
    00218   glRotatef(angle, 0.0, 0.0, 1.0);
    00219
    00220   // =================================================================
    00221   // Render a quad
    00222   // Instead of the using (s,t) coordinates, with the GL_NV_texture_rectangle
    00223   // extension, you need to use the actual dimensions of the texture.
    00224   // This makes using 2D sprites for games and emulators much easier now
    00225   // that you won't have to convert :)
    00226   //
    00227   // convert the coordinates so that the bottom left corner changes to
    00228   // (0, 0) -> (1, 1) and the top right corner changes from (1, 1) -> (0, 0)
    00229   // we will use this new coordinate system to calculate the location of the sprite
    00230   // in the world coordinates to do the rotation and scaling. This mapping is done in
    00231   // order to make implementation simpler in this class and let the caller keep using
    00232   // the standard OpenGL coordinates system (bottom left corner at (0, 0))
    00233   // =================================================================
    00234   glBegin(GL_QUADS);
    00235     glTexCoord2i(0, 0);
    00236     glVertex2i(-pivotX * image->GetWidth(), -pivotY * image->GetHeight());
    00237
    00238     glTexCoord2i(0, image->GetHeight());
    00239     glVertex2i(-pivotX * image->GetWidth(), (1 - pivotY) * image->GetHeight());
    00240
    00241     glTexCoord2i(image->GetWidth(), image->GetHeight());
    00242     glVertex2i( (1 - pivotX) * image->GetWidth(), (1 - pivotY) * image->GetHeight());
    00243
    00244     glTexCoord2i(image->GetWidth(), 0);
    00245     glVertex2i( (1 - pivotX) * image->GetWidth(), -pivotY * image->GetHeight());
    00246   glEnd();
    00247
    00248   glPopMatrix();
    00249 }

All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines