void CRLC<T>::doEncode(CImage<T> * pImg, CBitstream * pBstr) { for(int k=0;k<pImg->getComponents(); k++) { CSize size((*pImg)[k].getHeight(), (*pImg)[k].getWidth()); for(int y=0; y < (*pImg)[k].getHeight(); y+=8) { for(int x=0; x < (*pImg)[k].getWidth(); x+=8) { EncodeBlock(&(*pImg)[k][0][0], CPoint(k, y, x), size, pBstr); } } } }
/// RefinementScan::WriteMCU // Write a single MCU in this scan. Return true if there are more blocks in this row. bool RefinementScan::WriteMCU(void) { bool more = true; int c; assert(m_pBlockCtrl); BeginWriteMCU(m_bMeasure?NULL:m_Stream.ByteStreamOf()); for(c = 0;c < m_ucCount;c++) { class Component *comp = m_pComponent[c]; class QuantizedRow *q = m_pBlockCtrl->CurrentQuantizedRow(comp->IndexOf()); class HuffmanCoder *ac = m_pACCoder[c]; class HuffmanStatistics *acstat = m_pACStatistics[c]; UWORD &skip = m_usSkip[c]; UBYTE mcux = (m_ucCount > 1)?(comp->MCUWidthOf() ):(1); UBYTE mcuy = (m_ucCount > 1)?(comp->MCUHeightOf()):(1); ULONG xmin = m_ulX[c]; ULONG xmax = xmin + mcux; ULONG x,y; if (xmax >= q->WidthOf()) { more = false; } for(y = 0;y < mcuy;y++) { for(x = xmin;x < xmax;x++) { LONG *block,dummy[64]; if (q && x < q->WidthOf()) { block = q->BlockAt(x)->m_Data; } else { block = dummy; memset(dummy ,0,sizeof(dummy) ); } if (m_bMeasure) { MeasureBlock(block,acstat,skip); } else { EncodeBlock(block,ac,skip); } } if (q) q = q->NextOf(); } // Done with this component, advance the block. m_ulX[c] = xmax; } return more; }
// Encode a source buffer, adding padding and line breaks void Encode(const unsigned char *src, size_t len, std::vector<unsigned char> &dst) { const size_t lineSize = 0; // Do not insert linefeeds (illegal in JSON) size_t blocksOut = 0; for (size_t j = 0; j < len; /*EMPTY*/) { size_t k = 0; unsigned char in[3], out[4]; for (size_t i = 0; i < 3; ++i) { if (j < len) { ++k; in[i] = src[j++]; } else { in[i] = 0; } } if (k) { EncodeBlock(in, out, k); ++blocksOut; for (size_t i = 0; i < 4; ++i) dst.push_back(out[i]); } if (lineSize > 0 && (blocksOut >= lineSize/4 || j >= len)) { if (blocksOut) { dst.push_back('\r'); dst.push_back('\n'); } blocksOut = 0; } } // Percent-encode any trailing equals signs size_t neq = 0; for (size_t i = 0; i < 4; ++i) if (dst[dst.size() - 1 - i] == '=') neq++; if (neq) { dst.resize(dst.size() - neq); for (size_t i = 0; i < neq; ++i) { dst.push_back('%'); dst.push_back('3'); dst.push_back('D'); } } }
/// ACRefinementScan::WriteMCU // Write a single MCU in this scan. Return true if there are more blocks in this row. bool ACRefinementScan::WriteMCU(void) { #if ACCUSOFT_CODE bool more = true; int c; assert(m_pBlockCtrl); BeginWriteMCU(m_Coder.ByteStreamOf()); for(c = 0;c < m_ucCount;c++) { class Component *comp = m_pComponent[c]; class QuantizedRow *q = m_pBlockCtrl->CurrentQuantizedRow(comp->IndexOf()); UBYTE mcux = (m_ucCount > 1)?(comp->MCUWidthOf() ):(1); UBYTE mcuy = (m_ucCount > 1)?(comp->MCUHeightOf()):(1); ULONG xmin = m_ulX[c]; ULONG xmax = xmin + mcux; ULONG x,y; if (xmax >= q->WidthOf()) { more = false; } for(y = 0;y < mcuy;y++) { for(x = xmin;x < xmax;x++) { LONG *block,dummy[64]; if (q && x < q->WidthOf()) { block = q->BlockAt(x)->m_Data; } else { block = dummy; memset(dummy ,0,sizeof(dummy) ); } EncodeBlock(block); } if (q) q = q->NextOf(); } // Done with this component, advance the block. m_ulX[c] = xmax; } return more; #else return false; #endif }
// blockSize > 0 UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize) { WriteByte2(kBlockSig0); WriteByte2(kBlockSig1); WriteByte2(kBlockSig2); WriteByte2(kBlockSig3); WriteByte2(kBlockSig4); WriteByte2(kBlockSig5); CBZip2CRC crc; int numReps = 0; Byte prevByte = block[0]; UInt32 i = 0; do { Byte b = block[i]; if (numReps == kRleModeRepSize) { for (; b > 0; b--) crc.UpdateByte(prevByte); numReps = 0; continue; } if (prevByte == b) numReps++; else { numReps = 1; prevByte = b; } crc.UpdateByte(b); } while (++i < blockSize); UInt32 crcRes = crc.GetDigest(); WriteCRC2(crcRes); EncodeBlock(block, blockSize); return crcRes; }
void FIndirectLightingCache::UpdateBlock(FScene* Scene, FViewInfo* DebugDrawingView, FBlockUpdateInfo& BlockInfo) { const int32 NumSamplesPerBlock = BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize; FSHVectorRGB3 SingleSample; float DirectionalShadowing = 1; FVector SkyBentNormal(0, 0, 1); //always do point interpolation to get valid 3band single sample and directional data. InterpolatePoint(Scene, BlockInfo.Block, DirectionalShadowing, SingleSample, SkyBentNormal); if (CanIndirectLightingCacheUseVolumeTexture(GetFeatureLevel()) && !BlockInfo.Allocation->bPointSample) { static TArray<float> AccumulatedWeight; AccumulatedWeight.Reset(NumSamplesPerBlock); AccumulatedWeight.AddZeroed(NumSamplesPerBlock); //volume textures are encoded as two band, so no reason to waste perf interpolating 3 bands. static TArray<FSHVectorRGB2> AccumulatedIncidentRadiance; AccumulatedIncidentRadiance.Reset(NumSamplesPerBlock); AccumulatedIncidentRadiance.AddZeroed(NumSamplesPerBlock); // Interpolate SH samples from precomputed lighting samples and accumulate lighting data for an entire block InterpolateBlock(Scene, BlockInfo.Block, AccumulatedWeight, AccumulatedIncidentRadiance); static TArray<FFloat16Color> Texture0Data; static TArray<FFloat16Color> Texture1Data; static TArray<FFloat16Color> Texture2Data; Texture0Data.Reset(NumSamplesPerBlock); Texture1Data.Reset(NumSamplesPerBlock); Texture2Data.Reset(NumSamplesPerBlock); Texture0Data.AddUninitialized(NumSamplesPerBlock); Texture1Data.AddUninitialized(NumSamplesPerBlock); Texture2Data.AddUninitialized(NumSamplesPerBlock); const int32 FormatSize = GPixelFormats[PF_FloatRGBA].BlockBytes; check(FormatSize == sizeof(FFloat16Color)); // Encode the SH samples into a texture format // Note the single sample is updated even if this is a volume allocation, because translucent materials only use the single sample EncodeBlock(DebugDrawingView, BlockInfo.Block, AccumulatedWeight, AccumulatedIncidentRadiance, Texture0Data, Texture1Data, Texture2Data); // Setup an update region const FUpdateTextureRegion3D UpdateRegion( BlockInfo.Block.MinTexel.X, BlockInfo.Block.MinTexel.Y, BlockInfo.Block.MinTexel.Z, 0, 0, 0, BlockInfo.Block.TexelSize, BlockInfo.Block.TexelSize, BlockInfo.Block.TexelSize); // Update the volume texture atlas RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture0().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture0Data.GetData()); RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture1().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture1Data.GetData()); RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture2().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture2Data.GetData()); } else { if (GCacheDrawInterpolationPoints != 0 && DebugDrawingView) { FViewElementPDI DebugPDI(DebugDrawingView, NULL); const FVector WorldPosition = BlockInfo.Block.Min; DebugPDI.DrawPoint(WorldPosition, FLinearColor(0, 0, 1), 10, SDPG_World); } } // Record the position that the sample was taken at BlockInfo.Allocation->TargetPosition = BlockInfo.Block.Min + BlockInfo.Block.Size / 2; BlockInfo.Allocation->TargetSamplePacked0[0] = FVector4(SingleSample.R.V[0], SingleSample.R.V[1], SingleSample.R.V[2], SingleSample.R.V[3]) / PI; BlockInfo.Allocation->TargetSamplePacked0[1] = FVector4(SingleSample.G.V[0], SingleSample.G.V[1], SingleSample.G.V[2], SingleSample.G.V[3]) / PI; BlockInfo.Allocation->TargetSamplePacked0[2] = FVector4(SingleSample.B.V[0], SingleSample.B.V[1], SingleSample.B.V[2], SingleSample.B.V[3]) / PI; BlockInfo.Allocation->TargetSamplePacked1[0] = FVector4(SingleSample.R.V[4], SingleSample.R.V[5], SingleSample.R.V[6], SingleSample.R.V[7]) / PI; BlockInfo.Allocation->TargetSamplePacked1[1] = FVector4(SingleSample.G.V[4], SingleSample.G.V[5], SingleSample.G.V[6], SingleSample.G.V[7]) / PI; BlockInfo.Allocation->TargetSamplePacked1[2] = FVector4(SingleSample.B.V[4], SingleSample.B.V[5], SingleSample.B.V[6], SingleSample.B.V[7]) / PI; BlockInfo.Allocation->TargetSamplePacked2 = FVector4(SingleSample.R.V[8], SingleSample.G.V[8], SingleSample.B.V[8], 0) / PI; BlockInfo.Allocation->TargetDirectionalShadowing = DirectionalShadowing; const float BentNormalLength = SkyBentNormal.Size(); BlockInfo.Allocation->TargetSkyBentNormal = FVector4(SkyBentNormal / FMath::Max(BentNormalLength, .0001f), BentNormalLength); if (!BlockInfo.Allocation->bHasEverUpdatedSingleSample) { // If this is the first update, also set the interpolated state to match the new target //@todo - detect and handle teleports in the same way BlockInfo.Allocation->SingleSamplePosition = BlockInfo.Allocation->TargetPosition; for (int32 VectorIndex = 0; VectorIndex < 3; VectorIndex++) // RGB { BlockInfo.Allocation->SingleSamplePacked0[VectorIndex] = BlockInfo.Allocation->TargetSamplePacked0[VectorIndex]; BlockInfo.Allocation->SingleSamplePacked1[VectorIndex] = BlockInfo.Allocation->TargetSamplePacked1[VectorIndex]; } BlockInfo.Allocation->SingleSamplePacked2 = BlockInfo.Allocation->TargetSamplePacked2; BlockInfo.Allocation->CurrentDirectionalShadowing = BlockInfo.Allocation->TargetDirectionalShadowing; BlockInfo.Allocation->CurrentSkyBentNormal = BlockInfo.Allocation->TargetSkyBentNormal; BlockInfo.Allocation->bHasEverUpdatedSingleSample = true; } BlockInfo.Block.bHasEverBeenUpdated = true; }
bool CDynamicHuffman<T>::EncodeBlock(T * ptr,uint32_t size,CBitstream * bstr) { return EncodeBlock(ptr, size, bstr, true); }
void FIndirectLightingCache::UpdateBlock(FScene* Scene, FViewInfo* DebugDrawingView, FBlockUpdateInfo& BlockInfo) { const int32 NumSamplesPerBlock = BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize; FSHVectorRGB2 SingleSample; float DirectionalShadowing = 1; if (CanIndirectLightingCacheUseVolumeTexture() && BlockInfo.Allocation->bOpaqueRelevance) { static TArray<float> AccumulatedWeight; AccumulatedWeight.Reset(NumSamplesPerBlock); AccumulatedWeight.AddZeroed(NumSamplesPerBlock); static TArray<FSHVectorRGB2> AccumulatedIncidentRadiance; AccumulatedIncidentRadiance.Reset(NumSamplesPerBlock); AccumulatedIncidentRadiance.AddZeroed(NumSamplesPerBlock); // Interpolate SH samples from precomputed lighting samples and accumulate lighting data for an entire block InterpolateBlock(Scene, BlockInfo.Block, AccumulatedWeight, AccumulatedIncidentRadiance); static TArray<FFloat16Color> Texture0Data; static TArray<FFloat16Color> Texture1Data; static TArray<FFloat16Color> Texture2Data; Texture0Data.Reset(NumSamplesPerBlock); Texture1Data.Reset(NumSamplesPerBlock); Texture2Data.Reset(NumSamplesPerBlock); Texture0Data.AddUninitialized(NumSamplesPerBlock); Texture1Data.AddUninitialized(NumSamplesPerBlock); Texture2Data.AddUninitialized(NumSamplesPerBlock); const int32 FormatSize = GPixelFormats[PF_FloatRGBA].BlockBytes; check(FormatSize == sizeof(FFloat16Color)); // Encode the SH samples into a texture format EncodeBlock(DebugDrawingView, BlockInfo.Block, AccumulatedWeight, AccumulatedIncidentRadiance, Texture0Data, Texture1Data, Texture2Data, SingleSample); // Setup an update region const FUpdateTextureRegion3D UpdateRegion( BlockInfo.Block.MinTexel.X, BlockInfo.Block.MinTexel.Y, BlockInfo.Block.MinTexel.Z, 0, 0, 0, BlockInfo.Block.TexelSize, BlockInfo.Block.TexelSize, BlockInfo.Block.TexelSize); // Update the volume texture atlas RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture0().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture0Data.GetData()); RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture1().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture1Data.GetData()); RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture2().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture2Data.GetData()); } else { InterpolatePoint(Scene, BlockInfo.Block, DirectionalShadowing, SingleSample); } // Record the position that the sample was taken at BlockInfo.Allocation->TargetPosition = BlockInfo.Block.Min + BlockInfo.Block.Size / 2; BlockInfo.Allocation->TargetSamplePacked[0] = FVector4(SingleSample.R.V[0], SingleSample.R.V[1], SingleSample.R.V[2], SingleSample.R.V[3]) / PI; BlockInfo.Allocation->TargetSamplePacked[1] = FVector4(SingleSample.G.V[0], SingleSample.G.V[1], SingleSample.G.V[2], SingleSample.G.V[3]) / PI; BlockInfo.Allocation->TargetSamplePacked[2] = FVector4(SingleSample.B.V[0], SingleSample.B.V[1], SingleSample.B.V[2], SingleSample.B.V[3]) / PI; BlockInfo.Allocation->TargetDirectionalShadowing = DirectionalShadowing; if (!BlockInfo.Allocation->bHasEverUpdatedSingleSample) { // If this is the first update, also set the interpolated state to match the new target //@todo - detect and handle teleports in the same way BlockInfo.Allocation->SingleSamplePosition = BlockInfo.Allocation->TargetPosition; for (int32 VectorIndex = 0; VectorIndex < ARRAY_COUNT(BlockInfo.Allocation->SingleSamplePacked); VectorIndex++) { BlockInfo.Allocation->SingleSamplePacked[VectorIndex] = BlockInfo.Allocation->TargetSamplePacked[VectorIndex]; } BlockInfo.Allocation->CurrentDirectionalShadowing = BlockInfo.Allocation->TargetDirectionalShadowing; BlockInfo.Allocation->bHasEverUpdatedSingleSample = true; } BlockInfo.Block.bHasEverBeenUpdated = true; }
/// SequentialScan::WriteMCU // Write a single MCU in this scan. Return true if there are more blocks in this row. bool SequentialScan::WriteMCU(void) { bool more = true; int c; assert(m_pBlockCtrl); BeginWriteMCU(m_Stream.ByteStreamOf()); for(c = 0;c < m_ucCount;c++) { class Component *comp = m_pComponent[c]; class QuantizedRow *q = m_pBlockCtrl->CurrentQuantizedRow(comp->IndexOf()); class HuffmanCoder *dc = m_pDCCoder[c]; class HuffmanCoder *ac = m_pACCoder[c]; class HuffmanStatistics *dcstat = m_pDCStatistics[c]; class HuffmanStatistics *acstat = m_pACStatistics[c]; LONG &prevdc = m_lDC[c]; UWORD &skip = m_usSkip[c]; UBYTE mcux = (m_ucCount > 1)?(comp->MCUWidthOf() ):(1); UBYTE mcuy = (m_ucCount > 1)?(comp->MCUHeightOf()):(1); ULONG xmin = m_ulX[c]; ULONG xmax = xmin + mcux; ULONG x,y; if (xmax >= q->WidthOf()) { more = false; } for(y = 0;y < mcuy;y++) { for(x = xmin;x < xmax;x++) { LONG *block,dummy[64]; if (q && x < q->WidthOf()) { block = q->BlockAt(x)->m_Data; } else { block = dummy; memset(dummy ,0,sizeof(dummy) ); block[0] = prevdc; } #if HIERARCHICAL_HACK // A nice hack for the hierarchical scan: If this is not the last frame // in the hierarchy, remove all coefficients below the diagonal to allow a // fast "EOB", they can be encoded by the level above. if (m_pFrame->NextOf()) { LONG i,j; for(j = 0;j < 8;j++) { for(i = 0;i < 8;i++) { if (i+j > 4) { block[i + (j << 3)] = 0; } } } } #endif if (m_bMeasure) { MeasureBlock(block,dcstat,acstat,prevdc,skip); } else { EncodeBlock(block,dc,ac,prevdc,skip); } } if (q) q = q->NextOf(); } // Done with this component, advance the block. m_ulX[c] = xmax; } return more; }