/// <summary>
        /// Draw the picture on Surface
        /// </summary>
        /// <param name="surfaceId"></param>
        /// <param name="destRect"></param>
        public void RenderRemoteFXTile(ushort surfaceId, RDPGFX_RECT16 destRect)
        {
            if (surfaceDic.ContainsKey(surfaceId))
            {
                Surface sur = surfaceDic[surfaceId];

                byte quantIdxY  = remoteFXContext.TileSet.tiles[0].quantIdxY;
                byte quantIdxCb = remoteFXContext.TileSet.tiles[0].quantIdxCb;
                byte quantIdxCr = remoteFXContext.TileSet.tiles[0].quantIdxCr;
                RemoteFXCodecContext context = new RemoteFXCodecContext(remoteFXContext.TileSet.quantVals, quantIdxY, quantIdxCb, quantIdxCr, remoteFXContext.Entropy);
                foreach (TS_RFX_TILE tile in remoteFXContext.TileSet.tiles)
                {
                    RemoteFXDecoder.DecodeTile(context, tile.YData, tile.CbData, tile.CrData);
                    for (int i = 0; i < RgbTile.TileSize; i++)
                    {
                        for (int j = 0; j < RgbTile.TileSize; j++)
                        {
                            int x = tile.xIdx + i;
                            int y = tile.yIdx + j;
                            if (IsInRects(x, y, remoteFXContext.Region.rects))
                            {
                                if (destRect.left + x < destRect.right && destRect.top + y < destRect.bottom)
                                {
                                    sur.SetPixel(destRect.left + x, destRect.top + y, Color.FromArgb(context.RSet[i, j], context.GSet[i, j], context.BSet[i, j]));
                                }
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Draw the picture on output screen
        /// SetRemoteFXRegion and SetRemoteFXTileSet must be called before calling this method
        /// </summary>
        /// <param name="left"></param>
        /// <param name="top"></param>
        /// <param name="surfaceId"></param>
        public void RenderRemoteFXTile(ushort left, ushort top)
        {
            Bitmap image                 = baseImage;
            byte   quantIdxY             = remoteFXContext.TileSet.tiles[0].quantIdxY;
            byte   quantIdxCb            = remoteFXContext.TileSet.tiles[0].quantIdxCb;
            byte   quantIdxCr            = remoteFXContext.TileSet.tiles[0].quantIdxCr;
            RemoteFXCodecContext context = new RemoteFXCodecContext(remoteFXContext.TileSet.quantVals, quantIdxY, quantIdxCb, quantIdxCr, remoteFXContext.Entropy);

            foreach (TS_RFX_TILE tile in remoteFXContext.TileSet.tiles)
            {
                RemoteFXDecoder.DecodeTile(context, tile.YData, tile.CbData, tile.CrData);
                for (int i = 0; i < RgbTile.TileSize; i++)
                {
                    for (int j = 0; j < RgbTile.TileSize; j++)
                    {
                        int x = tile.xIdx * 64 + i;
                        int y = tile.yIdx * 64 + j;
                        if (IsInRects(x, y, remoteFXContext.Region.rects))
                        {
                            image.SetPixel(left + x, top + y, Color.FromArgb(context.RSet[i, j], context.GSet[i, j], context.BSet[i, j]));
                        }
                    }
                }
            }
        }
        private static void InverseDWT_2D(short[,] data2D, int pass)
        {
            //level > 0
            //data2D.Length % (1<<(level - 1)) == 0
            int inScopelen;

            switch (pass)
            {
            case 1:
            {
                // First pass
                inScopelen = 64;
                break;
            }

            case 2:
            {
                // Second pass
                inScopelen = 33;
                break;
            }

            case 3:
            {
                // Third pass
                inScopelen = 17;
                break;
            }

            default:
            {
                throw new InvalidOperationException("DWT_2D: the parameter level should only be 1, 2, or 3.");
            }
            }

            //Horizontal DWT
            for (int y = 0; y < inScopelen; y++)
            {
                short[] row;
                RemoteFXDecoder.getRowFrom2DArr <short>(data2D, out row, y, inScopelen);
                row = InverseDWT_1D(row);
                for (int x = 0; x < inScopelen; x++)
                {
                    data2D[x, y] = row[x];
                }
            }

            //Vertical DWT
            for (int x = 0; x < inScopelen; x++)
            {
                short[] col;
                RemoteFXDecoder.getColFrom2DArr <short>(data2D, out col, x, inScopelen);
                col = InverseDWT_1D(col);
                for (int y = 0; y < inScopelen; y++)
                {
                    data2D[x, y] = col[y];
                }
            }
        }
        /// <summary>
        /// Decode a tile from DWT
        /// </summary>
        /// <param name="codecContext">The codec context which contains the DWT data of a tile.</param>
        public static void DecodeTileFromDwtQ(RfxProgressiveCodecContext codecContext)
        {
            //Sub Band Reconstruction
            SubBandReconstruction(codecContext);

            //De-quantization
            Dequantization(codecContext);

            //Inverse DWT
            if (codecContext.UseReduceExtrapolate)
            {
                InverseDWT(codecContext);
            }
            else
            {
                RemoteFXDecoder.InverseDWT(codecContext);
            }

            //(Y, U, V) to (R, G, B)
            RemoteFXDecoder.YCbCrToRGB(codecContext);
        }
        /// <summary>
        /// Decode an encoded tile
        /// </summary>
        /// <param name="enTile">Represents an encoded tile.</param>
        /// <param name="tState">The context state of the tile that going to be decoded.</param>
        public static void DecodeTile(EncodedTile enTile, TileState tState)
        {
            RfxProgressiveCodecContext codecContext = new RfxProgressiveCodecContext(
                enTile.CodecQuantVals,
                enTile.QuantIdxY,
                enTile.QuantIdxCb,
                enTile.QuantIdxCr,
                enTile.DataType == EncodedTileType.Simple ? false : true,
                enTile.IsDifferenceTile,
                enTile.UseReduceExtrapolate);

            //RLGR/SRL Decode
            if (enTile.DataType == EncodedTileType.FirstPass || enTile.DataType == EncodedTileType.Simple)
            {   //first pass or simple
                codecContext.YData  = enTile.YEncodedData;
                codecContext.CbData = enTile.CbEncodedData;
                codecContext.CrData = enTile.CrEncodedData;
                RemoteFXDecoder.RLGRDecode(codecContext);
                ComputeOriginalLL3FromDeltas(codecContext);
            }
            else
            {
                SRLDecode(codecContext, enTile, tState);
            }

            //Progressive Dequantization
            if (enTile.DataType != EncodedTileType.Simple)
            {
                ProgressiveDeQuantization(codecContext, enTile.ProgCodecQuant);
            }

            // Create a DwtTile instance for tri-state
            DwtTile triStateDwt = new DwtTile(codecContext.YComponent, codecContext.CbComponent, codecContext.CrComponent,
                                              enTile.CodecQuantVals, enTile.QuantIdxY, enTile.QuantIdxCb, enTile.QuantIdxCr, enTile.UseReduceExtrapolate, enTile.ProgCodecQuant);

            //Set Tri-State for progressive codec
            if (enTile.DataType == EncodedTileType.FirstPass)
            {
                //DwtTile tileTriStat = SetTriState(diffDwt, enTile.UseReduceExtrapolate);
                tState.UpdateTriState(triStateDwt);
            }
            else if (enTile.DataType == EncodedTileType.UpgradePass)
            {
                DwtTile prvStat = tState.GetTriState();
                prvStat.Add(triStateDwt);
                // update ProCodecQuant
                prvStat.ProgCodecQuant = triStateDwt.ProgCodecQuant;
                tState.UpdateTriState(prvStat);
            }

            // Create another DwtTile instance for DWT Data.
            // The data in diffDwt is the same as triStateDwt, this will makesure the DWT data and tri-state not share the same DWT tile instance
            DwtTile diffDwt = new DwtTile(codecContext.YComponent, codecContext.CbComponent, codecContext.CrComponent,
                                          enTile.CodecQuantVals, enTile.QuantIdxY, enTile.QuantIdxCb, enTile.QuantIdxCr, enTile.UseReduceExtrapolate, enTile.ProgCodecQuant);

            //Sum difference
            if (enTile.IsDifferenceTile || enTile.DataType == EncodedTileType.UpgradePass)
            {
                tState.AddDwt(diffDwt);
            }
            else
            {
                tState.UpdateDwt(diffDwt);
            }
        }