00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00024
00026
00028 #include <SFML/Graphics/Image.hpp>
00029 #include <SFML/Graphics/ImageLoader.hpp>
00030 #include <SFML/Graphics/GraphicsDevice.hpp>
00031 #include <SFML/Graphics/OpenGL.hpp>
00032 #include <SFML/Window/OpenGLCaps.hpp>
00033 #include <algorithm>
00034 #include <iostream>
00035 #include <vector>
00036
00037
00038 namespace sf
00039 {
00043 Image::Image() :
00044 myWidth (0),
00045 myHeight (0),
00046 myTextureWidth (0),
00047 myTextureHeight(0),
00048 myGLTexture (0)
00049 {
00050
00051 }
00052
00053
00057 Image::Image(const Image& Copy) :
00058 VideoResource (Copy),
00059 myWidth (Copy.myWidth),
00060 myHeight (Copy.myHeight),
00061 myTextureWidth (Copy.myTextureWidth),
00062 myTextureHeight(Copy.myTextureHeight),
00063 myPixels (Copy.myPixels),
00064 myGLTexture (0)
00065 {
00066 CreateTexture();
00067 }
00068
00069
00073 Image::Image(unsigned int Width, unsigned int Height, const Color& Col) :
00074 myWidth (0),
00075 myHeight (0),
00076 myTextureWidth (0),
00077 myTextureHeight(0),
00078 myGLTexture (0)
00079 {
00080 Create(Width, Height, Col);
00081 }
00082
00083
00087 Image::Image(unsigned int Width, unsigned int Height, const void* Data) :
00088 myWidth (0),
00089 myHeight (0),
00090 myTextureWidth (0),
00091 myTextureHeight(0),
00092 myGLTexture (0)
00093 {
00094 LoadFromMemory(Width, Height, Data);
00095 }
00096
00097
00101 Image::~Image()
00102 {
00103
00104 DestroyVideoResources();
00105 }
00106
00107
00111 bool Image::LoadFromFile(const std::string& Filename)
00112 {
00113
00114 bool Success = priv::ImageLoader::GetInstance().LoadImageFromFile(Filename, myPixels, myWidth, myHeight);
00115
00116 if (Success)
00117 {
00118
00119 CreateTexture();
00120
00121 return true;
00122 }
00123 else
00124 {
00125
00126 myWidth = 0;
00127 myHeight = 0;
00128 myTextureWidth = 0;
00129 myTextureHeight = 0;
00130 myGLTexture = 0;
00131 myPixels.clear();
00132
00133 return false;
00134 }
00135 }
00136
00137
00141 bool Image::SaveToFile(const std::string& Filename) const
00142 {
00143
00144 return priv::ImageLoader::GetInstance().SaveImageToFile(Filename, myPixels, myWidth, myHeight);
00145 }
00146
00147
00151 void Image::Create(unsigned int Width, unsigned int Height, const Color& Col)
00152 {
00153
00154 myWidth = Width;
00155 myHeight = Height;
00156
00157
00158 myPixels.clear();
00159 myPixels.resize(Width * Height, Col.ToRGBA());
00160
00161
00162 CreateTexture();
00163 }
00164
00165
00169 void Image::LoadFromMemory(unsigned int Width, unsigned int Height, const void* Data)
00170 {
00171 if (Data)
00172 {
00173
00174 myWidth = Width;
00175 myHeight = Height;
00176
00177
00178 const Uint32* Ptr = reinterpret_cast<const Uint32*>(Data);
00179 myPixels.assign(Ptr, Ptr + Width * Height);
00180
00181
00182 CreateTexture();
00183 }
00184 else
00185 {
00186
00187 Create(Width, Height, Color(255, 255, 255, 255));
00188 }
00189 }
00190
00191
00195 void Image::CreateMaskFromColor(const Color& ColorKey, Uint8 Alpha)
00196 {
00197
00198 Uint32 OldColor = ColorKey.ToRGBA();
00199 Uint32 NewColor = (OldColor & 0x00FFFFFF) | (Alpha << 24);
00200
00201
00202 std::replace(myPixels.begin(), myPixels.end(), OldColor, NewColor);
00203
00204
00205 Update();
00206 }
00207
00208
00213 void Image::Resize(unsigned int Width, unsigned int Height, const Color& Col)
00214 {
00215
00216 if ((Width == 0) || (Height == 0))
00217 {
00218 std::cerr << "Invalid new size for image (width = " << Width << ", height = " << Height << ")" << std::endl;
00219 return;
00220 }
00221
00222
00223 std::vector<Uint32> Pixels(Width * Height, Col.ToRGBA());
00224
00225
00226 for (unsigned int i = 0; i < std::min(Width, myWidth); ++i)
00227 for (unsigned int j = 0; j < std::min(Height, myHeight); ++j)
00228 Pixels[i + j * Width] = myPixels[i + j * myWidth];
00229 Pixels.swap(myPixels);
00230
00231
00232 myWidth = Width;
00233 myHeight = Height;
00234
00235
00236 CreateTexture();
00237 }
00238
00239
00244 void Image::SetPixel(unsigned int X, unsigned int Y, const Color& Col)
00245 {
00246
00247 if ((X >= myWidth) || (Y >= myHeight))
00248 {
00249 std::cerr << "Cannot set pixel (" << X << "," << Y << ") for image "
00250 << "(width = " << myWidth << ", height = " << myHeight << ")" << std::endl;
00251 return;
00252 }
00253
00254 myPixels[X + Y * myWidth] = Col.ToRGBA();
00255 }
00256
00257
00261 Color Image::GetPixel(unsigned int X, unsigned int Y) const
00262 {
00263
00264 if ((X >= myWidth) || (Y >= myHeight))
00265 {
00266 std::cerr << "Cannot get pixel (" << X << "," << Y << ") for image "
00267 << "(width = " << myWidth << ", height = " << myHeight << ")" << std::endl;
00268 return Color::Black;
00269 }
00270
00271 return Color(myPixels[X + Y * myWidth]);
00272 }
00273
00274
00280 const Uint32* Image::GetPixelsPtr() const
00281 {
00282 if (!myPixels.empty())
00283 {
00284 return &myPixels[0];
00285 }
00286 else
00287 {
00288 std::cerr << "Trying to access the pixels of an empty image" << std::endl;
00289 return NULL;
00290 }
00291 }
00292
00293
00297 void Image::Update()
00298 {
00299 if (myGLTexture && myWidth && myHeight && !myPixels.empty())
00300 {
00301
00302 GLCheck(glBindTexture(GL_TEXTURE_2D, myGLTexture));
00303 GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myWidth, myHeight, GL_RGBA, GL_UNSIGNED_BYTE, &myPixels[0]));
00304 GLCheck(glBindTexture(GL_TEXTURE_2D, 0));
00305 }
00306 }
00307
00308
00312 void Image::Bind() const
00313 {
00314
00315 if (myGLTexture)
00316 {
00317 GLCheck(glEnable(GL_TEXTURE_2D));
00318 GLCheck(glBindTexture(GL_TEXTURE_2D, myGLTexture));
00319 }
00320 }
00321
00322
00326 void Image::SetSmooth(bool Smooth) const
00327 {
00328 if (myGLTexture)
00329 {
00330
00331 GLCheck(glBindTexture(GL_TEXTURE_2D, myGLTexture));
00332 GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Smooth ? GL_LINEAR : GL_NEAREST));
00333 GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Smooth ? GL_LINEAR : GL_NEAREST));
00334 GLCheck(glBindTexture(GL_TEXTURE_2D, 0));
00335 }
00336 }
00337
00338
00343 void Image::SetRepeat(bool Repeat) const
00344 {
00345 if (myGLTexture)
00346 {
00347
00348 GLCheck(glBindTexture(GL_TEXTURE_2D, myGLTexture));
00349 GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, Repeat ? GL_REPEAT : GL_CLAMP));
00350 GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, Repeat ? GL_REPEAT : GL_CLAMP));
00351 GLCheck(glBindTexture(GL_TEXTURE_2D, 0));
00352 }
00353 }
00354
00355
00359 unsigned int Image::GetWidth() const
00360 {
00361 return myWidth;
00362 }
00363
00364
00368 unsigned int Image::GetHeight() const
00369 {
00370 return myHeight;
00371 }
00372
00373
00378 FloatRect Image::GetTexCoords(const IntRect& Rect) const
00379 {
00380 return FloatRect((Rect.Left + 0.5f) / myTextureWidth,
00381 (Rect.Top + 0.5f) / myTextureHeight,
00382 (Rect.Right - 0.5f) / myTextureWidth,
00383 (Rect.Bottom - 0.5f) / myTextureHeight);
00384 }
00385
00386
00390 unsigned int Image::GetValidTextureSize(unsigned int Size)
00391 {
00392 if (OpenGLCaps::CheckExtension("GL_ARB_texture_non_power_of_two"))
00393 {
00394
00395 return Size;
00396 }
00397 else
00398 {
00399
00400 unsigned int PowerOfTwo = 1;
00401 while (PowerOfTwo < Size)
00402 PowerOfTwo *= 2;
00403
00404 return PowerOfTwo;
00405 }
00406 }
00407
00408
00412 Image& Image::operator =(const Image& Other)
00413 {
00414 Image Temp(Other);
00415
00416 std::swap(myWidth, Temp.myWidth);
00417 std::swap(myHeight, Temp.myHeight);
00418 std::swap(myTextureWidth, Temp.myTextureWidth);
00419 std::swap(myTextureHeight, Temp.myTextureHeight);
00420 std::swap(myGLTexture, Temp.myGLTexture);
00421 myPixels.swap(Temp.myPixels);
00422
00423 return *this;
00424 }
00425
00426
00430 void Image::CreateTexture()
00431 {
00432
00433 if (!myWidth || !myHeight || myPixels.empty())
00434 return;
00435
00436
00437 if (myGLTexture)
00438 {
00439 GLCheck(glDeleteTextures(1, (GLuint*)&myGLTexture));
00440 myGLTexture = 0;
00441 }
00442
00443
00444 myTextureWidth = GetValidTextureSize(myWidth);
00445 myTextureHeight = GetValidTextureSize(myHeight);
00446
00447
00448 GLCheck(glGenTextures(1, (GLuint*)&myGLTexture));
00449 GLCheck(glBindTexture(GL_TEXTURE_2D, myGLTexture));
00450 GLCheck(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, myTextureWidth, myTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
00451
00452
00453 GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
00454 GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
00455 GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
00456 GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
00457
00458
00459 Update();
00460 }
00461
00462
00466 void Image::DestroyVideoResources()
00467 {
00468
00469 if (myGLTexture)
00470 {
00471 GLCheck(glDeleteTextures(1, (GLuint*)&myGLTexture));
00472 myGLTexture = 0;
00473 }
00474 }
00475
00476 }