예제 #1
0
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;
   }
예제 #2
0
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;
}
예제 #3
0
void ImposterCapture::_separateAlpha( GBitmap *imposterOut )
{
   PROFILE_START(TSShapeInstance_snapshot_sb_separate);

   // TODO: Remove all this when we get rid of the 'render on black/white'.

      // now separate the color and alpha channels
      GBitmap *bmp = new GBitmap;
      bmp->allocateBitmap(mDim, mDim, false, GFXFormatR8G8B8A8);
      U8 * wbmp = (U8*)mWhiteBmp->getBits(0);
      U8 * bbmp = (U8*)mBlackBmp->getBits(0);
      U8 * dst  = (U8*)bmp->getBits(0);

      const U32 pixCount = mDim * mDim;

      // simpler, probably faster...
      for ( U32 i=0; i < pixCount; i++ )
      {
         // Shape on black background is alpha * color, shape on white 
         // background is alpha * color + (1-alpha) * 255 we want 255 *
         // alpha, or 255 - (white - black).
         //
         // JMQ: or more verbosely:
         //  cB = alpha * color + (0 * (1 - alpha))
         //  cB = alpha * color
         //  cW = alpha * color + (255 * (1 - alpha))
         //  cW = cB + (255 * (1 - alpha))
         // solving for alpha
         //  cW - cB = 255 * (1 - alpha)
         //  (cW - cB)/255 = (1 - alpha)
         //  alpha = 1 - (cW - cB)/255
         // since we want alpha*255, multiply through by 255
         //  alpha * 255 = 255 - cW - cB
         U32 alpha = 255 - (wbmp[i*3+0] - bbmp[i*3+0]);
         alpha    += 255 - (wbmp[i*3+1] - bbmp[i*3+1]);
         alpha    += 255 - (wbmp[i*3+2] - bbmp[i*3+2]);

         if ( alpha != 0 )
         {
            F32 floatAlpha = ((F32)alpha)/(3.0f*255.0f); 
            dst[i*4+0] = (U8)(bbmp[i*3+0] / floatAlpha);
            dst[i*4+1] = (U8)(bbmp[i*3+1] / floatAlpha);
            dst[i*4+2] = (U8)(bbmp[i*3+2] / floatAlpha);

            // Before we assign the alpha we "fizzle" the value
            // if its greater than 84.  This causes the imposter
            // to dissolve instead of popping into view.
            alpha /= 3;
            dst[i*4+3] = (U8)alpha;
         }
         else
         {
            dst[i*4+0] = dst[i*4+1] = dst[i*4+2] = dst[i*4+3] = 0;
         }
      }

   PROFILE_END(); // TSShapeInstance_snapshot_sb_separate
  
   PROFILE_START(TSShapeInstance_snapshot_sb_filter);

      // We now run a special kernel filter over the image that
      // averages color into the transparent areas.  This should
      // in essence give us a border around the edges of the 
      // imposter silhouette which fixes the artifacts around the
      // alpha test billboards.
      U8* dst2 = (U8*)imposterOut->getBits(0);

      _colorAverageFilter( mDim, dst, dst2 );
      
      if ( 0 )
      {
         FileStream fs;
         if ( fs.open( "./imposterout.png", Torque::FS::File::Write ) )
            imposterOut->writeBitmap( "png", fs );

         fs.close();

         if ( fs.open( "./temp.png", Torque::FS::File::Write ) )
            bmp->writeBitmap( "png", fs );

         fs.close();
      }
   

   PROFILE_END(); // TSShapeInstance_snapshot_sb_filter

   delete bmp;
}
예제 #4
0
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();
}