// This assumes that both Surfaces are the same format and bit depth /*static*/ void Surface::ScaledBlit( const Surface& Src, Surface& Dest, int Scalar ) { PROFILE_FUNCTION; ASSERT( Src.GetWidth() * Scalar == Dest.GetWidth() ); ASSERT( Src.GetHeight() * Scalar == Dest.GetHeight() ); const byte* SrcPixels = Src.GetPointerAt( 0, 0 ); int SrcIncrement = Src.GetStride() * 2 - Src.GetPadding(); // Roll forward (padding) to end of line then roll back two lines (stride*2) int DestIncrement = Dest.GetStride() + Scalar * BYTES; // Roll back scalar width plus one line for( int SrcY = 0; SrcY < Src.GetHeight(); ++SrcY ) { for( int SrcX = 0; SrcX < Src.GetWidth(); ++SrcX ) { byte B = *SrcPixels++; byte G = *SrcPixels++; byte R = *SrcPixels++; byte* DestPixels = Dest.GetPointerAt( SrcX * Scalar, SrcY * Scalar ); for( int j = 0; j < Scalar; ++j ) { for( int i = 0; i < Scalar; ++i ) { *DestPixels++ = B; *DestPixels++ = G; *DestPixels++ = R; } DestPixels -= DestIncrement; } } SrcPixels -= SrcIncrement; } }
/*static*/ void Surface::MaskBlendBlit( const Surface& Src, Surface& Dest, int dx, int dy, int w, int h, int sx, int sy, uint ColorKey ) { if( !ClipRectangles( Src, Dest, dx, dy, w, h, sx, sy ) ) { return; } int Length = w * BYTES; int SrcIncrement = ( Src.GetWidth() * BYTES ) + Src.GetPadding() + Length; int DestIncrement = ( Dest.GetWidth() * BYTES ) + Dest.GetPadding() + Length; byte* DestPixels = Dest.GetPointerAt( dx, dy ); const byte* SrcPixels = Src.GetPointerAt( sx, sy ); // Would it be faster to iterate forward (Pixels += ...)? for cache reasons...? for( int j = 0; j < h; ++j ) { for( int i = 0; i < w; ++i ) { // Conditional: bad, but coming up with a *faster* mathy way is hard if( ( *(unsigned int*)SrcPixels & 0x00ffffff ) != ColorKey ) { *DestPixels++ = ( *DestPixels + *SrcPixels++ ) >> 1; *DestPixels++ = ( *DestPixels + *SrcPixels++ ) >> 1; *DestPixels++ = ( *DestPixels + *SrcPixels++ ) >> 1; } else { DestPixels += BYTES; SrcPixels += BYTES; } }
void Framework3D::CreateSplashWindow(const uint WindowIcon, const char* const Title) { XTRACE_FUNCTION; STATICHASH(Framework); STATICHASH(SplashImage); const char* const pSplashImage = ConfigManager::GetString(sSplashImage, nullptr, sFramework); if (!pSplashImage) { return; } const Surface SplashSurface = Surface(PackStream(pSplashImage), Surface::ESFT_BMP); const int SplashWindowWidth = SplashSurface.GetWidth(); const int SplashWindowHeight = SplashSurface.GetHeight(); ASSERT(!m_SplashWindow); m_SplashWindow = new Window; #if BUILD_WINDOWS_NO_SDL const DWORD WindowStyle = WS_POPUP; const DWORD WindowExStyle = WS_EX_TOOLWINDOW; // Prevents this window appearing in the taskbar const int ScreenWidth = m_Display->m_Fullscreen ? m_Display->m_Width : m_Display->m_ScreenWidth; const int ScreenHeight = m_Display->m_Fullscreen ? m_Display->m_Height : m_Display->m_ScreenHeight; m_SplashWindow->Init(Title, "SplashWindowClass", WindowStyle, WindowExStyle, SplashWindowWidth, SplashWindowHeight, m_hInstance, NULL, WindowIcon, ScreenWidth, ScreenHeight); // The window needs to be shown before we can blit to it. m_SplashWindow->Show(m_CmdShow); #endif #if BUILD_SDL // TODO SDL: Unify interface? const uint Flags = SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS; m_SplashWindow->Init(Title, Flags, SplashWindowWidth, SplashWindowHeight); // Load icon from package file instead of compiled resource. Unused(WindowIcon); STATICHASH(IconImage); const char* const pIconImage = ConfigManager::GetString(sIconImage, nullptr, sFramework); if(pIconImage) { ASSERT(pIconImage); const Surface IconSurface = Surface(PackStream(pIconImage), Surface::ESFT_BMP); SDL_SetWindowIcon(m_SplashWindow->GetSDLWindow(), IconSurface.GetSDLSurface()); } #endif SplashSurface.BlitToWindow(m_SplashWindow); }
Bitmap::Bitmap(const Surface& surface) { width = surface.GetWidth(); height = surface.GetHeight(); format = surface.GetPixelFormat(); pitch = width * format.GetBytes(); image = new uint8[height*pitch]; // copy image CopyImage(image,surface.GetImage(),pitch,surface.GetPitch(),height); }
/*static*/ void Surface::MaskBlit( const Surface& Src, Surface& Dest, int dx, int dy, int w, int h, int sx, int sy, uint ColorKey ) { if( !ClipRectangles( Src, Dest, dx, dy, w, h, sx, sy ) ) { return; } int Length = w * BYTES; int SrcIncrement = ( Src.GetWidth() * BYTES ) + Src.GetPadding() + Length; int DestIncrement = ( Dest.GetWidth() * BYTES ) + Dest.GetPadding() + Length; byte* DestPixels = Dest.GetPointerAt( dx, dy ); const byte* SrcPixels = Src.GetPointerAt( sx, sy ); // Would it be faster to iterate forward (Pixels += ...)? for cache reasons...? for( int j = 0; j < h; ++j ) { for( int i = 0; i < w; ++i ) { // Fixed this when last three bytes can't be converted to a uint because end of block. // The other methods need to use this version when/if I ever actually dust this class off. byte B = *SrcPixels++; byte G = *SrcPixels++; byte R = *SrcPixels++; if( RGB_TO_COLOR( R, G, B ) == ColorKey ) { DestPixels += BYTES; } else { *DestPixels++ = B; *DestPixels++ = G; *DestPixels++ = R; } } DestPixels -= DestIncrement; SrcPixels -= SrcIncrement; } }
/*static*/ void Surface::StandardBlit( const Surface& Src, Surface& Dest, int dx, int dy, int w, int h, int sx, int sy ) { if( !ClipRectangles( Src, Dest, dx, dy, w, h, sx, sy ) ) { return; } int Length = w * BYTES; int SrcIncrement = ( Src.GetWidth() * BYTES ) + Src.GetPadding(); int DestIncrement = ( Dest.GetWidth() * BYTES ) + Dest.GetPadding(); byte* DestPixels = Dest.GetPointerAt( dx, dy ); const byte* SrcPixels = Src.GetPointerAt( sx, sy ); // Would it be faster to iterate forward (Pixels += ...)? for cache reasons...? for( int j = 0; j < h; ++j ) { memcpy( DestPixels, SrcPixels, Length ); DestPixels -= DestIncrement; SrcPixels -= SrcIncrement; } }
// takes ownership of image data Image* ResourceManager::LoadImage(const string &aPath) { Surface* pSurface = PngToSurface(aPath.c_str()); Image* pImage = NULL; if (pSurface) { pImage = new Image(); pImage->_pPathName = aPath; pImage->_width = pSurface->GetWidth(); pImage->_height = pSurface->GetHeight(); _preloadData.push_back(ImageSurfacePair(pImage, pSurface)); } return pImage; }
void Map::DrawBackground(Window screen, Graphics* assets){ Point2D dim = GetMapDimension(); Surface* surface =& (assets->forest[0]); Surface* parallax = & (assets->forestParallax); int forestStart = (int)dim.Y;//The bottom of the map int Xstart = 0; int Xcount = 0; int parallaxStartX =0; //(Bottom of map - (the current camera position + the height of the screen)) divided by the height of the background surface -1 //== (bottom of map - the bottom of the screen)/height of background -1 //==how many backgrounds are already beneath this position? int Ycount = (int)((forestStart - (_mapPosition.Y+screen.GetHeight())) / surface->GetHeight()) - 1; //the starting point for the background to draw int Ystart = (int)dim.Y - surface->GetHeight()*Ycount; while(Ystart>_mapPosition.Y){ //The vertical height determines the kind of background surface->SetTransparency(255); if(Ycount == 0) {surface = &(assets->forest[0]); parallax=&(assets->forestParallax);} else if(Ycount == 1) {surface =&( assets->air[0]);parallax=0;} else if(Ycount == 2) {surface = &(assets->space1);parallax=0;} else if(Ycount < 0) {surface->SetTransparency(0);parallax=0;} else {surface = &(assets->space2);parallax=0;} //This one is handled, go the next one Ystart -= surface->GetHeight(); //The starting position of the next background to render Xstart = (int)(_mapPosition.X - ((Uint32)_mapPosition.X % (Uint32)surface->GetWidth())); //How many backgrounds are already left of this? Xcount = (int)(_mapPosition.X/surface->GetWidth()); if (parallax!=0 && parallax->IsInit()) { int parallaxStartX=(int)(_mapPosition.X/2 - ((Uint32)(_mapPosition.X/2) % (Uint32)parallax->GetWidth())); while(parallaxStartX < _mapPosition.X + screen.GetWidth()){ parallax->Draw(screen,(Uint32)(parallaxStartX-_mapPosition.X/2), (Uint32)(Ystart-_mapPosition.Y)+400); parallax->Draw(screen,(Uint32)(parallaxStartX-_mapPosition.X/2), (Uint32)(Ystart-_mapPosition.Y)+400); parallaxStartX += parallax->GetWidth(); } } while(Xstart < _mapPosition.X + screen.GetWidth()){ //Handle the current image for the looping backgrounds if(Ycount == 1){ if(Xcount>2)Xcount = Xcount%3; surface = &(assets->air[Xcount]); Xcount++; } else if(Ycount == 0){ if(Xcount>3) Xcount = Xcount%4; surface = &(assets->forest[Xcount]); Xcount++; } surface->Draw(screen, (Uint32)(Xstart-_mapPosition.X), (Uint32)(Ystart-_mapPosition.Y)); Xstart += surface->GetWidth(); } Ycount++; } }
void ResourceManager::GenerateTextures(const Vector2i &maxSize) { // sort by size for (uint16 i=0; i<_preloadData.size()-1; ++i) { Surface* s1 = _preloadData[i].second; Surface* s2 = _preloadData[i+1].second; if (s1->GetArea() < s2->GetArea()) { Surface* temp = s1; s1 = s2; s2 = s1; } } vector<Surface*> masterTextures; int masterTextureCount = 0; while(!_preloadData.empty() && masterTextureCount < MAX_TEXTURES) { Surface* masterSurface = new Surface(NULL, maxSize.x, maxSize.y, 4); masterTextureCount ++; vector<Image*> imagesOnSurface; Node rootNode; rootNode.rect = Rect(0, 0, maxSize.x, maxSize.y); for (vector<ImageSurfacePair>::iterator it = _preloadData.begin(); it != _preloadData.end();) { Image* image = it->first; Surface* surface = it->second; Rect rect = Rect(0, 0, surface->GetWidth(), surface->GetHeight()); Node* node = rootNode.Insert(rect); if (node) { // we managed to fit it inside the master texture rect = node->rect; masterSurface->BlitSurface(surface, rect.x, rect.y); surface->Destroy(); imagesOnSurface.push_back(image); image->_textureX = (float)rect.x / masterSurface->GetWidth(); image->_textureY = (float)rect.y / masterSurface->GetHeight(); image->_textureW = (float)rect.width / masterSurface->GetWidth(); image->_textureH = (float)rect.height / masterSurface->GetHeight(); it = _preloadData.erase(it); } else ++it; } // OpenGl has reversed Y axis masterSurface->FlipY(); GLuint texture = masterSurface->CreateGLTexture(); masterSurface->Destroy(); for (uint16 i=0; i<imagesOnSurface.size(); ++i) { imagesOnSurface[i]->_texture = texture; } } }