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; }
// Console Functions void loadHeightMap(SimObject *obj, S32 argc, const char *argv[]) { GBitmap *bmp = dynamic_cast<GBitmap*>(Link.ResourceManager->loadInstance(argv[1])); if(bmp != NULL) { terrainBuilder->height = (bmp->getHeight() / 2) * 2; terrainBuilder->width = (bmp->getWidth() / 2) * 2; terrainBuilder->heightMap = new F32[terrainBuilder->height * terrainBuilder->width]; for(U32 y = 0; y < terrainBuilder->height; y++) { for(U32 x = 0; x < terrainBuilder->width; x++) { ColorI heightSample; bmp->getColor(x, y, heightSample); terrainBuilder->heightMap[(y * terrainBuilder->width) + x] = ((F32)heightSample.red) * 0.1f; } } terrainBuilder->rebuild(); refresh(); } }
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(); } }
S32 GuiControlProfile::constructBitmapArray() { if(mBitmapArrayRects.size()) return mBitmapArrayRects.size(); if( mTextureObject.isNull() ) { if ( !mBitmapName || !mBitmapName[0] || !mTextureObject.set( mBitmapName, &GFXDefaultPersistentProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__) )) return 0; } GBitmap *bmp = mTextureObject->getBitmap(); //get the separator color ColorI sepColor; if ( !bmp || !bmp->getColor( 0, 0, sepColor ) ) { Con::errorf("Failed to create bitmap array from %s for profile %s - couldn't ascertain seperator color!", mBitmapName, getName()); AssertFatal( false, avar("Failed to create bitmap array from %s for profile %s - couldn't ascertain seperator color!", mBitmapName, getName())); return 0; } //now loop through all the scroll pieces, and find the bounding rectangle for each piece in each state S32 curY = 0; // ascertain the height of this row... ColorI color; mBitmapArrayRects.clear(); while(curY < bmp->getHeight()) { // skip any sep colors bmp->getColor( 0, curY, color); if(color == sepColor) { curY++; continue; } // ok, process left to right, grabbing bitmaps as we go... S32 curX = 0; while(curX < bmp->getWidth()) { bmp->getColor(curX, curY, color); if(color == sepColor) { curX++; continue; } S32 startX = curX; while(curX < bmp->getWidth()) { bmp->getColor(curX, curY, color); if(color == sepColor) break; curX++; } S32 stepY = curY; while(stepY < bmp->getHeight()) { bmp->getColor(startX, stepY, color); if(color == sepColor) break; stepY++; } mBitmapArrayRects.push_back(RectI(startX, curY, curX - startX, stepY - curY)); } // ok, now skip to the next separation color on column 0 while(curY < bmp->getHeight()) { bmp->getColor(0, curY, color); if(color == sepColor) break; curY++; } } return mBitmapArrayRects.size(); }
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(); }