Exemple #1
0
        private void Decode_COMPRESSED_DXT1()
        {
            var colors = new OutputPixel[4];

            for (int y = 0, ni = 0; y < _height; y += 4)
            {
                for (int x = 0; x < _width; x += 4, ni++)
                {
                    var block = ((Dxt1Block *)_inputByte)[ni];

                    colors[0] = Decode_RGBA_5650_Pixel(block.Color0)
                                .Transform((r, g, b, a) => OutputPixel.FromRgba(b, g, r, a));
                    colors[1] = Decode_RGBA_5650_Pixel(block.Color1)
                                .Transform((r, g, b, a) => OutputPixel.FromRgba(b, g, r, a));

                    if (block.Color0 > block.Color1)
                    {
                        colors[2] = OutputPixel.OperationPerComponent(colors[0], colors[1],
                                                                      (a, b) => (byte)(a * 2 / 3 + b * 1 / 3));
                        colors[3] = OutputPixel.OperationPerComponent(colors[0], colors[1],
                                                                      (a, b) => (byte)(a * 1 / 3 + b * 2 / 3));
                    }
                    else
                    {
                        colors[2] = OutputPixel.OperationPerComponent(colors[0], colors[1],
                                                                      (a, b) => (byte)(a * 1 / 2 + b * 1 / 2));
                        colors[3] = OutputPixel.FromRgba(0, 0, 0, 0);
                    }

                    var no = 0;
                    for (var y2 = 0; y2 < 4; y2++)
                    {
                        for (var x2 = 0; x2 < 4; x2++, no++)
                        {
                            var color = (block.ColorLookup >> (2 * no)) & 0x3;

                            var rx = x + x2;
                            var ry = y + y2;
                            var n  = ry * _width + rx;

                            _output[n] = colors[color];
                        }
                    }
                }
            }
        }
        /// <summary>
        /// DXT2 and DXT3 (collectively also known as Block Compression 2 or BC2) converts 16 input pixels
        /// (corresponding to a 4x4 pixel block) into 128 bits of output, consisting of 64 bits of alpha channel data
        /// (4 bits for each pixel) followed by 64 bits of color data, encoded the same way as DXT1 (with the exception
        /// that the 4 color version of the DXT1 algorithm is always used instead of deciding which version to use based
        /// on the relative values of  and ). In DXT2, the color data is interpreted as being premultiplied by alpha, in
        /// DXT3 it is interpreted as not having been premultiplied by alpha. Typically DXT2/3 are well suited to images
        /// with sharp alpha transitions, between translucent and opaque areas.
        /// </summary>
        private void Decode_COMPRESSED_DXT3()
        {
            var colors = new OutputPixel[4];

            var ni = 0;

            for (var y = 0; y < _height; y += 4)
            {
                for (var x = 0; x < _width; x += 4, ni++)
                {
                    var block = ((Dxt3Block *)_inputByte)[ni];
                    colors[0] = Decode_RGBA_5650_Pixel(block.Color0)
                                .Transform((r, g, b, a) => OutputPixel.FromRgba(b, g, r, a));
                    colors[1] = Decode_RGBA_5650_Pixel(block.Color1)
                                .Transform((r, g, b, a) => OutputPixel.FromRgba(b, g, r, a));
                    colors[2] = OutputPixel.OperationPerComponent(colors[0], colors[1],
                                                                  (a, b) => (byte)(((a * 2) / 3) + ((b * 1) / 3)));
                    colors[3] = OutputPixel.OperationPerComponent(colors[0], colors[1],
                                                                  (a, b) => (byte)(((a * 1) / 3) + ((b * 2) / 3)));

                    var no = 0;
                    for (var y2 = 0; y2 < 4; y2++)
                    {
                        for (var x2 = 0; x2 < 4; x2++, no++)
                        {
                            var alpha = (block.Alpha >> (4 * no)) & 0xF;
                            var color = (block.ColorLookup >> (2 * no)) & 0x3;

                            var rx = (x + x2);
                            var ry = (y + y2);
                            var n  = ry * _width + rx;

                            _output[n]   = colors[color];
                            _output[n].A = (byte)((alpha * 0xFF) / 0xF);
                        }
                    }
                }
            }
        }
Exemple #3
0
        private void Decode_COMPRESSED_DXT5()
        {
            //Console.Error.WriteLine("Not Implemented: Decode_COMPRESSED_DXT5");
            //throw new NotImplementedException();

            //_Decode_Unimplemented();

            var colors = new OutputPixel[4];

            var ni = 0;

            for (var y = 0; y < _height; y += 4)
            {
                for (var x = 0; x < _width; x += 4, ni++)
                {
                    var block = ((Dxt5Block *)_inputByte)[ni];
                    colors[0] = Decode_RGBA_5650_Pixel(block.Color0)
                                .Transform((r, g, b, a) => OutputPixel.FromRgba(b, g, r, a));
                    colors[1] = Decode_RGBA_5650_Pixel(block.Color1)
                                .Transform((r, g, b, a) => OutputPixel.FromRgba(b, g, r, a));
                    colors[2] = OutputPixel.OperationPerComponent(colors[0], colors[1],
                                                                  (a, b) => (byte)(a * 2 / 3 + b * 1 / 3));
                    colors[3] = OutputPixel.OperationPerComponent(colors[0], colors[1],
                                                                  (a, b) => (byte)(a * 1 / 3 + b * 2 / 3));

                    // Create Alpha Lookup
                    var alphaLookup = new byte[8];
                    var alphas      = (ushort)(block.Alpha >> 48);
                    var alpha0      = (byte)((alphas >> 0) & 0xFF);
                    var alpha1      = (byte)((alphas >> 8) & 0xFF);

                    alphaLookup[0] = alpha0;
                    alphaLookup[1] = alpha1;
                    if (alpha0 > alpha1)
                    {
                        alphaLookup[2] = (byte)((6 * alpha0 + alpha1) / 7);
                        alphaLookup[3] = (byte)((5 * alpha0 + 2 * alpha1) / 7);
                        alphaLookup[4] = (byte)((4 * alpha0 + 3 * alpha1) / 7);
                        alphaLookup[5] = (byte)((3 * alpha0 + 4 * alpha1) / 7);
                        alphaLookup[6] = (byte)((2 * alpha0 + 5 * alpha1) / 7);
                        alphaLookup[7] = (byte)((alpha0 + 6 * alpha1) / 7);
                    }
                    else
                    {
                        alphaLookup[2] = (byte)((4 * alpha0 + alpha1) / 5);
                        alphaLookup[3] = (byte)((3 * alpha0 + 2 * alpha1) / 5);
                        alphaLookup[4] = (byte)((2 * alpha0 + 3 * alpha1) / 5);
                        alphaLookup[5] = (byte)((alpha0 + 4 * alpha1) / 5);
                        alphaLookup[6] = (byte)0x00;
                        alphaLookup[7] = (byte)0xFF;
                    }

                    var no = 0;
                    for (var y2 = 0; y2 < 4; y2++)
                    {
                        for (var x2 = 0; x2 < 4; x2++, no++)
                        {
                            var alpha = alphaLookup[(block.Alpha >> (3 * no)) & 0x7];
                            var color = (block.ColorLookup >> (2 * no)) & 0x3;

                            var rx = x + x2;
                            var ry = y + y2;
                            var n  = ry * _width + rx;

                            _output[n]   = colors[color];
                            _output[n].A = alpha;
                        }
                    }
                }
            }
        }
Exemple #4
0
        public TTexture Get(GpuStateStruct GpuState)
        {
            var TextureMappingState = GpuState.TextureMappingState;
            var ClutState           = TextureMappingState.ClutState;
            var TextureState        = TextureMappingState.TextureState;

            TTexture Texture;
            //GC.Collect();
            bool Swizzled       = TextureState.Swizzled;
            uint TextureAddress = TextureState.Mipmap0.Address;
            uint ClutAddress    = ClutState.Address;
            var  ClutFormat     = ClutState.PixelFormat;
            var  ClutStart      = ClutState.Start;
            var  ClutDataStart  = PixelFormatDecoder.GetPixelsSize(ClutFormat, ClutStart);

            ulong Hash1   = TextureAddress | (ulong)((ClutAddress + ClutDataStart) << 32);
            bool  Recheck = false;

            if (Cache.TryGetValue(Hash1, out Texture))
            {
                if (Texture.RecheckTimestamp != RecheckTimestamp)
                {
                    Recheck = true;
                }
            }
            else
            {
                Recheck = true;
            }

            if (Recheck)
            {
                //Console.Write(".");

                //Console.WriteLine("{0:X}", ClutAddress);

                var TextureFormat = TextureState.PixelFormat;
                //var Width = TextureState->Mipmap0.TextureWidth;

                int BufferWidth = TextureState.Mipmap0.BufferWidth;

                // FAKE!
                //BufferWidth = TextureState->Mipmap0.TextureWidth;

                var Height          = TextureState.Mipmap0.TextureHeight;
                var TextureDataSize = PixelFormatDecoder.GetPixelsSize(TextureFormat, BufferWidth * Height);
                if (ClutState.NumberOfColors > 256)
                {
                    ClutState.NumberOfColors = 256;
                }
                var ClutDataSize = PixelFormatDecoder.GetPixelsSize(ClutFormat, ClutState.NumberOfColors);
                var ClutCount    = ClutState.NumberOfColors;
                var ClutShift    = ClutState.Shift;
                var ClutMask     = ClutState.Mask;

                //Console.WriteLine(TextureFormat);

                // INVALID TEXTURE
                if (!PspMemory.IsRangeValid(TextureAddress, TextureDataSize) || TextureDataSize > 2048 * 2048 * 4)
                {
                    Console.Error.WriteLineColored(ConsoleColor.DarkRed,
                                                   "UPDATE_TEXTURE(TEX={0},CLUT={1}:{2}:{3}:{4}:0x{5:X},SIZE={6}x{7},{8},Swizzled={9})",
                                                   TextureFormat, ClutFormat, ClutCount, ClutStart, ClutShift, ClutMask, BufferWidth, Height,
                                                   BufferWidth, Swizzled);
                    Console.Error.WriteLineColored(ConsoleColor.DarkRed,
                                                   "Invalid TEXTURE! TextureAddress=0x{0:X}, TextureDataSize={1}", TextureAddress,
                                                   TextureDataSize);
                    if (InvalidTexture == null)
                    {
                        InvalidTexture = new TTexture();
                        InvalidTexture.Init(GpuImpl);

                        int InvalidTextureWidth = 2, InvalidTextureHeight = 2;
                        int InvalidTextureSize = InvalidTextureWidth * InvalidTextureHeight;
                        var Data = new OutputPixel[InvalidTextureSize];
                        fixed(OutputPixel *DataPtr = Data)
                        {
                            var Color1 = OutputPixel.FromRgba(0xFF, 0x00, 0x00, 0xFF);
                            var Color2 = OutputPixel.FromRgba(0x00, 0x00, 0xFF, 0xFF);

                            for (int n = 0; n < InvalidTextureSize; n++)
                            {
                                DataPtr[n] = (n & 1) != 0 ? Color1 : Color2;
                            }
                            InvalidTexture.SetData(Data, InvalidTextureWidth, InvalidTextureHeight);
                        }
                    }
                    return(InvalidTexture);
                }

                //Console.WriteLine("TextureAddress=0x{0:X}, TextureDataSize=0x{1:X}", TextureAddress, TextureDataSize);

                byte *TexturePointer = null;
                byte *ClutPointer    = null;

                try
                {
                    TexturePointer = (byte *)PspMemory.PspAddressToPointerSafe(TextureAddress);
                    ClutPointer    = (byte *)PspMemory.PspAddressToPointerSafe(ClutAddress);
                }
                catch (PspMemory.InvalidAddressException InvalidAddressException)
                {
                    throw InvalidAddressException;
                }

                TextureCacheKey TextureCacheKey = new TextureCacheKey()
                {
                    TextureAddress = TextureAddress,
                    TextureFormat  = TextureFormat,
                    TextureHash    = FastHash(TexturePointer, TextureDataSize),

                    ClutHash    = FastHash(&ClutPointer[ClutDataStart], ClutDataSize),
                    ClutAddress = ClutAddress,
                    ClutFormat  = ClutFormat,
                    ClutStart   = ClutStart,
                    ClutShift   = ClutShift,
                    ClutMask    = ClutMask,
                    Swizzled    = Swizzled,

                    ColorTestEnabled  = GpuState.ColorTestState.Enabled,
                    ColorTestRef      = GpuState.ColorTestState.Ref,
                    ColorTestMask     = GpuState.ColorTestState.Mask,
                    ColorTestFunction = GpuState.ColorTestState.Function,
                };

                if (Texture == null || !Texture.TextureCacheKey.Equals(TextureCacheKey))
                {
                    string TextureName = "texture_" + TextureCacheKey.TextureHash + "_" + TextureCacheKey.ClutHash +
                                         "_" + TextureFormat + "_" + ClutFormat + "_" + BufferWidth + "x" + Height +
                                         "_" + Swizzled;
#if DEBUG_TEXTURE_CACHE
                    Console.Error.WriteLine("UPDATE_TEXTURE(TEX={0},CLUT={1}:{2}:{3}:{4}:0x{5:X},SIZE={6}x{7},{8},Swizzled={9})", TextureFormat, ClutFormat, ClutCount, ClutStart, ClutShift, ClutMask, BufferWidth, Height, BufferWidth, Swizzled);
#endif
                    Texture = new TTexture();
                    Texture.Init(GpuImpl);
                    Texture.TextureCacheKey = TextureCacheKey;
                    //Texture.Hash = Hash1;

                    {
                        //int TextureWidth = Math.Max(BufferWidth, Height);
                        //int TextureHeight = Math.Max(BufferWidth, Height);
                        int TextureWidth       = BufferWidth;
                        int TextureHeight      = Height;
                        int TextureWidthHeight = TextureWidth * TextureHeight;

                        fixed(OutputPixel *TexturePixelsPointer = DecodedTextureBuffer)
                        {
                            if (Swizzled)
                            {
                                fixed(byte *SwizzlingBufferPointer = SwizzlingBuffer)
                                {
                                    PointerUtils.Memcpy(SwizzlingBuffer, TexturePointer, TextureDataSize);
                                    PixelFormatDecoder.UnswizzleInline(TextureFormat, (void *)SwizzlingBufferPointer,
                                                                       BufferWidth, Height);
                                    PixelFormatDecoder.Decode(
                                        TextureFormat, (void *)SwizzlingBufferPointer, TexturePixelsPointer,
                                        BufferWidth, Height,
                                        ClutPointer, ClutFormat, ClutCount, ClutStart, ClutShift, ClutMask,
                                        strideWidth: PixelFormatDecoder.GetPixelsSize(TextureFormat, TextureWidth)
                                        );
                                }
                            }
                            else
                            {
                                PixelFormatDecoder.Decode(
                                    TextureFormat, (void *)TexturePointer, TexturePixelsPointer, BufferWidth, Height,
                                    ClutPointer, ClutFormat, ClutCount, ClutStart, ClutShift, ClutMask,
                                    strideWidth: PixelFormatDecoder.GetPixelsSize(TextureFormat, TextureWidth)
                                    );
                            }

                            if (TextureCacheKey.ColorTestEnabled)
                            {
                                byte EqualValue, NotEqualValue;

                                switch (TextureCacheKey.ColorTestFunction)
                                {
                                case ColorTestFunctionEnum.GuAlways:
                                    EqualValue    = 0xFF;
                                    NotEqualValue = 0xFF;
                                    break;

                                case ColorTestFunctionEnum.GuNever:
                                    EqualValue    = 0x00;
                                    NotEqualValue = 0x00;
                                    break;

                                case ColorTestFunctionEnum.GuEqual:
                                    EqualValue    = 0xFF;
                                    NotEqualValue = 0x00;
                                    break;

                                case ColorTestFunctionEnum.GuNotequal:
                                    EqualValue    = 0x00;
                                    NotEqualValue = 0xFF;
                                    break;

                                default: throw new NotImplementedException();
                                }

                                ConsoleUtils.SaveRestoreConsoleState(() =>
                                {
                                    Console.BackgroundColor = ConsoleColor.Red;
                                    Console.ForegroundColor = ConsoleColor.Yellow;
                                    Console.Error.WriteLine("{0} : {1}, {2} : ref:{3} : mask:{4}",
                                                            TextureCacheKey.ColorTestFunction, EqualValue, NotEqualValue,
                                                            TextureCacheKey.ColorTestRef, TextureCacheKey.ColorTestMask);
                                });

                                for (int n = 0; n < TextureWidthHeight; n++)
                                {
                                    if ((TexturePixelsPointer[n] & TextureCacheKey.ColorTestMask).Equals(
                                            TextureCacheKey.ColorTestRef & TextureCacheKey.ColorTestMask))
                                    {
                                        TexturePixelsPointer[n].A = EqualValue;
                                    }
                                    else
                                    {
                                        TexturePixelsPointer[n].A = NotEqualValue;
                                    }
                                    if (TexturePixelsPointer[n].A == 0)
                                    {
                                        //Console.Write("yup!");
                                    }
                                }
                            }

                            var TextureInfo = new TextureHookInfo()
                            {
                                TextureCacheKey = TextureCacheKey,
                                Data            = DecodedTextureBuffer,
                                Width           = TextureWidth,
                                Height          = TextureHeight
                            };

                            MessageBus.Dispatch(TextureInfo);

                            var Result = Texture.SetData(TextureInfo.Data, TextureInfo.Width, TextureInfo.Height);
                        }
                    }
                    if (Cache.ContainsKey(Hash1))
                    {
                        Cache[Hash1].Dispose();
                    }
                    Cache[Hash1] = Texture;
                }
            }

            Texture.RecheckTimestamp = RecheckTimestamp;

            return(Texture);
        }