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 TerrainFile::import( const GBitmap &heightMap, F32 heightScale, const Vector<U8> &layerMap, const Vector<String> &materials, bool flipYAxis ) { AssertFatal( heightMap.getWidth() == heightMap.getHeight(), "TerrainFile::import - Height map is not square!" ); AssertFatal( isPow2( heightMap.getWidth() ), "TerrainFile::import - Height map is not power of two!" ); const U32 newSize = heightMap.getWidth(); if ( newSize != mSize ) { mHeightMap.setSize( newSize * newSize ); mHeightMap.compact(); mSize = newSize; } // Convert the height map to heights. U16 *oBits = mHeightMap.address(); if ( heightMap.getFormat() == GFXFormatR5G6B5 ) { const F32 toFixedPoint = ( 1.0f / (F32)U16_MAX ) * floatToFixed( heightScale ); const U16 *iBits = (const U16*)heightMap.getBits(); if ( flipYAxis ) { for ( U32 i = 0; i < mSize * mSize; i++ ) { U16 height = convertBEndianToHost( *iBits ); *oBits = (U16)mCeil( (F32)height * toFixedPoint ); ++oBits; ++iBits; } } else { for(S32 y = mSize - 1; y >= 0; y--) { for(U32 x = 0; x < mSize; x++) { U16 height = convertBEndianToHost( *iBits ); mHeightMap[x + y * mSize] = (U16)mCeil( (F32)height * toFixedPoint ); ++iBits; } } } } else { const F32 toFixedPoint = ( 1.0f / (F32)U8_MAX ) * floatToFixed( heightScale ); const U8 *iBits = heightMap.getBits(); if ( flipYAxis ) { for ( U32 i = 0; i < mSize * mSize; i++ ) { *oBits = (U16)mCeil( ((F32)*iBits) * toFixedPoint ); ++oBits; iBits += heightMap.getBytesPerPixel(); } } else { for(S32 y = mSize - 1; y >= 0; y--) { for(U32 x = 0; x < mSize; x++) { mHeightMap[x + y * mSize] = (U16)mCeil( ((F32)*iBits) * toFixedPoint ); iBits += heightMap.getBytesPerPixel(); } } } } // Copy over the layer map. AssertFatal( layerMap.size() == mHeightMap.size(), "TerrainFile::import - Layer map is the wrong size!" ); mLayerMap = layerMap; mLayerMap.compact(); // Resolve the materials. _resolveMaterials( materials ); // Rebuild the collision grid map. _buildGridMap(); }