bool ConvertPixelDataDeferred( Interface *engineInterface, const pixelDataTraversal& srcPixels, pixelDataTraversal& dstPixels, const pixelFormat pixFormat )
{
    // First create a new copy of the texels.
    dstPixels.CloneFrom( engineInterface, srcPixels );

    // Perform the conversion on the new texels.
    return ConvertPixelData( engineInterface, dstPixels, pixFormat );
}
bool ConvertPixelData( Interface *engineInterface, pixelDataTraversal& pixelsToConvert, const pixelFormat pixFormat )
{
    // We must have stand-alone pixel data.
    // Otherwise we could mess up pretty badly!
    assert( pixelsToConvert.isNewlyAllocated == true );

    // Decide how to convert stuff.
    bool hasUpdated = false;

    eCompressionType srcCompressionType = pixelsToConvert.compressionType;
    eCompressionType dstCompressionType = pixFormat.compressionType;

    uint32 srcDXTType, dstDXTType;

    bool isSrcDXTCompressed = IsDXTCompressionType( srcCompressionType, srcDXTType );
    bool isDstDXTCompressed = IsDXTCompressionType( dstCompressionType, dstDXTType );

    bool shouldRecalculateAlpha = false;

    if ( isSrcDXTCompressed || isDstDXTCompressed )
    {
        // Check whether the compression status even changed.
        if ( srcCompressionType != dstCompressionType )
        {
            // If we were compressed, decompress.
            bool compressionSuccess = false;
            bool decompressionSuccess = false;

            if ( isSrcDXTCompressed )
            {
                decompressionSuccess = genericDecompressDXTNative( engineInterface, pixelsToConvert, srcDXTType );
            }
            else
            {
                // No decompression means we are always successful.
                decompressionSuccess = true;
            }

            if ( decompressionSuccess )
            {
                // If we have to compress, do it.
                if ( isDstDXTCompressed )
                {
                    genericCompressDXTNative( engineInterface, pixelsToConvert, dstDXTType );

                    // No way to fail compression, yet.
                    compressionSuccess = true;
                }
                else
                {
                    // If we do not want to compress the target, then we
                    // want to put it into a proper pixel format.
                    pixelFormat pixSubFormat;
                    pixSubFormat.rasterFormat = pixFormat.rasterFormat;
                    pixSubFormat.depth = pixFormat.depth;
                    pixSubFormat.colorOrder = pixFormat.colorOrder;
                    pixSubFormat.paletteType = pixFormat.paletteType;
                    pixSubFormat.compressionType = RWCOMPRESS_NONE;

                    bool subSuccess = ConvertPixelData( engineInterface, pixelsToConvert, pixSubFormat );

                    // We are successful if the sub conversion succeeded.
                    compressionSuccess = subSuccess;
                }
            }

            if ( compressionSuccess || decompressionSuccess )
            {
                // TODO: if this routine is incomplete, revert to last known best status.
                hasUpdated = true;
            }
        }
    }
    else if ( srcCompressionType == RWCOMPRESS_NONE && dstCompressionType == RWCOMPRESS_NONE )
    {
        ePaletteType srcPaletteType = pixelsToConvert.paletteType;
        ePaletteType dstPaletteType = pixFormat.paletteType;

        if ( srcPaletteType == PALETTE_NONE && dstPaletteType != PALETTE_NONE )
        {
            // Call into the palettizer.
            // It will do the remainder of the complex job.
            PalettizePixelData( engineInterface, pixelsToConvert, pixFormat );

            // We assume the palettization has always succeeded.
            hasUpdated = true;

            // Recalculating alpha is important.
            shouldRecalculateAlpha = true;
        }
        else if ( srcPaletteType != PALETTE_NONE && dstPaletteType == PALETTE_NONE ||
                  srcPaletteType != PALETTE_NONE && dstPaletteType != PALETTE_NONE ||
                  srcPaletteType == PALETTE_NONE && dstPaletteType == PALETTE_NONE )
        {
            // Grab the values on the stack.
            eRasterFormat srcRasterFormat = pixelsToConvert.rasterFormat;
            eColorOrdering srcColorOrder = pixelsToConvert.colorOrder;
            uint32 srcDepth = pixelsToConvert.depth;

            eRasterFormat dstRasterFormat = pixFormat.rasterFormat;
            eColorOrdering dstColorOrder = pixFormat.colorOrder;
            uint32 dstDepth = pixFormat.depth;

            // Check whether we even have to update the texels.
            if ( srcRasterFormat != dstRasterFormat || srcPaletteType != dstPaletteType || srcColorOrder != dstColorOrder || srcDepth != dstDepth )
            {
                // Grab palette parameters.
                void *srcPaletteTexels = pixelsToConvert.paletteData;
                uint32 srcPaletteSize = pixelsToConvert.paletteSize;

                uint32 srcPalRasterDepth;

                if ( srcPaletteType != PALETTE_NONE )
                {
                    srcPalRasterDepth = Bitmap::getRasterFormatDepth( srcRasterFormat );
                }

                void *dstPaletteTexels = srcPaletteTexels;
                uint32 dstPaletteSize = srcPaletteSize;

                uint32 dstPalRasterDepth;

                if ( dstPaletteType != PALETTE_NONE )
                {
                    dstPalRasterDepth = Bitmap::getRasterFormatDepth( dstRasterFormat );
                }

                // Check whether we have to update the palette texels.
                if ( dstPaletteType != PALETTE_NONE )
                {
                    // Make sure we had a palette before.
                    assert( srcPaletteType != PALETTE_NONE );

                    if ( dstPaletteType == PALETTE_4BIT )
                    {
                        dstPaletteSize = 16;
                    }
                    else if ( dstPaletteType == PALETTE_8BIT )
                    {
                        dstPaletteSize = 256;
                    }
                    else
                    {
                        assert( 0 );
                    }

                    // If the palette increased in size, allocate a new array for it.
                    if ( srcPaletteSize != dstPaletteSize || srcPalRasterDepth != dstPalRasterDepth )
                    {
                        uint32 dstPalDataSize = getRasterDataSize( dstPaletteSize, dstPalRasterDepth );

                        dstPaletteTexels = engineInterface->PixelAllocate( dstPalDataSize );
                    }
                }
                else
                {
                    dstPaletteTexels = NULL;
                    dstPaletteSize = 0;
                }

                // If we have a palette, process it.
                if ( srcPaletteType != PALETTE_NONE && dstPaletteType != PALETTE_NONE )
                {
                    ConvertPaletteData(
                        srcPaletteTexels, dstPaletteTexels,
                        srcPaletteSize, dstPaletteSize,
                        srcRasterFormat, srcColorOrder, srcDepth,
                        dstRasterFormat, dstColorOrder, dstDepth
                    );
                }

                // Process mipmaps.
                uint32 mipmapCount = pixelsToConvert.mipmaps.size();

                // Determine the depth of the items.
                for ( uint32 n = 0; n < mipmapCount; n++ )
                {
                    pixelDataTraversal::mipmapResource& mipLayer = pixelsToConvert.mipmaps[ n ];

                    void *dstTexels;
                    uint32 dstTexelsDataSize;

                    // Convert this mipmap.
                    ConvertMipmapLayer(
                        engineInterface,
                        mipLayer, srcRasterFormat, srcDepth, srcColorOrder, srcPaletteType, srcPaletteTexels, srcPaletteSize,
                        dstRasterFormat, dstDepth, dstColorOrder, dstPaletteType,
                        false,
                        dstTexels, dstTexelsDataSize
                    );

                    // Update mipmap properties.
                    void *srcTexels = mipLayer.texels;

                    if ( dstTexels != srcTexels )
                    {
                        // Delete old texels.
                        // We always have texels allocated.
                        engineInterface->PixelFree( srcTexels );

                        // Replace stuff.
                        mipLayer.texels = dstTexels;
                    }

                    uint32 srcTexelsDataSize = mipLayer.dataSize;

                    if ( dstTexelsDataSize != srcTexelsDataSize )
                    {
                        // Update the data size.
                        mipLayer.dataSize = dstTexelsDataSize;
                    }
                }

                // Update the palette if necessary.
                if ( srcPaletteTexels != dstPaletteTexels )
                {
                    if ( srcPaletteTexels )
                    {
                        // Delete old palette texels.
                        engineInterface->PixelFree( srcPaletteTexels );
                    }

                    // Put in the new ones.
                    pixelsToConvert.paletteData = dstPaletteTexels;
                }

                if ( srcPaletteSize != dstPaletteSize )
                {
                    pixelsToConvert.paletteSize = dstPaletteSize;
                }

                // Update the D3DFORMAT field.
                hasUpdated = true;

                // We definately should recalculate alpha.
                shouldRecalculateAlpha = true;
            }

            // Update texture properties that changed.
            if ( srcRasterFormat != dstRasterFormat )
            {
                pixelsToConvert.rasterFormat = dstRasterFormat;
            }

            if ( srcPaletteType != dstPaletteType )
            {
                pixelsToConvert.paletteType = dstPaletteType;
            }

            if ( srcColorOrder != dstColorOrder )
            {
                pixelsToConvert.colorOrder = dstColorOrder;
            }

            if ( srcDepth != dstDepth )
            {
                pixelsToConvert.depth = dstDepth;
            }
        }
    }

    // If we have updated the pixels, we _should_ recalculate the pixel alpha flag.
    if ( hasUpdated )
    {
        if ( shouldRecalculateAlpha )
        {
            pixelsToConvert.hasAlpha = calculateHasAlpha( pixelsToConvert );
        }
    }

    return hasUpdated;
}
Beispiel #3
0
static AINLINE void CompressNativeTexture(
    Interface *engineInterface, texNativeTypeProvider *texProvider, PlatformTexture *platformTex,
    eCompressionType targetCompressionType
)
{
    // Since we now know about everything, we can take the pixels and perform the compression.
    pixelDataTraversal pixelData;

    texProvider->GetPixelDataFromTexture( engineInterface, platformTex, pixelData );

    bool hasDirectlyAcquired = false;

    try
    {
        // Unset the pixels from the texture and make them standalone.
        texProvider->UnsetPixelDataFromTexture( engineInterface, platformTex, pixelData.isNewlyAllocated == true );

        pixelData.SetStandalone();

        // Compress things.
        pixelFormat targetPixelFormat;
        targetPixelFormat.rasterFormat = pixelData.rasterFormat;
        targetPixelFormat.depth = pixelData.depth;
        targetPixelFormat.rowAlignment = 0;
        targetPixelFormat.colorOrder = pixelData.colorOrder;
        targetPixelFormat.paletteType = PALETTE_NONE;
        targetPixelFormat.compressionType = targetCompressionType;

        bool hasCompressed = ConvertPixelData( engineInterface, pixelData, targetPixelFormat );

        if ( !hasCompressed )
        {
            throw RwException( "failed to compress raster" );
        }

        AdjustPixelDataDimensionsByFormat( engineInterface, texProvider, pixelData );

        // Put the new pixels into the texture.
        texNativeTypeProvider::acquireFeedback_t acquireFeedback;

        texProvider->SetPixelDataToTexture( engineInterface, platformTex, pixelData, acquireFeedback );

        hasDirectlyAcquired = acquireFeedback.hasDirectlyAcquired;
    }
    catch( ... )
    {
        pixelData.FreePixels( engineInterface );

        throw;
    }

    if ( hasDirectlyAcquired == false )
    {
        // Should never happen.
        pixelData.FreePixels( engineInterface );
    }
    else
    {
        pixelData.DetachPixels();
    }
}