Exemplo n.º 1
0
void Raster::compressCustom(eCompressionType targetCompressionType)
{
    scoped_rwlock_writer <rwlock> rasterConsistency( GetRasterLock( this ) );

    // Make sure we are mutable.
    NativeCheckRasterMutable( this );

    PlatformTexture *platformTex = this->platformData;

    if ( !platformTex )
    {
        throw RwException( "no native data" );
    }

    Interface *engineInterface = this->engineInterface;

    texNativeTypeProvider *texProvider = GetNativeTextureTypeProvider( engineInterface, platformTex );

    if ( !texProvider )
    {
        throw RwException( "invalid native data" );
    }

    // Avoid recompression.
    if ( IsNativeTextureCompressed( engineInterface, texProvider, platformTex ) )
        return;

    CompressNativeTexture( engineInterface, texProvider, platformTex, targetCompressionType );
}
Exemplo n.º 2
0
void readStringChunkANSI( Interface *engineInterface, BlockProvider& inputProvider, std::string& stringOut )
{
    BlockProvider stringBlock( &inputProvider );

    stringBlock.EnterContext();

    try
    {
        if ( stringBlock.getBlockID() == CHUNK_STRING )
        {
            int64 chunkLength = stringBlock.getBlockLength();

            if ( chunkLength < 0x80000000L )
            {
                size_t strLen = (size_t)chunkLength;

                char *buffer = new char[ strLen + 1 ];

                if ( buffer == NULL )
                {
                    throw RwException( "failed to allocate memory for string chunk" );
                }
                
                try
                {
                    stringBlock.read(buffer, strLen);

                    buffer[strLen] = '\0';

                    stringOut = buffer;
                }
                catch( ... )
                {
                    delete[] buffer;

                    throw;
                }

                delete[] buffer;
            }
            else
            {
                engineInterface->PushWarning( "too long string in string chunk" );
            }
        }
        else
        {
            engineInterface->PushWarning( "could not find string chunk" );
        }
    }
    catch( ... )
    {
        stringBlock.LeaveContext();

        throw;
    }

    stringBlock.LeaveContext();
}
Exemplo n.º 3
0
 void MagnifyFiltering(
     const resizeColorPipeline& srcBmp, uint32 magX, uint32 magY, uint32 magScaleX, uint32 magScaleY,
     resizeColorPipeline& dstBmp, uint32 dstX, uint32 dstY
 ) const override
 {
     // TODO.
     throw RwException( "not supported yet" );
 }
Exemplo n.º 4
0
void d3d12DriverInterface::RasterInstance( Interface *engineInterface, void *driverObjMem, void *objMem, Raster *sysRaster )
{
    if ( sysRaster->hasNativeDataOfType( "Direct3D9" ) == false )
    {
        throw RwException( "unsupported raster type for Direct3D 12 native raster instancing" );
    }

    // TODO.
}
Exemplo n.º 5
0
eCompressionType Raster::getCompressionFormat( void ) const
{
    scoped_rwlock_reader <rwlock> rasterConsistency( GetRasterLock( this ) );

    PlatformTexture *platformTex = this->platformData;

    if ( !platformTex )
    {
        throw RwException( "no native data" );
    }

    Interface *engineInterface = this->engineInterface;

    texNativeTypeProvider *texProvider = GetNativeTextureTypeProvider( engineInterface, platformTex );

    if ( !texProvider )
    {
        throw RwException( "invalid native data" );
    }

    return texProvider->GetTextureCompressionFormat( platformTex );
}
Exemplo n.º 6
0
bool ConvertMipmapLayerNative(
    Interface *engineInterface,
    uint32 mipWidth, uint32 mipHeight, uint32 layerWidth, uint32 layerHeight, void *srcTexels, uint32 srcDataSize,
    eRasterFormat srcRasterFormat, uint32 srcDepth, eColorOrdering srcColorOrder, ePaletteType srcPaletteType, const void *srcPaletteData, uint32 srcPaletteSize, eCompressionType srcCompressionType,
    eRasterFormat dstRasterFormat, uint32 dstDepth, eColorOrdering dstColorOrder, ePaletteType dstPaletteType, const void *dstPaletteData, uint32 dstPaletteSize, eCompressionType dstCompressionType,
    bool copyAnyway,
    uint32& dstPlaneWidthOut, uint32& dstPlaneHeightOut,
    void*& dstTexelsOut, uint32& dstDataSizeOut
)
{
    bool isMipLayerTexels = true;

    // Perform this like a pipeline with multiple stages.
    uint32 srcDXTType;
    uint32 dstDXTType;

    bool isSrcDXTType = IsDXTCompressionType( srcCompressionType, srcDXTType );
    bool isDstDXTType = IsDXTCompressionType( dstCompressionType, dstDXTType );

    bool requiresCompression = ( srcCompressionType != dstCompressionType );

    if ( requiresCompression )
    {
        if ( isSrcDXTType )
        {
            assert( srcPaletteType == PALETTE_NONE );

            // Decompress stuff.
            eDXTCompressionMethod dxtMethod = engineInterface->GetDXTRuntime();

            void *decompressedTexels;
            uint32 decompressedSize;

            bool success = decompressTexelsUsingDXT(
                engineInterface, srcDXTType, dxtMethod,
                mipWidth, mipHeight,
                layerWidth, layerHeight,
                srcTexels, dstRasterFormat, dstColorOrder, dstDepth,
                decompressedTexels, decompressedSize
            );

            assert( success == true );

            // Update with raw raster data.
            srcRasterFormat = dstRasterFormat;
            srcColorOrder = dstColorOrder;
            srcDepth = dstDepth;

            srcTexels = decompressedTexels;
            srcDataSize = decompressedSize;

            mipWidth = layerWidth;
            mipHeight = layerHeight;

            srcCompressionType = RWCOMPRESS_NONE;

            isMipLayerTexels = false;
        }
    }

    if ( srcCompressionType == RWCOMPRESS_NONE && dstCompressionType == RWCOMPRESS_NONE )
    {
        uint32 texUnitCount = ( mipWidth * mipHeight );

        void *newtexels = NULL;
        uint32 dstDataSize = 0;

        if ( dstPaletteType == PALETTE_NONE )
        {
            dstDataSize = getRasterDataSize( texUnitCount, dstDepth );

            newtexels = engineInterface->PixelAllocate( dstDataSize );

            // Do the conversion.
            for ( uint32 n = 0; n < texUnitCount; n++ )
            {
                uint8 r, g, b, a;

                bool gotColor = browsetexelcolor( srcTexels, srcPaletteType, srcPaletteData, srcPaletteSize, n, srcRasterFormat, srcColorOrder, srcDepth, r, g, b, a );

                if ( !gotColor )
                {
                    r = 0;
                    g = 0;
                    b = 0;
                    a = 0;
                }

                puttexelcolor( newtexels, n, dstRasterFormat, dstColorOrder, dstDepth, r, g, b, a );
            }
        }
        else if ( srcPaletteType != PALETTE_NONE )
        {
            if ( srcPaletteData == dstPaletteData )
            {
                // Fix the indice, if necessary.
                if ( srcDepth != dstDepth )
                {
                    dstDataSize = getRasterDataSize( texUnitCount, dstDepth );

                    newtexels = engineInterface->PixelAllocate( dstDataSize );

                    // Convert the depth.
                    ConvertPaletteDepth(
                        srcTexels, newtexels,
                        texUnitCount,
                        srcPaletteType, srcPaletteSize,
                        srcDepth, dstDepth
                    );
                }
            }
            else
            {
                // Remap texels.
                RemapMipmapLayer(
                    engineInterface,
                    dstRasterFormat, dstColorOrder,
                    srcTexels, texUnitCount,
                    srcRasterFormat, srcColorOrder, srcDepth, srcPaletteType, srcPaletteData, srcPaletteSize,
                    dstPaletteData, dstPaletteSize,
                    dstDepth, dstPaletteType,
                    newtexels, dstDataSize
                );
            }
        }
        else
        {
            // There must be a destination palette already allocated, as we cannot create one.
            assert( dstPaletteData != NULL );

            // Remap.
            RemapMipmapLayer(
                engineInterface,
                dstRasterFormat, dstColorOrder,
                srcTexels, texUnitCount,
                srcRasterFormat, srcColorOrder, srcDepth, srcPaletteType, srcPaletteData, srcPaletteSize,
                dstPaletteData, dstPaletteSize,
                dstDepth, dstPaletteType,
                newtexels, dstDataSize
            );
        }
        
        if ( newtexels != NULL )
        {
            if ( isMipLayerTexels == false )
            {
                // If we have temporary texels, remove them.
                engineInterface->PixelFree( srcTexels );
            }

            // Store the new texels.
            srcTexels = newtexels;
            srcDataSize = dstDataSize;

            // Update raster properties.
            srcRasterFormat = dstRasterFormat;
            srcColorOrder = dstColorOrder;
            srcDepth = dstDepth;

            isMipLayerTexels = false;
        }
    }

    if ( requiresCompression )
    {
        // Perform compression now.
        if ( isDstDXTType )
        {
            if ( dstDXTType == 2 || dstDXTType == 4 )
            {
                throw RwException( "unsupported DXT target in pixel conversion routine (sorry)" );
            }

            void *dstTexels;
            uint32 dstDataSize;

            uint32 newWidth, newHeight;

            compressTexelsUsingDXT(
                engineInterface,
                dstDXTType, srcTexels, mipWidth, mipHeight,
                srcRasterFormat, srcPaletteData, srcPaletteType, srcPaletteSize, srcColorOrder, srcDepth,
                dstTexels, dstDataSize,
                newWidth, newHeight
            );

            // Delete old texels (if necessary).
            if ( isMipLayerTexels == false )
            {
                engineInterface->PixelFree( srcTexels );
            }

            // Update parameters.
            srcTexels = dstTexels;
            srcDataSize = dstDataSize;

            // Clear raster format (for safety).
            srcRasterFormat = RASTER_DEFAULT;
            srcColorOrder = COLOR_BGRA;
            srcDepth = 16;

            mipWidth = newWidth;
            mipHeight = newHeight;
            
            srcCompressionType = dstCompressionType;

            isMipLayerTexels = false;
        }
    }

    // Output parameters.
    if ( copyAnyway == true || isMipLayerTexels == false )
    {
        dstPlaneWidthOut = mipWidth;
        dstPlaneHeightOut = mipHeight;

        dstTexelsOut = srcTexels;
        dstDataSizeOut = srcDataSize;

        return true;
    }

    return false;
}
Exemplo n.º 7
0
void genericCompressDXTNative( Interface *engineInterface, pixelDataTraversal& pixelData, uint32 dxtType )
{
    // We must get data in raw format.
    if ( pixelData.compressionType != RWCOMPRESS_NONE )
    {
        throw RwException( "runtime fault: attempting to compress an already compressed texture" );
    }

    if (dxtType != 1 && dxtType != 3 && dxtType != 5)
    {
        throw RwException( "cannot compress Direct3D textures using unsupported DXTn format" );
    }

    // We must have stand-alone pixel data.
    // Otherwise we could mess up pretty badly!
    assert( pixelData.isNewlyAllocated == true );

    // Compress it now.
    uint32 mipmapCount = pixelData.mipmaps.size();

    uint32 itemDepth = pixelData.depth;

    eRasterFormat rasterFormat = pixelData.rasterFormat;
    ePaletteType paletteType = pixelData.paletteType;
    eColorOrdering colorOrder = pixelData.colorOrder;

    uint32 maxpalette = pixelData.paletteSize;
    void *paletteData = pixelData.paletteData;

    for ( uint32 n = 0; n < mipmapCount; n++ )
    {
        pixelDataTraversal::mipmapResource& mipLayer = pixelData.mipmaps[ n ];

        uint32 mipWidth = mipLayer.width;
        uint32 mipHeight = mipLayer.height;

        void *texelSource = mipLayer.texels;

        void *dxtArray = NULL;
        size_t dxtDataSize = 0;

        // Create the new DXT array.
        uint32 realMipWidth, realMipHeight;

        compressTexelsUsingDXT(
            engineInterface,
            dxtType, texelSource, mipWidth, mipHeight,
            rasterFormat, paletteData, paletteType, maxpalette, colorOrder, itemDepth,
            dxtArray, dxtDataSize,
            realMipWidth, realMipHeight
        );

        // Delete the raw texels.
        engineInterface->PixelFree( texelSource );

        if ( mipWidth != realMipWidth )
        {
            mipLayer.width = realMipWidth;
        }

        if ( mipHeight != realMipHeight )
        {
            mipLayer.height = realMipHeight;
        }

        // Put in the new DXTn texels.
        mipLayer.texels = dxtArray;

        // Update fields.
        mipLayer.dataSize = dxtDataSize;
    }

    // We are finished compressing.
    // If we were palettized, unset that.
    if ( paletteType != PALETTE_NONE )
    {
        // Free the palette colors.
        engineInterface->PixelFree( paletteData );

        // Reset the fields.
        pixelData.paletteType = PALETTE_NONE;
        pixelData.paletteData = NULL;
        pixelData.paletteSize = 0;
    }

    // Set a virtual raster format.
    // This is what is done by the R* DXT output system.
    {
        uint32 newDepth = itemDepth;
        eRasterFormat virtualRasterFormat = RASTER_8888;

        if ( dxtType == 1 )
        {
            newDepth = 16;

            if ( pixelData.hasAlpha )
            {
                virtualRasterFormat = RASTER_1555;
            }
            else
            {
                virtualRasterFormat = RASTER_565;
            }
        }
        else if ( dxtType == 2 || dxtType == 3 || dxtType == 4 || dxtType == 5 )
        {
            newDepth = 16;

            virtualRasterFormat = RASTER_4444;
        }

        if ( rasterFormat != virtualRasterFormat )
        {
            pixelData.rasterFormat = virtualRasterFormat;
        }

        if ( newDepth != itemDepth )
        {
            pixelData.depth = newDepth;
        }
    }

    // We are now successfully compressed, so set the correct compression type.
    eCompressionType targetCompressionType = RWCOMPRESS_NONE;

    if ( dxtType == 1 )
    {
        targetCompressionType = RWCOMPRESS_DXT1;
    }
    else if ( dxtType == 2 )
    {
        targetCompressionType = RWCOMPRESS_DXT2;
    }
    else if ( dxtType == 3 )
    {
        targetCompressionType = RWCOMPRESS_DXT3;
    }
    else if ( dxtType == 4 )
    {
        targetCompressionType = RWCOMPRESS_DXT4;
    }
    else if ( dxtType == 5 )
    {
        targetCompressionType = RWCOMPRESS_DXT5;
    }
    else
    {
        throw RwException( "runtime fault: unknown compression type request in DXT compressor" );
    }

    pixelData.compressionType = targetCompressionType;
}
Exemplo n.º 8
0
void Raster::optimizeForLowEnd(float quality)
{
    PlatformTexture *platformTex = this->platformData;

    if ( !platformTex )
    {
        throw RwException( "no native data" );
    }

    Interface *engineInterface = this->engineInterface;

    texNativeTypeProvider *texProvider = GetNativeTextureTypeProvider( engineInterface, platformTex );

    if ( !texProvider )
    {
        throw RwException( "invalid native data" );
    }

    // To make good decisions, we need the storage capabilities of the texture.
    storageCapabilities storeCaps;

    texProvider->GetStorageCapabilities( storeCaps );

    // Textures that should run on low end hardware should not be too HD.
    // This routine takes the PlayStation 2 as reference hardware.

    const uint32 maxTexWidth = 256;
    const uint32 maxTexHeight = 256;

    while ( true )
    {
        // Get properties of this texture first.
        uint32 texWidth, texHeight;

        nativeTextureBatchedInfo nativeInfo;

        texProvider->GetTextureInfo( engineInterface, platformTex, nativeInfo );

        texWidth = nativeInfo.baseWidth;
        texHeight = nativeInfo.baseHeight;

        // Optimize this texture.
        bool hasTakenStep = false;

        if ( !hasTakenStep && quality < 1.0f )
        {
            // We first must make sure that the texture is not unnecessaringly huge.
            if ( texWidth > maxTexWidth || texHeight > maxTexHeight )
            {
                // Half the texture size until we are at a suitable size.
                uint32 targetWidth = texWidth;
                uint32 targetHeight = texHeight;

                do
                {
                    targetWidth /= 2;
                    targetHeight /= 2;
                }
                while ( targetWidth > maxTexWidth || targetHeight > maxTexHeight );

                // The texture dimensions are too wide.
                // We half the texture in size.
                this->resize( targetWidth, targetHeight );

                hasTakenStep = true;
            }
        }
        
        if ( !hasTakenStep )
        {
            // Can we store palette data?
            if ( storeCaps.pixelCaps.supportsPalette == true )
            {
                // We should decrease the texture size by palettization.
                ePaletteType currentPaletteType = texProvider->GetTexturePaletteType( platformTex );

                if (currentPaletteType == PALETTE_NONE)
                {
                    ePaletteType targetPalette = ( quality > 0.0f ) ? ( PALETTE_8BIT ) : ( PALETTE_4BIT );

                    // TODO: per mipmap alpha checking.

                    if (texProvider->DoesTextureHaveAlpha( platformTex ) == false)
                    {
                        // 4bit palette is only feasible for non-alpha textures (at higher quality settings).
                        // Otherwise counting the colors is too complicated.
                        
                        // TODO: still allow 8bit textures.
                        targetPalette = PALETTE_4BIT;
                    }

                    // The texture should be palettized for good measure.
                    this->convertToPalette( targetPalette );

                    // TODO: decide whether 4bit or 8bit palette.

                    hasTakenStep = true;
                }
            }
        }

        if ( !hasTakenStep )
        {
            // The texture dimension is important for renderer performance. That is why we need to scale the texture according
            // to quality settings aswell.

        }
    
        if ( !hasTakenStep )
        {
            break;
        }
    }
}
Exemplo n.º 9
0
void Raster::compress( float quality )
{
    scoped_rwlock_writer <rwlock> rasterConsistency( GetRasterLock( this ) );

    // Make sure we are mutable.
    NativeCheckRasterMutable( this );

    // A pretty complicated algorithm that can be used to optimally compress rasters.
    // Currently this only supports DXT.

    PlatformTexture *platformTex = this->platformData;

    if ( !platformTex )
    {
        throw RwException( "no native data" );
    }

    Interface *engineInterface = this->engineInterface;

    texNativeTypeProvider *texProvider = GetNativeTextureTypeProvider( engineInterface, platformTex );

    if ( !texProvider )
    {
        throw RwException( "invalid native data" );
    }

    // We should not continue if we are compressed already.
    storageCapabilities storeCaps;

    if ( IsNativeTextureCompressed( engineInterface, texProvider, platformTex, &storeCaps ) )
        return;

    // We want to check what kind of compression the target architecture supports.
    // If we have any compression support, we proceed to next stage.
    bool supportsDXT1 = false;
    bool supportsDXT2 = false;
    bool supportsDXT3 = false;
    bool supportsDXT4 = false;
    bool supportsDXT5 = false;

    pixelCapabilities inputTransferCaps;

    texProvider->GetPixelCapabilities( inputTransferCaps );

    // Now decide upon things.
    if ( inputTransferCaps.supportsDXT1 && storeCaps.pixelCaps.supportsDXT1 )
    {
        supportsDXT1 = true;
    }

    if ( inputTransferCaps.supportsDXT2 && storeCaps.pixelCaps.supportsDXT2 )
    {
        supportsDXT2 = true;
    }

    if ( inputTransferCaps.supportsDXT3 && storeCaps.pixelCaps.supportsDXT3 )
    {
        supportsDXT3 = true;
    }

    if ( inputTransferCaps.supportsDXT4 && storeCaps.pixelCaps.supportsDXT4 )
    {
        supportsDXT4 = true;
    }

    if ( inputTransferCaps.supportsDXT5 && storeCaps.pixelCaps.supportsDXT5 )
    {
        supportsDXT5 = true;
    }

    if ( supportsDXT1 == false &&
         supportsDXT2 == false &&
         supportsDXT3 == false &&
         supportsDXT4 == false &&
         supportsDXT5 == false )
    {
        throw RwException( "attempted to compress a raster that does not support compression" );
    }

    // We need to know about the alpha status of the texture to make a good decision.
    bool texHasAlpha = texProvider->DoesTextureHaveAlpha( platformTex );

    // Decide now what compression we want.
    eCompressionType targetCompressionType = RWCOMPRESS_NONE;

    bool couldDecide =
        DecideBestDXTCompressionFormat(
            engineInterface,
            texHasAlpha,
            supportsDXT1, supportsDXT2, supportsDXT3, supportsDXT4, supportsDXT5,
            quality,
            targetCompressionType
        );

    if ( !couldDecide )
    {
        throw RwException( "could not decide on an optimal DXT compression type" );
    }

    CompressNativeTexture( engineInterface, texProvider, platformTex, targetCompressionType );
}
Exemplo n.º 10
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();
    }
}
Exemplo n.º 11
0
void uncNativeTextureTypeProvider::DeserializeTexture( TextureBase *theTexture, PlatformTexture *nativeTex, BlockProvider& inputProvider ) const
{
    Interface *engineInterface = theTexture->engineInterface;

    // Read the texture native block.
    {
        BlockProvider texImageDataBlock( &inputProvider );

        texImageDataBlock.EnterContext();

        try
        {
            if ( texImageDataBlock.getBlockID() == CHUNK_STRUCT )
            {
                // Read the meta header first.
                mobile_unc::textureNativeGenericHeader metaHeader;

                texImageDataBlock.read( &metaHeader, sizeof( metaHeader ) );

                // Make sure we got the right platform descriptor.
                if ( metaHeader.platformDescriptor != PLATFORMDESC_UNC_MOBILE )
                {
                    throw RwException( "invalid platform descriptor in uncompressed mobile texture native" );
                }

                // Cast out native texture type.
                NativeTextureMobileUNC *platformTex = (NativeTextureMobileUNC*)nativeTex;

                // Read the format info.
                metaHeader.formatInfo.parse( *theTexture );

                // Read the texture names.
                {
                    char tmpbuf[ sizeof( metaHeader.name ) + 1 ];

                    // Make sure the name buffer is zero terminted.
                    tmpbuf[ sizeof( metaHeader.name ) ] = '\0';

                    // Move over the texture name.
                    memcpy( tmpbuf, metaHeader.name, sizeof( metaHeader.name ) );

                    theTexture->SetName( tmpbuf );

                    // Move over the texture mask name.
                    memcpy( tmpbuf, metaHeader.maskName, sizeof( metaHeader.maskName ) );

                    theTexture->SetMaskName( tmpbuf );
                }
                
                // Read some advanced properties.
                bool hasAlpha = metaHeader.hasAlpha;

                platformTex->hasAlpha = hasAlpha;
                
                platformTex->unk2 = metaHeader.unk2;
                platformTex->unk3 = metaHeader.unk3;

                assert( metaHeader.unk1 == false );
                assert( metaHeader.unk2 == 0 );

                // This texture format is very primitive.
                // It supports only RASTER_4444 textures with 16 depth.
                // Everything that this format stores is already storable in the Direct3D 8/9 platform.
                eRasterFormat rasterFormat;
                uint32 depth;
                eColorOrdering colorOrder;

                getUNCRasterFormat( hasAlpha, rasterFormat, colorOrder, depth );

                // Parse all mipmaps.
                // This format is pretty simple.
                uint32 maybeMipmapCount = metaHeader.mipmapCount;

                mipGenLevelGenerator mipLevelGen( metaHeader.width, metaHeader.height );

                if ( !mipLevelGen.isValidLevel() )
                {
                    throw RwException( "texture " + theTexture->GetName() + " has invalid dimensions" );
                }

                uint32 mipmap_index = 0;
                
                uint32 remainingTexImageDataSize = metaHeader.imageDataSectionSize;

                while ( true )
                {
                    if ( remainingTexImageDataSize == 0 )
                    {
                        break;
                    }

                    if ( mipmap_index >= maybeMipmapCount )
                    {
                        break;
                    }

                    bool couldEstablishLevel = true;

                    if ( mipmap_index > 0 )
                    {
                        couldEstablishLevel = mipLevelGen.incrementLevel();
                    }

                    if ( !couldEstablishLevel )
                    {
                        break;
                    }

                    // Create the new mipmap layer.
                    NativeTextureMobileUNC::mipmapLayer newLayer;

                    uint32 width = mipLevelGen.getLevelWidth();
                    uint32 height = mipLevelGen.getLevelHeight();

                    newLayer.layerWidth = width;
                    newLayer.layerHeight = height;

                    // Since we are an uncompressed texture, the layer dimensions equal the raw dimensions.
                    newLayer.width = width;
                    newLayer.height = height;

                    // Calculate the size of this layer.
                    uint32 texRowSize = getUNCRasterDataRowSize( width, depth );

                    uint32 texDataSize = getRasterDataSizeByRowSize( texRowSize, height );

                    // Reduce the texture image data section remainder.
                    if ( remainingTexImageDataSize < texDataSize )
                    {
                        throw RwException( "texture " + theTexture->GetName() + " has an invalid image data stream section size" );
                    }

                    remainingTexImageDataSize -= texDataSize;

                    // Store the texels.
                    texImageDataBlock.check_read_ahead( texDataSize );

                    void *texels = engineInterface->PixelAllocate( texDataSize );

                    try
                    {
                        texImageDataBlock.read( texels, texDataSize );
                    }
                    catch( ... )
                    {
                        engineInterface->PixelFree( texels );

                        throw;
                    }

                    newLayer.texels = texels;
                    newLayer.dataSize = texDataSize;

                    // Store this layer.
                    platformTex->mipmaps.push_back( newLayer );

                    // Increase the mipmap index.
                    mipmap_index++;
                }

                // We do not want no empty textures.
                if ( mipmap_index == 0 )
                {
                    throw RwException( "texture " + theTexture->GetName() + " is empty" );
                }

                // Fix filtering mode.
                fixFilteringMode( *theTexture, mipmap_index );

                int warningLevel = engineInterface->GetWarningLevel();

                // Check whether we have any remaining texture image data.
                if ( remainingTexImageDataSize != 0 )
                {
                    if ( warningLevel >= 3 )
                    {
                        engineInterface->PushWarning( "texture " + theTexture->GetName() + " has image data section meta-data" );
                    }

                    // Skip the meta-data.
                    texImageDataBlock.skip( remainingTexImageDataSize );
                }

                // We are done!
            }
            else
            {
                throw RwException( "could not find tex image data block in uncompressed mobile texture native" );
            }
        }
        catch( ... )
        {
            texImageDataBlock.LeaveContext();

            throw;
        }

        texImageDataBlock.LeaveContext();
    }

    // Deserialize extensions.
    engineInterface->DeserializeExtensions( theTexture, inputProvider );
}
Exemplo n.º 12
0
void d3d8NativeTextureTypeProvider::DeserializeTexture( TextureBase *theTexture, PlatformTexture *nativeTex, BlockProvider& inputProvider ) const
{
    Interface *engineInterface = theTexture->engineInterface;

    {
        BlockProvider texNativeImageStruct( &inputProvider );

        texNativeImageStruct.EnterContext();

        try
        {
            if ( texNativeImageStruct.getBlockID() == CHUNK_STRUCT )
            {
                d3d8::textureMetaHeaderStructGeneric metaHeader;
                texNativeImageStruct.read( &metaHeader, sizeof(metaHeader) );

	            uint32 platform = metaHeader.platformDescriptor;

	            if (platform != PLATFORM_D3D8)
                {
                    throw RwException( "invalid platform type in Direct3D 8 texture reading" );
                }

                // Recast the texture to our native type.
                NativeTextureD3D8 *platformTex = (NativeTextureD3D8*)nativeTex;

                int engineWarningLevel = engineInterface->GetWarningLevel();

                bool engineIgnoreSecureWarnings = engineInterface->GetIgnoreSecureWarnings();

                // Read the texture names.
                {
                    char tmpbuf[ sizeof( metaHeader.name ) + 1 ];

                    // Make sure the name buffer is zero terminted.
                    tmpbuf[ sizeof( metaHeader.name ) ] = '\0';

                    // Move over the texture name.
                    memcpy( tmpbuf, metaHeader.name, sizeof( metaHeader.name ) );

                    theTexture->SetName( tmpbuf );

                    // Move over the texture mask name.
                    memcpy( tmpbuf, metaHeader.maskName, sizeof( metaHeader.maskName ) );

                    theTexture->SetMaskName( tmpbuf );
                }

                // Read texture format.
                texFormatInfo formatInfo = metaHeader.texFormat;

                formatInfo.parse( *theTexture );

                // Deconstruct the format flags.
                bool hasMipmaps = false;    // TODO: actually use this flag.

                readRasterFormatFlags( metaHeader.rasterFormat, platformTex->rasterFormat, platformTex->paletteType, hasMipmaps, platformTex->autoMipmaps );

	            platformTex->hasAlpha = ( metaHeader.hasAlpha != 0 ? true : false );

                uint32 depth = metaHeader.depth;
                uint32 maybeMipmapCount = metaHeader.mipmapCount;

                platformTex->depth = depth;

                platformTex->rasterType = metaHeader.rasterType;

                // Decide about the color order.
                {
                    eColorOrdering colorOrder = COLOR_BGRA;

                    if ( platformTex->paletteType != PALETTE_NONE )
                    {
                        colorOrder = COLOR_RGBA;
                    }

                    platformTex->colorOrdering = colorOrder;
                }

                // Read compression information.
                {
                    uint32 dxtInfo = metaHeader.dxtCompression;

                    platformTex->dxtCompression = dxtInfo;

                    // If we are compressed, it must be a compression we know about.
                    if ( dxtInfo != 0 )
                    {
                        if ( dxtInfo != 1 && dxtInfo != 2 && dxtInfo != 3 && dxtInfo != 4 && dxtInfo != 5 )
                        {
                            throw RwException( "invalid Direct3D texture compression format" );
                        }
                    }
                }

                // Verify raster properties and attempt to fix broken textures.
                // Broken textures travel with mods like San Andreas Retextured.
                // - Verify depth.
                {
                    bool hasInvalidDepth = false;

                    if (platformTex->paletteType == PALETTE_4BIT)
                    {
                        if (depth != 4 && depth != 8)
                        {
                            hasInvalidDepth = true;
                        }
                    }
                    else if (platformTex->paletteType == PALETTE_8BIT)
                    {
                        if (depth != 8)
                        {
                            hasInvalidDepth = true;
                        }
                    }

                    if (hasInvalidDepth == true)
                    {
                        throw RwException( "texture " + theTexture->GetName() + " has an invalid depth" );

                        // We cannot fix an invalid depth.
                    }
                }
                
                if (platformTex->paletteType != PALETTE_NONE)
                {
                    uint32 reqPalItemCount = getD3DPaletteCount( platformTex->paletteType );

                    uint32 palDepth = Bitmap::getRasterFormatDepth( platformTex->rasterFormat );

                    assert( palDepth != 0 );

                    size_t paletteDataSize = getPaletteDataSize( reqPalItemCount, palDepth );

                    // Check whether we have palette data in the stream.
                    texNativeImageStruct.check_read_ahead( paletteDataSize );

                    void *palData = engineInterface->PixelAllocate( paletteDataSize );

                    try
                    {
	                    texNativeImageStruct.read( palData, paletteDataSize );
                    }
                    catch( ... )
                    {
                        engineInterface->PixelFree( palData );

                        throw;
                    }

                    // Store the palette.
                    platformTex->palette = palData;
                    platformTex->paletteSize = reqPalItemCount;
                }

                mipGenLevelGenerator mipLevelGen( metaHeader.width, metaHeader.height );

                if ( !mipLevelGen.isValidLevel() )
                {
                    throw RwException( "texture " + theTexture->GetName() + " has invalid dimensions" );
                }

                uint32 mipmapCount = 0;

                uint32 processedMipmapCount = 0;

                uint32 dxtCompression = platformTex->dxtCompression;

                bool hasDamagedMipmaps = false;

                for (uint32 i = 0; i < maybeMipmapCount; i++)
                {
                    bool couldEstablishLevel = true;

	                if (i > 0)
                    {
                        couldEstablishLevel = mipLevelGen.incrementLevel();
                    }

                    if (!couldEstablishLevel)
                    {
                        break;
                    }

                    // Create a new mipmap layer.
                    NativeTextureD3D8::mipmapLayer newLayer;

                    newLayer.layerWidth = mipLevelGen.getLevelWidth();
                    newLayer.layerHeight = mipLevelGen.getLevelHeight();

                    // Process dimensions.
                    uint32 texWidth = newLayer.layerWidth;
                    uint32 texHeight = newLayer.layerHeight;
                    {
		                // DXT compression works on 4x4 blocks,
		                // no smaller values allowed
		                if (dxtCompression != 0)
                        {
			                texWidth = ALIGN_SIZE( texWidth, 4u );
                            texHeight = ALIGN_SIZE( texHeight, 4u );
		                }
                    }

                    newLayer.width = texWidth;
                    newLayer.height = texHeight;

	                uint32 texDataSize = texNativeImageStruct.readUInt32();

                    // We started processing this mipmap.
                    processedMipmapCount++;

                    // Verify the data size.
                    bool isValidMipmap = true;
                    {
                        uint32 actualDataSize = 0;

                        if (dxtCompression != 0)
                        {
                            uint32 texItemCount = ( texWidth * texHeight );

                            actualDataSize = getDXTRasterDataSize(dxtCompression, texItemCount);
                        }
                        else
                        {
                            uint32 rowSize = getD3DRasterDataRowSize( texWidth, depth );

                            actualDataSize = getRasterDataSizeByRowSize( rowSize, texHeight );
                        }

                        if (actualDataSize != texDataSize)
                        {
                            isValidMipmap = false;
                        }
                    }

                    if ( !isValidMipmap )
                    {
                        // Even the Rockstar games texture generator appeared to have problems with mipmap generation.
                        // This is why textures appear to have the size of zero.

                        if (texDataSize != 0)
                        {
                            if ( !engineIgnoreSecureWarnings )
                            {
                               engineInterface->PushWarning( "texture " + theTexture->GetName() + " has damaged mipmaps (ignoring)" );
                            }

                            hasDamagedMipmaps = true;
                        }

                        // Skip the damaged bytes.
                        if (texDataSize != 0)
                        {
                            texNativeImageStruct.skip( texDataSize );
                        }
                        break;
                    }

                    // We first have to check whether there is enough data in the stream.
                    // Otherwise we would just flood the memory in case of an error;
                    // that could be abused by exploiters.
                    texNativeImageStruct.check_read_ahead( texDataSize );
                    
                    void *texelData = engineInterface->PixelAllocate( texDataSize );

                    try
                    {
	                    texNativeImageStruct.read( texelData, texDataSize );
                    }
                    catch( ... )
                    {
                        engineInterface->PixelFree( texelData );

                        throw;
                    }

                    // Store mipmap properties.
	                newLayer.dataSize = texDataSize;

                    // Store the image data pointer.
	                newLayer.texels = texelData;

                    // Put the layer.
                    platformTex->mipmaps.push_back( newLayer );

                    mipmapCount++;
                }
                
                if ( mipmapCount == 0 )
                {
                    throw RwException( "texture " + theTexture->GetName() + " is empty" );
                }

                // mipmapCount can only be smaller than maybeMipmapCount.
                // This is logically true and would be absurd to assert here.

                if ( processedMipmapCount < maybeMipmapCount )
                {
                    // Skip the remaining mipmaps (most likely zero-sized).
                    bool hasSkippedNonZeroSized = false;

                    for ( uint32 n = processedMipmapCount; n < maybeMipmapCount; n++ )
                    {
                        uint32 mipSize = texNativeImageStruct.readUInt32();

                        if ( mipSize != 0 )
                        {
                            hasSkippedNonZeroSized = true;

                            // Skip the section.
                            texNativeImageStruct.skip( mipSize );
                        }
                    }

                    if ( !engineIgnoreSecureWarnings && !hasDamagedMipmaps )
                    {
                        // Print the debug message.
                        if ( !hasSkippedNonZeroSized )
                        {
                            engineInterface->PushWarning( "texture " + theTexture->GetName() + " has zero sized mipmaps" );
                        }
                        else
                        {
                            engineInterface->PushWarning( "texture " + theTexture->GetName() + " violates mipmap rules" );
                        }
                    }
                }

                // Fix filtering mode.
                fixFilteringMode( *theTexture, mipmapCount );

                // - Verify auto mipmap
                {
                    bool hasAutoMipmaps = platformTex->autoMipmaps;

                    if ( hasAutoMipmaps )
                    {
                        bool canHaveAutoMipmaps = ( mipmapCount == 1 );

                        if ( !canHaveAutoMipmaps )
                        {
                            engineInterface->PushWarning( "texture " + theTexture->GetName() + " has an invalid auto-mipmap flag (fixing)" );

                            platformTex->autoMipmaps = false;
                        }
                    }
                }
            }
            else
            {
                engineInterface->PushWarning( "failed to find texture native image struct in D3D texture native" );
            }
        }
        catch( ... )
        {
            texNativeImageStruct.LeaveContext();

            throw;
        }

        texNativeImageStruct.LeaveContext();
    }

    // Read extensions.
    engineInterface->DeserializeExtensions( theTexture, inputProvider );
}
Exemplo n.º 13
0
void xboxNativeTextureTypeProvider::SerializeTexture( TextureBase *theTexture, PlatformTexture *nativeTex, BlockProvider& outputProvider ) const
{
    Interface *engineInterface = theTexture->engineInterface;

    // Cast the texture to our native type.
    NativeTextureXBOX *platformTex = (NativeTextureXBOX*)nativeTex;

    // Debug some essentials.
    ePaletteType paletteType = platformTex->paletteType;

    uint32 compressionType = platformTex->dxtCompression;

    // If we are not compressed, then the color order matters.
    if ( compressionType == 0 )
    {
        // XBOX textures are always BGRA.
        eColorOrdering requiredColorOrder = COLOR_BGRA;

        if ( platformTex->colorOrder != requiredColorOrder )
        {
            throw RwException( "texture " + theTexture->GetName() + " has an invalid color ordering for writing" );
        }
    }

    // Write the struct.
    {
        BlockProvider texImageDataBlock( &outputProvider );

        texImageDataBlock.EnterContext();

        try
        {
            // First comes the platform id.
            texImageDataBlock.writeUInt32( NATIVE_TEXTURE_XBOX );

            // Write the header.
            size_t mipmapCount = platformTex->mipmaps.size();
            {
                textureMetaHeaderStructXbox metaInfo;

                // Write addressing information.
                texFormatInfo infoOut;
                infoOut.set( *theTexture );

                metaInfo.formatInfo = infoOut;

                // Write texture names.
                // These need to be written securely.
                writeStringIntoBufferSafe( engineInterface, theTexture->GetName(), metaInfo.name, sizeof( metaInfo.name ), theTexture->GetName(), "name" );
                writeStringIntoBufferSafe( engineInterface, theTexture->GetMaskName(), metaInfo.maskName, sizeof( metaInfo.maskName ), theTexture->GetName(), "mask name" );

                // Construct raster flags.
                uint32 rasterFlags = generateRasterFormatFlags(platformTex->rasterFormat, paletteType, mipmapCount > 1, platformTex->autoMipmaps);

                // Store the flags.
                metaInfo.rasterFormat = rasterFlags;

                metaInfo.hasAlpha = ( platformTex->hasAlpha ? 1 : 0 );

                metaInfo.isCubeMap = ( platformTex->isCubeMap ? 1 : 0 );

                metaInfo.mipmapCount = (uint8)mipmapCount;

                metaInfo.rasterType = platformTex->rasterType;

                metaInfo.dxtCompression = compressionType;

                // Write the dimensions.
                metaInfo.width = platformTex->mipmaps[ 0 ].layerWidth;
                metaInfo.height = platformTex->mipmaps[ 0 ].layerHeight;

                metaInfo.depth = platformTex->depth;

                // Calculate the size of all the texture data combined.
                uint32 imageDataSectionSize = 0;

                for (size_t n = 0; n < mipmapCount; n++)
                {
                    imageDataSectionSize += platformTex->mipmaps[ n ].dataSize;
                }

                metaInfo.imageDataSectionSize = imageDataSectionSize;

                // Write the generic header.
                texImageDataBlock.write( &metaInfo, sizeof( metaInfo ) );
            }

            // Write palette data (if available).
            if (paletteType != PALETTE_NONE)
            {
                // Make sure we write as much data as the system expects.
                uint32 reqPalCount = getD3DPaletteCount(paletteType);

                uint32 palItemCount = platformTex->paletteSize;

                // Get the real data size of the palette.
                uint32 palRasterDepth = Bitmap::getRasterFormatDepth(platformTex->rasterFormat);

                uint32 paletteDataSize = getPaletteDataSize( palItemCount, palRasterDepth );

                uint32 palByteWriteCount = writePartialBlockSafe(texImageDataBlock, platformTex->palette, paletteDataSize, getPaletteDataSize(reqPalCount, palRasterDepth));
        
                assert( palByteWriteCount * 8 / palRasterDepth == reqPalCount );
            }

            // Write mipmap data.
            for ( size_t n = 0; n < mipmapCount; n++ )
            {
                const NativeTextureXBOX::mipmapLayer& mipLayer = platformTex->mipmaps[ n ];

			    uint32 texDataSize = mipLayer.dataSize;

                const void *texelData = mipLayer.texels;

			    texImageDataBlock.write( texelData, texDataSize );
            }
        }
        catch( ... )
        {
            texImageDataBlock.LeaveContext();

            throw;
        }

        texImageDataBlock.LeaveContext();
    }

	// Extension
	engineInterface->SerializeExtensions( theTexture, outputProvider );
}