Unuk 1.0
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