private PatchHeader DecodePatchHeader(BitPack bitpack) { PatchHeader header = new PatchHeader(); // Quantized word bits header.QuantWBits = bitpack.UnpackBits(8); if (header.QuantWBits == END_OF_PATCHES) { return(header); } // DC offset header.DCOffset = bitpack.UnpackFloat(); // Range header.Range = bitpack.UnpackBits(16); // Patch IDs (10 bits) header.PatchIDs = bitpack.UnpackBits(10); // Word bits header.WordBits = (uint)((header.QuantWBits & 0x0f) + 2); return(header); }
/// <summary> /// Add a patch of terrain to a BitPacker /// </summary> /// <param name="output">BitPacker to write the patch to</param> /// <param name="heightmap">Heightmap of the simulator, must be a 256 * /// 256 float array</param> /// <param name="x">X offset of the patch to create, valid values are /// from 0 to 15</param> /// <param name="y">Y offset of the patch to create, valid values are /// from 0 to 15</param> public void CreatePatch(BitPack output, float[] heightmap, int x, int y) { if (heightmap.Length != 256 * 256) { Logger.Log("Invalid heightmap value of " + heightmap.Length + " passed to CreatePatch()", Helpers.LogLevel.Error, Client); return; } if (x < 0 || x > 15 || y < 0 || y > 15) { Logger.Log("Invalid x or y patch offset passed to CreatePatch(), x=" + x + ", y=" + y, Helpers.LogLevel.Error, Client); return; } PatchHeader header = PrescanPatch(heightmap, x, y); header.QuantWBits = 136; header.PatchIDs = (y & 0x1F); header.PatchIDs += (x << 5); // TODO: What is prequant? int[] patch = CompressPatch(heightmap, x, y, header, 10); int wbits = EncodePatchHeader(output, header, patch); // TODO: What is postquant? EncodePatch(output, patch, 0, wbits); }
private PatchHeader PrescanPatch(float[] heightmap, int patchX, int patchY) { PatchHeader header = new PatchHeader(); float zmax = -99999999.0f; float zmin = 99999999.0f; for (int j = patchY * 16; j < (patchY + 1) * 16; j++) { for (int i = patchX * 16; i < (patchX + 1) * 16; i++) { if (heightmap[j * 256 + i] > zmax) { zmax = heightmap[j * 256 + i]; } if (heightmap[j * 256 + i] < zmin) { zmin = heightmap[j * 256 + i]; } } } header.DCOffset = zmin; header.Range = (int)((zmax - zmin) + 1.0f); return(header); }
private static PatchHeader PrescanPatch(LayerPatch patch) { var header = new PatchHeader(); float zmax = -99999999.0f; float zmin = 99999999.0f; for (int y = 0; y < LAYER_PATCH_NUM_XY_ENTRIES; y++) { for (int x = 0; x < LAYER_PATCH_NUM_XY_ENTRIES; x++) { float val = patch[x, y]; if (val > zmax) { zmax = val; } if (val < zmin) { zmin = val; } } } header.DCOffset = zmin; header.Range = (int)((zmax - zmin) + 1.0f); return(header); }
/// <summary> /// Decompresses all the patches in the given BitPack and assigns heights and normals to the surface. /// </summary> /// <param name="bitPack"></param> /// <param name="groupHeader"></param> /// <param name="isLargePatch"></param> public void DecompressPatches(BitPack bitPack, GroupHeader groupHeader, bool isLargePatch) { int j; int i; int[] patchData = new int[Patch.LARGE_PATCH_SIZE * Patch.LARGE_PATCH_SIZE]; // Large enough for a maximum sized patch Patch.InitPatchDecompressor(groupHeader.PatchSize); groupHeader.Stride = (UInt16)GridsPerEdge; Patch.SetGroupHeader(groupHeader); while (true) { PatchHeader patchHeader = new PatchHeader(bitPack); //Logger.LogDebug("Surface.DecompressPatches", $"{patchHeader} w={patchHeader.PatchIds >> 5} h={patchHeader.PatchIds & 0x1f} (PatchesPerEdge={PatchesPerEdge})"); if (patchHeader.IsEnd) { break; } i = patchHeader.PatchIds >> 5; j = patchHeader.PatchIds & 0x1f; if ((i >= PatchesPerEdge) || (j >= PatchesPerEdge)) { //Logger.LogWarning("Surface.DecompressPatches", $"Received invalid terrain packet - patch header patch ID incorrect! {i}x{j} DcOffset={patchHeader.DcOffset} Range={patchHeader.Range} QuantWBits={patchHeader.QuantWBits} PatchIds={patchHeader.PatchIds}"); return; } SurfacePatch surfacePatch = PatchList[j * PatchesPerEdge + i]; Patch.Decode(bitPack, groupHeader.PatchSize, (patchHeader.QuantWBits & 0xf) + 2, patchData); Patch.DeCompress(SurfaceZ, surfacePatch.DataZStart, patchData, patchHeader); // Update edges for neighbours. Need to guarantee that this gets done before we generate vertical stats. surfacePatch.UpdateNorthEdge(); surfacePatch.UpdateEastEdge(); if (surfacePatch.GetNeighbourPatch(DirectionIndex.West) != null) { surfacePatch.GetNeighbourPatch(DirectionIndex.West).UpdateEastEdge(); } if (surfacePatch.GetNeighbourPatch(DirectionIndex.SouthWest) != null) { surfacePatch.GetNeighbourPatch(DirectionIndex.SouthWest).UpdateEastEdge(); surfacePatch.GetNeighbourPatch(DirectionIndex.SouthWest).UpdateNorthEdge(); } if (surfacePatch.GetNeighbourPatch(DirectionIndex.South) != null) { surfacePatch.GetNeighbourPatch(DirectionIndex.South).UpdateNorthEdge(); } //// Dirty patch statistics, and flag that the patch has data. surfacePatch.DirtyZ(); surfacePatch.HasReceivedData = true; //break; //TODO: Only do the first patch for testing } }
private void DecompressLand(Simulator simulator, BitPack bitpack, GroupHeader group) { int x; int y; int[] patches = new int[32 * 32]; int count = 0; while (true) { PatchHeader header = DecodePatchHeader(bitpack); if (header.QuantWBits == END_OF_PATCHES) { break; } x = header.PatchIDs >> 5; y = header.PatchIDs & 0x1F; if (x >= PATCHES_PER_EDGE || y >= PATCHES_PER_EDGE) { Logger.Log("Invalid LayerData land packet, x = " + x + ", y = " + y + ", dc_offset = " + header.DCOffset + ", range = " + header.Range + ", quant_wbits = " + header.QuantWBits + ", patchids = " + header.PatchIDs + ", count = " + count, Helpers.LogLevel.Warning, Client); return; } // Decode this patch DecodePatch(patches, bitpack, header, group.PatchSize); // Decompress this patch float[] heightmap = DecompressPatch(patches, header, group); count++; if (OnLandPatch != null) { try { OnLandPatch(simulator, x, y, group.PatchSize, heightmap); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } if (Client.Settings.STORE_LAND_PATCHES) { lock (SimPatches) { if (!SimPatches.ContainsKey(simulator.Handle)) { SimPatches.Add(simulator.Handle, new Patch[16 * 16]); } SimPatches[simulator.Handle][y * 16 + x] = new Patch(); SimPatches[simulator.Handle][y * 16 + x].Heightmap = heightmap; } } } }
/// <summary> /// /// </summary> /// <param name="output"></param> /// <param name="header"></param> /// <param name="patch"></param> /// <returns>wbits</returns> private int EncodePatchHeader(BitPack output, PatchHeader header, int[] patch) { int temp; int wbits = (header.QuantWBits & 0x0f) + 2; uint maxWbits = (uint)wbits + 5; uint minWbits = ((uint)wbits >> 1); wbits = (int)minWbits; for (int i = 0; i < patch.Length; i++) { temp = patch[i]; if (temp != 0) { // Get the absolute value if (temp < 0) { temp *= -1; } for (int j = (int)maxWbits; j > (int)minWbits; j--) { if ((temp & (1 << j)) != 0) { if (j > wbits) { wbits = j; } break; } } } } wbits += 1; header.QuantWBits &= 0xf0; if (wbits > 17 || wbits < 2) { Logger.Log("Bits needed per word in EncodePatchHeader() are outside the allowed range", Helpers.LogLevel.Error, Client); } header.QuantWBits |= (wbits - 2); output.PackBits(header.QuantWBits, 8); output.PackFloat(header.DCOffset); output.PackBits(header.Range, 16); output.PackBits(header.PatchIDs, 10); return(wbits); }
public static void DeCompress(float[] dest, uint destOffset, int[] src, PatchHeader patchHeader) { { int i; int j; float[] block = new float[LARGE_PATCH_SIZE * LARGE_PATCH_SIZE]; int tblockIndex = 0; int tpatchIndex; GroupHeader groupHeader = GroupHeader; int size = groupHeader.PatchSize; float range = patchHeader.Range; int prequant = (patchHeader.QuantWBits >> 4) + 2; int quantize = 1 << prequant; float hmin = patchHeader.DcOffset; int stride = groupHeader.Stride; float ooq = 1f / (float)quantize; int dqIndex = 0; int decopyMatrixIndex = 0; float mult = ooq * range; float addval = mult * (float)(1 << (prequant - 1)) + hmin; for (i = 0; i < size * size; i++) { block[tblockIndex++] = src[DeCopyMatrix[decopyMatrixIndex++]] * PatchDequantizeTable[dqIndex++]; } if (size == 16) { idct_patch(block); } else { idct_patch_large(block); } for (j = 0; j < size; j++) { tpatchIndex = j * stride; tblockIndex = j * size; for (i = 0; i < size; i++) { dest[destOffset + tpatchIndex++] = block[tblockIndex++] * mult + addval; } } } }
private byte[] ApplyCopyPatch(ref PatchInfoHeader patchInfoHeader, ref PatchHeader patchHeader, uint patchLength, byte[] originalData) { if (patchLength != patchHeader.PatchedFileSize) { throw new InvalidDataException("CopyPatchInvalidSize"); } var patchedData = patchLength == originalData.Length ? originalData : new byte[patchLength]; if (Read(patchedData, 0, patchedData.Length) != patchedData.Length) { throw new EndOfStreamException(); } return(patchedData); }
private void DecodePatch(int[] patches, BitPack bitpack, PatchHeader header, int size) { int temp; for (int n = 0; n < size * size; n++) { // ? temp = bitpack.UnpackBits(1); if (temp != 0) { // Value or EOB temp = bitpack.UnpackBits(1); if (temp != 0) { // Value temp = bitpack.UnpackBits(1); if (temp != 0) { // Negative temp = bitpack.UnpackBits((int)header.WordBits); patches[n] = temp * -1; } else { // Positive temp = bitpack.UnpackBits((int)header.WordBits); patches[n] = temp; } } else { // Set the rest to zero // TODO: This might not be necessary for (int o = n; o < size * size; o++) { patches[o] = 0; } break; } } else { patches[n] = 0; } } }
private float[] DecompressPatch(int[] patches, PatchHeader header, GroupHeader group) { float[] block = new float[group.PatchSize * group.PatchSize]; float[] output = new float[group.PatchSize * group.PatchSize]; int prequant = (header.QuantWBits >> 4) + 2; int quantize = 1 << prequant; float ooq = 1.0f / (float)quantize; float mult = ooq * (float)header.Range; float addval = mult * (float)(1 << (prequant - 1)) + header.DCOffset; if (group.PatchSize == 16) { for (int n = 0; n < 16 * 16; n++) { block[n] = patches[CopyMatrix16[n]] * DequantizeTable16[n]; } float[] ftemp = new float[16 * 16]; for (int o = 0; o < 16; o++) { IDCTColumn16(block, ftemp, o); } for (int o = 0; o < 16; o++) { IDCTLine16(ftemp, block, o); } } else { for (int n = 0; n < 32 * 32; n++) { block[n] = patches[CopyMatrix32[n]] * DequantizeTable32[n]; } Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error, Client); } for (int j = 0; j < block.Length; j++) { output[j] = block[j] * mult + addval; } return(output); }
private int[] CompressPatch(float[] heightmap, int patchX, int patchY, PatchHeader header, int prequant) { float[] block = new float[16 * 16]; int wordsize = prequant; float oozrange = 1.0f / (float)header.Range; float range = (float)(1 << prequant); float premult = oozrange * range; float sub = (float)(1 << (prequant - 1)) + header.DCOffset * premult; header.QuantWBits = wordsize - 2; header.QuantWBits |= (prequant - 2) << 4; int k = 0; for (int j = patchY * 16; j < (patchY + 1) * 16; j++) { for (int i = patchX * 16; i < (patchX + 1) * 16; i++) { block[k++] = heightmap[j * 256 + i] * premult - sub; } } float[] ftemp = new float[16 * 16]; int[] itemp = new int[16 * 16]; for (int o = 0; o < 16; o++) { DCTLine16(block, ftemp, o); } for (int o = 0; o < 16; o++) { DCTColumn16(ftemp, itemp, o); } return(itemp); }
private static int[] CompressPatch(LayerPatch patchData, PatchHeader header, int prequant) { var block = new float[LAYER_PATCH_NUM_XY_ENTRIES * LAYER_PATCH_NUM_XY_ENTRIES]; int wordsize = prequant; float oozrange = 1.0f / (float)header.Range; var range = (float)(1 << prequant); float premult = oozrange * range; float sub = (1 << (prequant - 1)) + header.DCOffset * premult; header.QuantWBits = wordsize - 2; header.QuantWBits |= (prequant - 2) << 4; int k = 0; for (int y = 0; y < LAYER_PATCH_NUM_XY_ENTRIES; y++) { for (int x = 0; x < LAYER_PATCH_NUM_XY_ENTRIES; x++) { block[k++] = patchData[x, y] * premult - sub; } } var ftemp = new float[LAYER_PATCH_NUM_XY_ENTRIES * LAYER_PATCH_NUM_XY_ENTRIES]; var itemp = new int[LAYER_PATCH_NUM_XY_ENTRIES * LAYER_PATCH_NUM_XY_ENTRIES]; for (int o = 0; o < LAYER_PATCH_NUM_XY_ENTRIES; o++) { DCTLine16(block, ftemp, o); } for (int o = 0; o < LAYER_PATCH_NUM_XY_ENTRIES; o++) { DCTColumn16(ftemp, itemp, o); } return(itemp); }
/// <summary> /// /// </summary> /// <param name="output"></param> /// <param name="header"></param> /// <param name="patch"></param> /// <returns>wbits</returns> private int EncodePatchHeader(BitPack output, PatchHeader header, int[] patch) { int temp; int wbits = (header.QuantWBits & 0x0f) + 2; uint maxWbits = (uint)wbits + 5; uint minWbits = ((uint)wbits >> 1); wbits = (int)minWbits; for (int i = 0; i < patch.Length; i++) { temp = patch[i]; if (temp != 0) { // Get the absolute value if (temp < 0) temp *= -1; for (int j = (int)maxWbits; j > (int)minWbits; j--) { if ((temp & (1 << j)) != 0) { if (j > wbits) wbits = j; break; } } } } wbits += 1; header.QuantWBits &= 0xf0; if (wbits > 17 || wbits < 2) { Logger.Log("Bits needed per word in EncodePatchHeader() are outside the allowed range", Helpers.LogLevel.Error, Client); } header.QuantWBits |= (wbits - 2); output.PackBits(header.QuantWBits, 8); output.PackFloat(header.DCOffset); output.PackBits(header.Range, 16); output.PackBits(header.PatchIDs, 10); return wbits; }
private PatchHeader DecodePatchHeader(BitPack bitpack) { PatchHeader header = new PatchHeader(); // Quantized word bits header.QuantWBits = bitpack.UnpackBits(8); if (header.QuantWBits == END_OF_PATCHES) return header; // DC offset header.DCOffset = bitpack.UnpackFloat(); // Range header.Range = bitpack.UnpackBits(16); // Patch IDs (10 bits) header.PatchIDs = bitpack.UnpackBits(10); // Word bits header.WordBits = (uint)((header.QuantWBits & 0x0f) + 2); return header; }
private PatchHeader PrescanPatch(float[] heightmap, int patchX, int patchY) { PatchHeader header = new PatchHeader(); float zmax = -99999999.0f; float zmin = 99999999.0f; for (int j = patchY * 16; j < (patchY + 1) * 16; j++) { for (int i = patchX * 16; i < (patchX + 1) * 16; i++) { if (heightmap[j * 256 + i] > zmax) zmax = heightmap[j * 256 + i]; if (heightmap[j * 256 + i] < zmin) zmin = heightmap[j * 256 + i]; } } header.DCOffset = zmin; header.Range = (int)((zmax - zmin) + 1.0f); return header; }
private unsafe byte[] ApplyBsd0Patch(ref PatchInfoHeader patchInfoHeader, ref PatchHeader patchHeader, uint patchLength, byte[] originalData) { byte[] patchData; if (patchLength < patchHeader.PatchLength) { patchData = UnpackRle(); } else { patchData = new byte[patchLength]; if (Read(patchData, 0, checked ((int)patchLength)) != patchLength) { throw new EndOfStreamException(); } } fixed(byte *patchDataPointer = patchData) { var bsdiffHeader = (PatchBsdiff40Header *)patchDataPointer; if (!BitConverter.IsLittleEndian) { CommonMethods.SwapBytes((ulong *)patchDataPointer, sizeof(PatchBsdiff40Header) >> 3); } if (bsdiffHeader->Signature != 0x3034464649445342 /* 'BSDIFF40' */) { throw new InvalidDataException(ErrorMessages.GetString("Bsd0PatchHeaderInvalidSignature")); } var controlBlock = (uint *)(patchDataPointer + sizeof(PatchBsdiff40Header)); var differenceBlock = (byte *)controlBlock + bsdiffHeader->ControlBlockLength; var extraBlock = differenceBlock + bsdiffHeader->DifferenceBlockLength; if (!BitConverter.IsLittleEndian) { CommonMethods.SwapBytes(controlBlock, bsdiffHeader->ControlBlockLength >> 2); } var patchBuffer = new byte[bsdiffHeader->PatchedFileSize]; fixed(byte *originalDataPointer = originalData) fixed(byte *patchBufferPointer = patchBuffer) { var sourcePointer = originalDataPointer; var destinationPointer = patchBufferPointer; int sourceCount = originalData.Length; int destinationCount = patchBuffer.Length; while (destinationCount != 0) { uint differenceLength = *controlBlock++; uint extraLength = *controlBlock++; uint sourceOffset = *controlBlock++; if (differenceLength > destinationCount) { throw new InvalidDataException(ErrorMessages.GetString("Bsd0PatchInvalidData")); } destinationCount = (int)(destinationCount - differenceLength); // Apply the difference patch (Patched Data = Original data + Difference data) for (; differenceLength-- != 0; destinationPointer++, sourcePointer++) { *destinationPointer = *differenceBlock++; if (sourceCount > 0) { *destinationPointer += *sourcePointer; } } if (extraLength > destinationCount) { throw new InvalidDataException(ErrorMessages.GetString("Bsd0PatchInvalidData")); } destinationCount = (int)(destinationCount - extraLength); // Apply the extra data patch (New data) for (; extraLength-- != 0;) { *destinationPointer++ = *extraBlock++; } sourcePointer += (sourceOffset & 0x80000000) != 0 ? unchecked ((int)(0x80000000 - sourceOffset)) : (int)sourceOffset; } } return(patchBuffer); } }
private unsafe byte[] ApplyBsd0Patch(ref PatchInfoHeader patchInfoHeader, ref PatchHeader patchHeader, uint patchLength, byte[] originalData) { byte[] patchData; if (patchLength < patchHeader.PatchLength) { patchData = UnpackRle(patchLength); } else { patchData = new byte[patchLength]; if (Read(patchData, 0, checked ((int)patchLength)) != patchLength) { throw new EndOfStreamException(); } } fixed(byte *patchDataPointer = patchData) { var bsdiffHeader = (PatchBsdiff40Header *)patchDataPointer; if (!BitConverter.IsLittleEndian) { CommonMethods.SwapBytes((ulong *)patchDataPointer, sizeof(PatchBsdiff40Header) / sizeof(ulong)); } if (bsdiffHeader->Signature != 0x3034464649445342 /* 'BSDIFF40' */) { throw new InvalidDataException(ErrorMessages.GetString("Bsd0PatchHeaderInvalidSignature")); } var controlBlock = (uint *)(patchDataPointer + sizeof(PatchBsdiff40Header)); var differenceBlock = (byte *)controlBlock + bsdiffHeader->ControlBlockLength; var extraBlock = differenceBlock + bsdiffHeader->DifferenceBlockLength; if (!BitConverter.IsLittleEndian) { CommonMethods.SwapBytes(controlBlock, bsdiffHeader->ControlBlockLength / sizeof(uint)); } var patchedBuffer = new byte[bsdiffHeader->PatchedFileSize]; uint o = 0; uint n = 0; try { while (n < patchedBuffer.Length) { uint differenceLength = *controlBlock++; uint extraLength = *controlBlock++; uint sourceOffset = *controlBlock++; // Apply the difference patch (Patched Data = Original data + Difference data) for (uint i = 0; i < differenceLength; i++, n++, o++) { patchedBuffer[n] = differenceBlock[i]; if (o < originalData.Length) { patchedBuffer[n] += originalData[o]; } } differenceBlock += differenceLength; // Apply the extra data patch (New data) for (int e = 0; e < extraLength; e++) { patchedBuffer[n++] = extraBlock[e]; } extraBlock += extraLength; unchecked { o += (sourceOffset & 0x80000000) != 0 ? (0x80000000 - sourceOffset) : sourceOffset; } } } catch (IndexOutOfRangeException ex) { throw new InvalidDataException(ErrorMessages.GetString("Bsd0PatchInvalidData"), ex); } return(patchedBuffer); } }
private static int EncodePatchHeader(BitPacker output, PatchHeader header, int[] patch, bool extended) { int temp; int wbits = (header.QuantWBits & 0x0f) + 2; uint maxWbits = (uint)wbits + 5; uint minWbits = (uint)wbits >> 1; wbits = (int)minWbits; for (int i = 0; i < patch.Length; i++) { temp = patch[i]; if (temp != 0) { // Get the absolute value if (temp < 0) { temp *= -1; } for (int j = (int)maxWbits; j > (int)minWbits; j--) { if ((temp & (1 << j)) != 0) { if (j > wbits) { wbits = j; } break; } } } } wbits++; if (wbits > 17) { wbits = 17; } else if (wbits < 2) { wbits = 2; } header.QuantWBits &= 0xf0; header.QuantWBits |= wbits - 2; output.PackBits(header.QuantWBits, 8); output.FloatValue = header.DCOffset; output.PackBits(header.Range, 16); if (extended) { output.PackBits(header.PatchIDs, 32); } else { output.PackBits(header.PatchIDs, 10); } /* Bit Length of Header in VarRegion format: 56 bits => 7 Bytes */ return(wbits); }
private float[] DecompressPatch(int[] patches, PatchHeader header, GroupHeader group) { float[] block = new float[group.PatchSize * group.PatchSize]; float[] output = new float[group.PatchSize * group.PatchSize]; int prequant = (header.QuantWBits >> 4) + 2; int quantize = 1 << prequant; float ooq = 1.0f / (float)quantize; float mult = ooq * (float)header.Range; float addval = mult * (float)(1 << (prequant - 1)) + header.DCOffset; if (group.PatchSize == 16) { for (int n = 0; n < 16 * 16; n++) { block[n] = patches[CopyMatrix16[n]] * DequantizeTable16[n]; } float[] ftemp = new float[16 * 16]; for (int o = 0; o < 16; o++) IDCTColumn16(block, ftemp, o); for (int o = 0; o < 16; o++) IDCTLine16(ftemp, block, o); } else { for (int n = 0; n < 32 * 32; n++) { block[n] = patches[CopyMatrix32[n]] * DequantizeTable32[n]; } Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error, Client); } for (int j = 0; j < block.Length; j++) { output[j] = block[j] * mult + addval; } return output; }
private byte[] ApplyCopyPatch(ref PatchInfoHeader patchInfoHeader, ref PatchHeader patchHeader, uint patchLength, byte[] originalData) { if (patchLength != patchHeader.PatchedFileSize) throw new InvalidDataException("CopyPatchInvalidSize"); var patchedData = patchLength == originalData.Length ? originalData : new byte[patchLength]; if (Read(patchedData, 0, patchedData.Length) != patchedData.Length) throw new EndOfStreamException(); return patchedData; }
private int[] CompressPatch(float[] heightmap, int patchX, int patchY, PatchHeader header, int prequant) { float[] block = new float[16 * 16]; int wordsize = prequant; float oozrange = 1.0f / (float)header.Range; float range = (float)(1 << prequant); float premult = oozrange * range; float sub = (float)(1 << (prequant - 1)) + header.DCOffset * premult; header.QuantWBits = wordsize - 2; header.QuantWBits |= (prequant - 2) << 4; int k = 0; for (int j = patchY * 16; j < (patchY + 1) * 16; j++) { for (int i = patchX * 16; i < (patchX + 1) * 16; i++) { block[k++] = heightmap[j * 256 + i] * premult - sub; } } float[] ftemp = new float[16 * 16]; int[] itemp = new int[16 * 16]; for (int o = 0; o < 16; o++) DCTLine16(block, ftemp, o); for (int o = 0; o < 16; o++) DCTColumn16(ftemp, itemp, o); return itemp; }
private unsafe byte[] ApplyBsd0Patch(ref PatchInfoHeader patchInfoHeader, ref PatchHeader patchHeader, uint patchLength, byte[] originalData) { byte[] patchData; if (patchLength < patchHeader.PatchLength) patchData = UnpackRle(patchLength); else { patchData = new byte[patchLength]; if (Read(patchData, 0, checked((int)patchLength)) != patchLength) throw new EndOfStreamException(); } fixed (byte* patchDataPointer = patchData) { var bsdiffHeader = (PatchBsdiff40Header*)patchDataPointer; if (!BitConverter.IsLittleEndian) CommonMethods.SwapBytes((ulong*)patchDataPointer, sizeof(PatchBsdiff40Header)/sizeof(ulong)); if (bsdiffHeader->Signature != 0x3034464649445342 /* 'BSDIFF40' */) throw new InvalidDataException(ErrorMessages.GetString("Bsd0PatchHeaderInvalidSignature")); var controlBlock = (uint*)(patchDataPointer + sizeof(PatchBsdiff40Header)); var differenceBlock = (byte*)controlBlock + bsdiffHeader->ControlBlockLength; var extraBlock = differenceBlock + bsdiffHeader->DifferenceBlockLength; if (!BitConverter.IsLittleEndian) CommonMethods.SwapBytes(controlBlock, bsdiffHeader->ControlBlockLength/sizeof(uint)); var patchedBuffer = new byte[bsdiffHeader->PatchedFileSize]; uint o = 0; uint n = 0; try { while (n < patchedBuffer.Length) { uint differenceLength = *controlBlock++; uint extraLength = *controlBlock++; uint sourceOffset = *controlBlock++; // Apply the difference patch (Patched Data = Original data + Difference data) for (uint i = 0; i < differenceLength; i++, n++, o++) { patchedBuffer[n] = differenceBlock[i]; if (o < originalData.Length) patchedBuffer[n] += originalData[o]; } differenceBlock += differenceLength; // Apply the extra data patch (New data) for (int e = 0; e < extraLength; e++) patchedBuffer[n++] = extraBlock[e]; extraBlock += extraLength; unchecked { o += (sourceOffset & 0x80000000) != 0 ? (0x80000000 - sourceOffset) : sourceOffset; } } } catch (IndexOutOfRangeException ex) { throw new InvalidDataException(ErrorMessages.GetString("Bsd0PatchInvalidData"), ex); } return patchedBuffer; } }