00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 #include "guichan/opengl/openglimage.hpp"
00062
00063 #include "guichan/exception.hpp"
00064
00065 namespace gcn
00066 {
00067 OpenGLImage::OpenGLImage(unsigned int* pixels, int width, int height,
00068 bool convertToDisplayFormat)
00069 {
00070 mAutoFree = true;
00071
00072 mWidth = width;
00073 mHeight = height;
00074 mTextureWidth = 1, mTextureHeight = 1;
00075
00076 while(mTextureWidth < mWidth)
00077 {
00078 mTextureWidth *= 2;
00079 }
00080
00081 while(mTextureHeight < mHeight)
00082 {
00083 mTextureHeight *= 2;
00084 }
00085
00086
00087 mPixels = new unsigned int[mTextureWidth * mTextureHeight];
00088
00089 #ifdef __BIG_ENDIAN__
00090 const unsigned int magicPink = 0xff00ffff;
00091 #else
00092 const unsigned int magicPink = 0xffff00ff;
00093 #endif
00094 int x, y;
00095 for (y = 0; y < mTextureHeight; y++)
00096 {
00097 for (x = 0; x < mTextureWidth; x++)
00098 {
00099 if (x < mWidth && y < mHeight)
00100 {
00101 unsigned int c = pixels[x + y * mWidth];
00102
00103
00104 if (c == magicPink)
00105 {
00106 c = 0x00000000;
00107 }
00108
00109 mPixels[x + y * mTextureWidth] = c;
00110 }
00111 else
00112 {
00113 mPixels[x + y * mTextureWidth] = 0x00000000;
00114 }
00115 }
00116 }
00117
00118 if (convertToDisplayFormat)
00119 {
00120 OpenGLImage::convertToDisplayFormat();
00121 }
00122 }
00123
00124 OpenGLImage::OpenGLImage(GLuint textureHandle, int width, int height, bool autoFree)
00125 {
00126 mTextureHandle = textureHandle;
00127 mAutoFree = autoFree;
00128 mPixels = NULL;
00129
00130 mWidth = width;
00131 mHeight = height;
00132 mTextureWidth = 1, mTextureHeight = 1;
00133
00134 while(mTextureWidth < mWidth)
00135 {
00136 mTextureWidth *= 2;
00137 }
00138
00139 while(mTextureHeight < mHeight)
00140 {
00141 mTextureHeight *= 2;
00142 }
00143 }
00144
00145 OpenGLImage::~OpenGLImage()
00146 {
00147 if (mAutoFree)
00148 {
00149 free();
00150 }
00151 }
00152
00153 GLuint OpenGLImage::getTextureHandle() const
00154 {
00155 return mTextureHandle;
00156 }
00157
00158 int OpenGLImage::getTextureWidth() const
00159 {
00160 return mTextureWidth;
00161 }
00162
00163 int OpenGLImage::getTextureHeight() const
00164 {
00165 return mTextureHeight;
00166 }
00167
00168 void OpenGLImage::free()
00169 {
00170 if (mPixels != NULL)
00171 {
00172 glDeleteTextures(1, &mTextureHandle);
00173 }
00174 else
00175 {
00176 delete[] mPixels;
00177 mPixels = NULL;
00178 }
00179 }
00180
00181 int OpenGLImage::getWidth() const
00182 {
00183 return mWidth;
00184 }
00185
00186 int OpenGLImage::getHeight() const
00187 {
00188 return mHeight;
00189 }
00190
00191 Color OpenGLImage::getPixel(int x, int y)
00192 {
00193 if (mPixels == NULL)
00194 {
00195 throw GCN_EXCEPTION("Image has been converted to display format");
00196 }
00197
00198 if (x < 0 || x >= mWidth || y < 0 || y >= mHeight)
00199 {
00200 throw GCN_EXCEPTION("Coordinates outside of the image");
00201 }
00202
00203 unsigned int c = mPixels[x + y * mTextureWidth];
00204
00205 #ifdef __BIG_ENDIAN__
00206 unsigned char r = (c >> 24) & 0xff;
00207 unsigned char g = (c >> 16) & 0xff;
00208 unsigned char b = (c >> 8) & 0xff;
00209 unsigned char a = c & 0xff;
00210 #else
00211 unsigned char a = (c >> 24) & 0xff;
00212 unsigned char b = (c >> 16) & 0xff;
00213 unsigned char g = (c >> 8) & 0xff;
00214 unsigned char r = c & 0xff;
00215 #endif
00216
00217 return Color(r, g, b, a);
00218 }
00219
00220 void OpenGLImage::putPixel(int x, int y, const Color& color)
00221 {
00222 if (mPixels == NULL)
00223 {
00224 throw GCN_EXCEPTION("Image has been converted to display format");
00225 }
00226
00227 if (x < 0 || x >= mWidth || y < 0 || y >= mHeight)
00228 {
00229 throw GCN_EXCEPTION("Coordinates outside of the image");
00230 }
00231
00232 #ifdef __BIG_ENDIAN__
00233 unsigned int c = color.a | color.b << 8 | color.g << 16 | color.r << 24;
00234 #else
00235 unsigned int c = color.r | color.g << 8 | color.b << 16 | color.a << 24;
00236 #endif
00237
00238 mPixels[x + y * mTextureWidth] = c;
00239 }
00240
00241 void OpenGLImage::convertToDisplayFormat()
00242 {
00243 if (mPixels == NULL)
00244 {
00245 throw GCN_EXCEPTION("Image has already been converted to display format");
00246 }
00247
00248 glGenTextures(1, &mTextureHandle);
00249 glBindTexture(GL_TEXTURE_2D, mTextureHandle);
00250
00251 glTexImage2D(GL_TEXTURE_2D,
00252 0,
00253 4,
00254 mTextureWidth,
00255 mTextureHeight,
00256 0,
00257 GL_RGBA,
00258 GL_UNSIGNED_BYTE,
00259 mPixels);
00260
00261 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00262 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00263
00264 delete[] mPixels;
00265 mPixels = NULL;
00266
00267 GLenum error = glGetError();
00268 if (error)
00269 {
00270 std::string errmsg;
00271 switch (error)
00272 {
00273 case GL_INVALID_ENUM:
00274 errmsg = "GL_INVALID_ENUM";
00275 break;
00276
00277 case GL_INVALID_VALUE:
00278 errmsg = "GL_INVALID_VALUE";
00279 break;
00280
00281 case GL_INVALID_OPERATION:
00282 errmsg = "GL_INVALID_OPERATION";
00283 break;
00284
00285 case GL_STACK_OVERFLOW:
00286 errmsg = "GL_STACK_OVERFLOW";
00287 break;
00288
00289 case GL_STACK_UNDERFLOW:
00290 errmsg = "GL_STACK_UNDERFLOW";
00291 break;
00292
00293 case GL_OUT_OF_MEMORY:
00294 errmsg = "GL_OUT_OF_MEMORY";
00295 break;
00296 }
00297
00298 throw GCN_EXCEPTION(std::string("Unable to convert to OpenGL display format, glGetError said: ") + errmsg);
00299 }
00300 }
00301 }