GFXTextureObject *GFXTextureManager::_createTexture( GBitmap *bmp, const String &resourceName, GFXTextureProfile *profile, bool deleteBmp, GFXTextureObject *inObj ) { PROFILE_SCOPE( GFXTextureManager_CreateTexture_Bitmap ); #ifdef DEBUG_SPEW Platform::outputDebugString( "[GFXTextureManager] _createTexture (GBitmap) '%s'", resourceName.c_str() ); #endif // Massage the bitmap based on any resize rules. U32 scalePower = getTextureDownscalePower( profile ); GBitmap *realBmp = bmp; U32 realWidth = bmp->getWidth(); U32 realHeight = bmp->getHeight(); if ( scalePower && isPow2(bmp->getWidth()) && isPow2(bmp->getHeight()) && profile->canDownscale() ) { // We only work with power of 2 textures for now, so we // don't have to worry about padding. // We downscale the bitmap on the CPU... this is the reason // you should be using DDS which already has good looking mips. GBitmap *padBmp = bmp; padBmp->extrudeMipLevels(); scalePower = getMin( scalePower, padBmp->getNumMipLevels() - 1 ); realWidth = getMax( (U32)1, padBmp->getWidth() >> scalePower ); realHeight = getMax( (U32)1, padBmp->getHeight() >> scalePower ); realBmp = new GBitmap( realWidth, realHeight, false, bmp->getFormat() ); // Copy to the new bitmap... dMemcpy( realBmp->getWritableBits(), padBmp->getBits(scalePower), padBmp->getBytesPerPixel() * realWidth * realHeight ); // This line is commented out because createPaddedBitmap is commented out. // If that line is added back in, this line should be added back in. // delete padBmp; }
void ScreenShot::capture( GuiCanvas *canvas ) { AssertFatal( mPending, "ScreenShot::capture() - The capture wasn't pending!" ); if ( mTiles == 1 ) { _singleCapture( canvas ); return; } char filename[256]; Point2I canvasSize = canvas->getPlatformWindow()->getVideoMode().resolution; // Calculate the real final size taking overlap in account Point2I overlapPixels( canvasSize.x * mPixelOverlap.x, canvasSize.y * mPixelOverlap.y ); // Calculate the overlap to be used by the frustum tiling, // so it properly expands the frustum to overlap the amount of pixels we want mFrustumOverlap.x = ((F32)canvasSize.x/(canvasSize.x - overlapPixels.x*2)) * ((F32)overlapPixels.x/(F32)canvasSize.x); mFrustumOverlap.y = ((F32)canvasSize.y/(canvasSize.y - overlapPixels.y*2)) * ((F32)overlapPixels.y/(F32)canvasSize.y); //overlapPixels.set(0,0); // Get a buffer to write a row of tiles into. GBitmap *outBuffer = new GBitmap( canvasSize.x * mTiles - overlapPixels.x * mTiles * 2 , canvasSize.y - overlapPixels.y ); // Open up the file on disk. dSprintf( filename, 256, "%s.%s", mFilename, "png" ); FileStream fs; if ( !fs.open( filename, Torque::FS::File::Write ) ) Con::errorf( "ScreenShot::capture() - Failed to open output file '%s'!", filename ); // Open a PNG stream for the final image DeferredPNGWriter pngWriter; pngWriter.begin(outBuffer->getFormat(), outBuffer->getWidth(), canvasSize.y * mTiles - overlapPixels.y * mTiles * 2, fs, 0); // Render each tile to generate a huge screenshot. for( U32 ty=0; ty < mTiles; ty++ ) { for( S32 tx=0; tx < mTiles; tx++ ) { // Set the current tile offset for tileFrustum(). mCurrTile.set( tx, mTiles - ty - 1 ); // Let the canvas render the scene. canvas->renderFrame( false ); // Now grab the current back buffer. GBitmap *gb = _captureBackBuffer(); // The current GFX device couldn't capture the backbuffer or it's unable of doing so. if (gb == NULL) return; // Copy the captured bitmap into its tile // within the output bitmap. const U32 inStride = gb->getWidth() * gb->getBytesPerPixel(); const U8 *inColor = gb->getBits() + inStride * overlapPixels.y; const U32 outStride = outBuffer->getWidth() * outBuffer->getBytesPerPixel(); const U32 inOverlapOffset = overlapPixels.x * gb->getBytesPerPixel(); const U32 inOverlapStride = overlapPixels.x * gb->getBytesPerPixel()*2; const U32 outOffset = (tx * (gb->getWidth() - overlapPixels.x*2 )) * gb->getBytesPerPixel(); U8 *outColor = outBuffer->getWritableBits() + outOffset; for( U32 row=0; row < gb->getHeight() - overlapPixels.y; row++ ) { dMemcpy( outColor, inColor + inOverlapOffset, inStride - inOverlapStride ); //Grandient blend the left overlap area of this tile over the previous tile left border if (tx && !(ty && row < overlapPixels.y)) { U8 *blendOverlapSrc = (U8*)inColor; U8 *blendOverlapDst = outColor - inOverlapOffset; for ( U32 px=0; px < overlapPixels.x; px++) { F32 blendFactor = (F32)px / (F32)overlapPixels.x; sBlendPixelRGB888(blendOverlapSrc, blendOverlapDst, blendFactor); blendOverlapSrc += gb->getBytesPerPixel(); blendOverlapDst += outBuffer->getBytesPerPixel(); } } //Gradient blend against the rows the excess overlap rows already in the buffer if (ty && row < overlapPixels.y) { F32 rowBlendFactor = (F32)row / (F32)overlapPixels.y; U8 *blendSrc = outColor + outStride * (outBuffer->getHeight() - overlapPixels.y); U8 *blendDst = outColor; for ( U32 px=0; px < gb->getWidth() - overlapPixels.x*2; px++) { sBlendPixelRGB888(blendSrc, blendDst, 1.0-rowBlendFactor); blendSrc += gb->getBytesPerPixel(); blendDst += outBuffer->getBytesPerPixel(); } } inColor += inStride; outColor += outStride; } delete gb; } // Write the captured tile row into the PNG stream pngWriter.append(outBuffer, outBuffer->getHeight()-overlapPixels.y); } //Close the PNG stream pngWriter.end(); // We captured... clear the flag. mPending = false; }
void ClipMap::fillWithTestPattern() { AssertISV(false, "ClipMap::fillWithTestPattern - assumes bitmaps, which " "are no longer present, switch to lock() semantics if you need this!"); // Table of random colors. U8 colorTbl[16][3] = { { 0xFF, 0x00, 0x0F }, { 0xFF, 0x00, 0xA0 }, { 0xFF, 0x00, 0xFF }, { 0x00, 0xA0, 0x00 }, { 0x00, 0xA0, 0xAF }, { 0x00, 0xA0, 0xF0 }, { 0xA0, 0xFF, 0xA0 }, { 0x00, 0xF0, 0xA0 }, { 0x00, 0xF0, 0xFF }, { 0xA0, 0x00, 0x00 }, { 0xA0, 0x00, 0xAF }, { 0xA0, 0x00, 0xF0 }, { 0xA0, 0xF0, 0x0F }, { 0xA0, 0xF0, 0xA0 }, { 0xA0, 0xF0, 0xFF }, { 0x00, 0xFF, 0x00 }, }; // Lock each layer of each texture and write a test pattern in. // Base levels first. for(S32 i=0; i<mClipStackDepth; i++) { GTexHandle >h = mLevels[i].mTex; U8 *bmpData = (U8*)gth.getBitmap()->getWritableBits(0); for(S32 x=0; x<gth.getHeight(); x++) { for(S32 y=0; y<gth.getWidth(); y++) { S32 xFlag = x & 4; S32 yFlag = y & 4; U32 offset = (x * gth.getWidth() + y) * 4; if(xFlag ^ yFlag) { // Set bright. bmpData[offset+0] = colorTbl[i][0]; bmpData[offset+1] = colorTbl[i][1]; bmpData[offset+2] = colorTbl[i][2]; bmpData[offset+3] = 0xFF; } else { // Set dim. bmpData[offset+0] = colorTbl[i][0] / 3; bmpData[offset+1] = colorTbl[i][1] / 3; bmpData[offset+2] = colorTbl[i][2] / 3; bmpData[offset+3] = 0xFF; } } } if(i == mClipStackDepth - 1) gth.getBitmap()->extrudeMipLevels(); else { // Write black/translucent in the higher levels. GBitmap *gb = gth.getBitmap(); for(S32 j=1; j<gb->getNumMipLevels(); j++) { U8 *b = gb->getWritableBits(j); dMemset(b, 0, 4 * gb->getWidth(j) * gb->getHeight(j)); } } gth.refresh(); } }