📄 surface.cpp
字号:
//// Cross-platform free Puyo-Puyo clone.// Copyright (C) 2006, 2007 Emma's Software//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.//#if defined (HAVE_CONFIG_H)#include <config.h>#endif // HAVE_CONFIG_H#include <assert.h>#include <math.h>#include <SDL.h>#include <SDL_image.h>#include <stdexcept>#include "Surface.h"#include "System.h"using namespace Amoebax;////// \brief Surface's default constructor.////// Makes an empty (NULL) surface.///Surface::Surface (void): m_SDLSurface (0){}////// \brief Creates a new surface with an already loaded SDL surface.////// \param SDLSurface The SDL surface that the class will have/// ownership of.///Surface::Surface (SDL_Surface *SDLSurface): m_SDLSurface (SDLSurface){}////// \brief Surface's copy constructor.////// \param surface The surface to copy from.///Surface::Surface (const Surface &surface): m_SDLSurface (0){ if ( 0 != surface.m_SDLSurface ) { SDL_Surface *tempSDLSurface = SDL_CreateRGBSurface (surface.m_SDLSurface->flags | SDL_SRCALPHA, surface.m_SDLSurface->w, surface.m_SDLSurface->h, surface.m_SDLSurface->format->BitsPerPixel, surface.m_SDLSurface->format->Rmask, surface.m_SDLSurface->format->Gmask, surface.m_SDLSurface->format->Bmask, surface.m_SDLSurface->format->Amask); if ( NULL == tempSDLSurface ) { throw std::runtime_error (SDL_GetError ()); } if ( SDL_BlitSurface (surface.m_SDLSurface, NULL, tempSDLSurface, NULL) < 0 ) { throw std::runtime_error (SDL_GetError ()); } std::swap (m_SDLSurface, tempSDLSurface); SDL_FreeSurface (tempSDLSurface); }}////// \brief Blits the whole surface to the left-top corner of destination.////// \param destination The distantion surface to blit this surface to.///voidSurface::blit (SDL_Surface *destination){ blit (0, 0, getWidth (), getHeight (), 0, 0, destination);}////// \brief Blits the whole surface to a position in destination.////// \param destinationX The X position where to blit the source into the/// destination./// \param destinationY The Y position where to blit the source into the/// destination./// \param destination The destination surface.///voidSurface::blit (uint16_t destinationX, uint16_t destinationY, SDL_Surface *destination){ blit (0, 0, getWidth (), getHeight (), destinationX, destinationY, destination);}////// \brief Blits a part of the surface into another surface.////// \param sourceX The X origin of the source surface to blit./// \param sourceY The X origin of the source surface to blit./// \param sourceWidth The width of the source surface part to blit./// \param sourceHeight The height of the source surface part to blit./// \param destinationX The X position where to blit the source into the/// destination./// \param destinationY The Y position where to blit the source into the/// destination./// \param destination The destination surface.///voidSurface::blit (uint16_t sourceX, uint16_t sourceY, uint16_t sourceWidth, uint16_t sourceHeight, uint16_t destinationX, uint16_t destinationY, SDL_Surface *destination){ SDL_Rect sourceRect; sourceRect.x = sourceX; sourceRect.y = sourceY; sourceRect.w = sourceWidth; sourceRect.h = sourceHeight; SDL_Rect destinationRect; destinationRect.x = destinationX; destinationRect.y = destinationY; destinationRect.w = sourceWidth; destinationRect.h = sourceHeight; SDL_BlitSurface (m_SDLSurface, &sourceRect, destination, &destinationRect); System::getInstance ().invalidateScreenRegion (&destinationRect);}////// \brief Surface's destructor.////// Frees the memory used by the image's surface.///Surface::~Surface (void){ SDL_FreeSurface (m_SDLSurface);}////// \brief Gets the height of the surface.////// \return Surface's height.///uint16_tSurface::getHeight (void) const{ return toSDLSurface ()->h;}////// \brief Gets the pixel color from a surface's position.////// \param x The x position to get the color from./// \param y The y position to get the color from./// \return The color at surface's \a x, \a y position.///uint32_tSurface::getPixel (uint16_t x, uint16_t y){ assert (x < m_SDLSurface->w && "Tried to get a color outside the surface."); assert (y < m_SDLSurface->h && "Tried to get a color outside the surface."); uint32_t pixelColor = 0; SDL_LockSurface (m_SDLSurface); switch (m_SDLSurface->format->BytesPerPixel) { case 1: pixelColor = static_cast<uint32_t>(*(static_cast<uint8_t *>(m_SDLSurface->pixels) + y * m_SDLSurface->pitch + x)); break; case 2: pixelColor = static_cast<uint32_t>(*(static_cast<uint16_t *>(m_SDLSurface->pixels) + y * m_SDLSurface->pitch / 2 + x)); break; case 3: { uint8_t *pixels = static_cast<uint8_t *>(m_SDLSurface->pixels) + y * m_SDLSurface->pitch + x * m_SDLSurface->format->BytesPerPixel; uint8_t red = *(pixels + m_SDLSurface->format->Rshift / 8); uint8_t green = *(pixels + m_SDLSurface->format->Gshift / 8); uint8_t blue = *(pixels + m_SDLSurface->format->Bshift / 8); pixelColor = SDL_MapRGB (m_SDLSurface->format, red, green, blue); } break; case 4: pixelColor = *(static_cast<uint32_t *>(m_SDLSurface->pixels) + y * m_SDLSurface->pitch / 4 + x); break; } SDL_UnlockSurface (m_SDLSurface); return pixelColor;}////// \brief Gets the width of the surface.////// \return Surface's width.///uint16_tSurface::getWidth (void) const{ return toSDLSurface ()->w;}////// \brief Creates a new surface from a file.////// \param fileName The file name to use to load the surface from./// \return The Surface class with the file loaded.///Surface *Surface::fromFile (std::string fileName){ SDL_Surface *loadedSurface = IMG_Load (fileName.c_str ()); if ( NULL == loadedSurface ) { throw std::runtime_error (IMG_GetError ()); } SDL_Surface *optimizedSurface = SDL_DisplayFormatAlpha (loadedSurface); SDL_FreeSurface (loadedSurface); if ( NULL == optimizedSurface ) { throw std::runtime_error (SDL_GetError ()); } return new Surface (optimizedSurface);}////// \brief Creates a new surface as a copy of the screen.////// \return The Surface object with a copy of the screen.///Surface *Surface::fromScreen (void){ SDL_Surface *screen = System::getInstance ().getScreenSDLSurface (); SDL_Surface *copy = SDL_CreateRGBSurface (SDL_SWSURFACE | SDL_SRCALPHA, screen->w, screen->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask); if ( 0 == copy ) { throw std::runtime_error (IMG_GetError ()); } SDL_BlitSurface (screen, NULL, copy, NULL); return new Surface (copy);}////// \brief Surface's assign operator.////// \param surface The surface to assign to the current surface.///Surface &Surface::operator= (const Surface &surface){ Surface tempSurface (surface); swap (*this, tempSurface); return *this;}////// \brief Scales the image using an scale factor.////// \param scaleFactor The scale factor to use to resize the image.///voidSurface::resize (float scaleFactor){ // In GP2X we use already scaled graphics. No need to scale them // by software (too slow.)#if !defined (IS_GP2X_HOST) // Can only resize 32-bit surfaces. assert ( 0 != m_SDLSurface && "Tried to resize an unloaded surface" ); assert ( 32 == m_SDLSurface->format->BitsPerPixel && "Tried to resize a non 32-bit surface." ); // If the scale factor is approximaltey 1.0f, then we don't need // to do anything!. if ( fabs (scaleFactor - 1.0f) < 1e-3 ) { return; } // Create the new scaled surface. SDL_Surface *scaledSDLSurface = SDL_CreateRGBSurface (m_SDLSurface->flags, static_cast<int>(m_SDLSurface->w * scaleFactor), static_cast<int>(m_SDLSurface->h * scaleFactor), m_SDLSurface->format->BitsPerPixel, m_SDLSurface->format->Rmask, m_SDLSurface->format->Gmask, m_SDLSurface->format->Bmask, m_SDLSurface->format->Amask); if ( 0 == scaledSDLSurface ) { throw std::runtime_error (SDL_GetError ()); } // Now, for each pixel in the scaled surface, get the corresponding // coordinate on the original surface and using a bilinear filter, // smooth the color for the scaled pixel. SDL_LockSurface (m_SDLSurface); SDL_LockSurface (scaledSDLSurface); uint32_t *scaledPixels = static_cast<uint32_t *>(scaledSDLSurface->pixels); uint32_t *originalPixels = static_cast<uint32_t *>(m_SDLSurface->pixels); int scaledPitch = scaledSDLSurface->pitch / sizeof (uint32_t); int originalPitch = m_SDLSurface->pitch / sizeof (uint32_t); for ( int scaledY = 0 ; scaledY < scaledSDLSurface->h ; ++scaledY ) { float originalY = scaledY / scaleFactor; int destinationY = static_cast<int>(floorf (originalY)); float yRatio = originalY - destinationY; float yOpposite = 1 - yRatio; uint32_t *currentScaledPixel = scaledPixels + scaledY * scaledPitch; for ( int scaledX = 0 ; scaledX < scaledSDLSurface->w ; ++scaledX ) { float scaledAlpha = 0.0f; float scaledBlue = 0.0f; float scaledGreen = 0.0f; float scaledRed = 0.0f; float originalX = scaledX / scaleFactor; int destinationX = static_cast<int>(floorf (originalX)); float xRatio = originalX - destinationX; float xOpposite = 1 - xRatio; uint8_t originalAlpha = 0; uint8_t originalBlue = 0; uint8_t originalGreen = 0; uint8_t originalRed = 0; // Left-top pixel. SDL_GetRGBA (originalPixels[destinationY * originalPitch + destinationX], m_SDLSurface->format, &originalRed, &originalGreen, &originalBlue, &originalAlpha); scaledAlpha += originalAlpha * xOpposite * yOpposite; scaledBlue += originalBlue * xOpposite * yOpposite; scaledGreen += originalGreen * xOpposite * yOpposite; scaledRed += originalRed * xOpposite * yOpposite; // Right-top pixel. SDL_GetRGBA (originalPixels[destinationY * originalPitch + destinationX + 1], m_SDLSurface->format, &originalRed, &originalGreen, &originalBlue, &originalAlpha); scaledAlpha += originalAlpha * xRatio * yOpposite; scaledBlue += originalBlue * xRatio * yOpposite; scaledGreen += originalGreen * xRatio * yOpposite; scaledRed += originalRed * xRatio * yOpposite; // Left-bottom pixel. SDL_GetRGBA (originalPixels[(destinationY + 1) * originalPitch + destinationX], m_SDLSurface->format, &originalRed, &originalGreen, &originalBlue, &originalAlpha); scaledAlpha += originalAlpha * xOpposite * yRatio; scaledBlue += originalBlue * xOpposite * yRatio; scaledGreen += originalGreen * xOpposite * yRatio; scaledRed += originalRed * xOpposite * yRatio; // Right-bottom pixel. SDL_GetRGBA (originalPixels[(destinationY + 1) * originalPitch + destinationX + 1], m_SDLSurface->format, &originalRed, &originalGreen, &originalBlue, &originalAlpha); scaledAlpha += originalAlpha * xRatio * yRatio; scaledBlue += originalBlue * xRatio * yRatio; scaledGreen += originalGreen * xRatio * yRatio; scaledRed += originalRed * xRatio * yRatio; *currentScaledPixel = SDL_MapRGBA (scaledSDLSurface->format, static_cast<uint8_t>(scaledRed), static_cast<uint8_t>(scaledGreen), static_cast<uint8_t>(scaledBlue), static_cast<uint8_t>(scaledAlpha)); currentScaledPixel++; } } SDL_UnlockSurface (scaledSDLSurface); SDL_UnlockSurface (m_SDLSurface); // Done. Swap the surfaces and free the original surface. std::swap (m_SDLSurface, scaledSDLSurface); SDL_FreeSurface (scaledSDLSurface);#endif // !IS_GP2X_HOST}////// \brief Sets the alpha value.////// \param alpha The alpha value to set to the surface.///voidSurface::setAlpha (uint8_t alpha){ SDL_SetAlpha (toSDLSurface (), SDL_SRCALPHA, alpha);}////// \brief Sets the transparent color.////// \param colorKey The color that will be transparent while blitting.///voidSurface::setColorKey (uint32_t colorKey){ SDL_SetColorKey (m_SDLSurface, SDL_SRCCOLORKEY, colorKey);}////// \brief Swaps two surfaces.////// \param lhs The left hand side surface of the swap operation./// \param rhs The right hand side surface of the swap operation.///voidSurface::swap (Surface &lhs, Surface &rhs){ std::swap (lhs.m_SDLSurface, rhs.m_SDLSurface);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -