![]() |
Unuk 1.0
|
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 }