diff options
author | onefang | 2019-09-11 16:36:50 +1000 |
---|---|---|
committer | onefang | 2019-09-11 16:36:50 +1000 |
commit | 50cd1ffd32f69228e566f2b0b89f86ea0d9fe489 (patch) | |
tree | 52f2ab0c04f1a5d7d6ac5dc872981b4b156447e7 /OpenSim/Region/Framework/Scenes/TerrainCompressor.cs | |
parent | Renamed branch to SledjChisl. (diff) | |
parent | Bump to release flavour, build 0. (diff) | |
download | opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.zip opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.gz opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.bz2 opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.xz |
Merge branch 'SledjChisl'
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/TerrainCompressor.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/TerrainCompressor.cs | 1589 |
1 files changed, 983 insertions, 606 deletions
diff --git a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs index fc8f8cd..9d1f815 100644 --- a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs +++ b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs | |||
@@ -27,10 +27,13 @@ | |||
27 | 27 | ||
28 | /* Freely adapted from the Aurora version of the terrain compressor. | 28 | /* Freely adapted from the Aurora version of the terrain compressor. |
29 | * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/ | 29 | * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/ |
30 | * Aurora version created from libOpenMetaverse Library terrain compressor | ||
30 | */ | 31 | */ |
31 | 32 | ||
32 | using System; | 33 | using System; |
34 | using System.Collections.Generic; | ||
33 | using System.Reflection; | 35 | using System.Reflection; |
36 | using System.Diagnostics; | ||
34 | 37 | ||
35 | using log4net; | 38 | using log4net; |
36 | 39 | ||
@@ -45,7 +48,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
45 | { | 48 | { |
46 | public static class OpenSimTerrainCompressor | 49 | public static class OpenSimTerrainCompressor |
47 | { | 50 | { |
48 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 51 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
49 | 52 | ||
50 | #pragma warning disable 414 | 53 | #pragma warning disable 414 |
51 | private static string LogHeader = "[TERRAIN COMPRESSOR]"; | 54 | private static string LogHeader = "[TERRAIN COMPRESSOR]"; |
@@ -61,47 +64,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
61 | private const int POSITIVE_VALUE = 0x6; | 64 | private const int POSITIVE_VALUE = 0x6; |
62 | private const int NEGATIVE_VALUE = 0x7; | 65 | private const int NEGATIVE_VALUE = 0x7; |
63 | 66 | ||
64 | private static readonly float[] DequantizeTable16 = | ||
65 | new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | ||
66 | |||
67 | private static readonly float[] DequantizeTable32 = | ||
68 | new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | ||
69 | 67 | ||
70 | private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | 68 | // private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; |
71 | //private static readonly float[] CosineTable32 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; | 69 | private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; |
72 | private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | ||
73 | private static readonly int[] CopyMatrix32 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | ||
74 | 70 | ||
75 | private static readonly float[] QuantizeTable16 = | 71 | private static readonly float[] QuantizeTable16 = |
76 | new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | 72 | new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; |
73 | private static readonly float[] DequantizeTable16 = | ||
74 | new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; | ||
77 | 75 | ||
78 | static OpenSimTerrainCompressor() | 76 | static OpenSimTerrainCompressor() |
79 | { | 77 | { |
80 | // Initialize the decompression tables | 78 | // Initialize the decompression tables |
81 | BuildDequantizeTable16(); | 79 | BuildDequantizeTable16(); |
82 | SetupCosines16(); | 80 | // SetupCosines16(); |
83 | BuildCopyMatrix16(); | 81 | BuildCopyMatrix16(); |
84 | BuildQuantizeTable16(); | 82 | BuildQuantizeTable16(); |
85 | } | 83 | } |
86 | 84 | ||
87 | // Used to send cloud and wind patches | 85 | // Used to send cloud and wind patches |
88 | public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, byte type, int pRegionSizeX, | 86 | public static LayerDataPacket CreateLayerDataPacketStandardSize(TerrainPatch[] patches, byte type) |
89 | int pRegionSizeY) | ||
90 | { | 87 | { |
91 | LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}}; | 88 | LayerDataPacket layer = new LayerDataPacket { LayerID = { Type = type } }; |
92 | 89 | ||
93 | TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader | 90 | TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader |
94 | {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize}; | 91 | { Stride = STRIDE, PatchSize = Constants.TerrainPatchSize }; |
95 | 92 | ||
96 | // Should be enough to fit even the most poorly packed data | 93 | // Should be enough to fit even the most poorly packed data |
97 | byte[] data = new byte[patches.Length*Constants.TerrainPatchSize*Constants.TerrainPatchSize*2]; | 94 | byte[] data = new byte[patches.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2]; |
98 | BitPack bitpack = new BitPack(data, 0); | 95 | BitPack bitpack = new BitPack(data, 0); |
99 | bitpack.PackBits(header.Stride, 16); | 96 | bitpack.PackBits(header.Stride, 16); |
100 | bitpack.PackBits(header.PatchSize, 8); | 97 | bitpack.PackBits(header.PatchSize, 8); |
101 | bitpack.PackBits(type, 8); | 98 | bitpack.PackBits(type, 8); |
102 | 99 | ||
103 | foreach (TerrainPatch t in patches) | 100 | foreach (TerrainPatch t in patches) |
104 | CreatePatch(bitpack, t.Data, t.X, t.Y, pRegionSizeX, pRegionSizeY); | 101 | CreatePatchtStandardSize(bitpack, t.Data, t.X, t.Y); |
105 | 102 | ||
106 | bitpack.PackBits(END_OF_PATCHES, 8); | 103 | bitpack.PackBits(END_OF_PATCHES, 8); |
107 | 104 | ||
@@ -111,122 +108,131 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
111 | return layer; | 108 | return layer; |
112 | } | 109 | } |
113 | 110 | ||
114 | // Create a land packet for a single patch. | 111 | public static void CreatePatchtStandardSize(BitPack output, float[] patchData, int x, int y) |
115 | public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY) | ||
116 | { | 112 | { |
117 | int[] xPieces = new int[1]; | 113 | TerrainPatch.Header header = PrescanPatch(patchData); |
118 | int[] yPieces = new int[1]; | 114 | header.QuantWBits = 136; |
119 | xPieces[0] = patchX; // patch X dimension | ||
120 | yPieces[0] = patchY; | ||
121 | 115 | ||
122 | return CreateLandPacket(terrData, xPieces, yPieces); | 116 | header.PatchIDs = (y & 0x1F); |
117 | header.PatchIDs += (x << 5); | ||
118 | |||
119 | int wbits; | ||
120 | int[] patch = CompressPatch(patchData, header, 10, out wbits); | ||
121 | EncodePatchHeader(output, header, patch, false, ref wbits); | ||
122 | EncodePatch(output, patch, 0, wbits); | ||
123 | } | 123 | } |
124 | 124 | ||
125 | public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] xPieces, int[] yPieces) | 125 | private static TerrainPatch.Header PrescanPatch(float[] patch) |
126 | { | 126 | { |
127 | byte landPacketType = (byte)TerrainPatch.LayerType.Land; | 127 | TerrainPatch.Header header = new TerrainPatch.Header(); |
128 | if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize) | 128 | float zmax = -99999999.0f; |
129 | float zmin = 99999999.0f; | ||
130 | |||
131 | for (int i = 0; i < Constants.TerrainPatchSize * Constants.TerrainPatchSize; i++) | ||
129 | { | 132 | { |
130 | landPacketType = (byte)TerrainPatch.LayerType.LandExtended; | 133 | float val = patch[i]; |
134 | if (val > zmax) zmax = val; | ||
135 | if (val < zmin) zmin = val; | ||
131 | } | 136 | } |
132 | 137 | ||
133 | return CreateLandPacket(terrData, xPieces, yPieces, landPacketType); | 138 | header.DCOffset = zmin; |
139 | header.Range = (int)((zmax - zmin) + 1.0f); | ||
140 | |||
141 | return header; | ||
134 | } | 142 | } |
135 | 143 | ||
136 | /// <summary> | 144 | private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits) |
137 | /// Creates a LayerData packet for compressed land data given a full | ||
138 | /// simulator heightmap and an array of indices of patches to compress | ||
139 | /// </summary> | ||
140 | /// <param name="terrData"> | ||
141 | /// Terrain data that can result in a meter square heightmap. | ||
142 | /// </param> | ||
143 | /// <param name="x"> | ||
144 | /// Array of indexes in the grid of patches | ||
145 | /// for this simulator. | ||
146 | /// If creating a packet for multiple patches, there will be entries in | ||
147 | /// both the X and Y arrays for each of the patches. | ||
148 | /// For example if patches 1 and 17 are to be sent, | ||
149 | /// x[] = {1,1} and y[] = {0,1} which specifies the patches at | ||
150 | /// indexes <1,0> and <1,1> (presuming the terrain size is 16x16 patches). | ||
151 | /// </param> | ||
152 | /// <param name="y"> | ||
153 | /// Array of indexes in the grid of patches. | ||
154 | /// </param> | ||
155 | /// <param name="type"></param> | ||
156 | /// <returns></returns> | ||
157 | public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type) | ||
158 | { | 145 | { |
159 | LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}}; | 146 | float[] block = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; |
147 | float oozrange = 1.0f / header.Range; | ||
148 | float range = (1 << prequant); | ||
149 | float premult = oozrange * range; | ||
160 | 150 | ||
161 | TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader | ||
162 | {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize}; | ||
163 | 151 | ||
164 | byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2]; | 152 | float sub = 0.5f * header.Range + header.DCOffset; |
165 | BitPack bitpack = new BitPack(data, 0); | ||
166 | bitpack.PackBits(header.Stride, 16); | ||
167 | bitpack.PackBits(header.PatchSize, 8); | ||
168 | bitpack.PackBits(type, 8); | ||
169 | 153 | ||
170 | for (int i = 0; i < x.Length; i++) | 154 | int wordsize = (prequant - 2) & 0x0f; |
171 | CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]); | 155 | header.QuantWBits = wordsize; |
156 | header.QuantWBits |= wordsize << 4; | ||
172 | 157 | ||
173 | bitpack.PackBits(END_OF_PATCHES, 8); | 158 | int k = 0; |
159 | for (int j = 0; j < Constants.TerrainPatchSize; j++) | ||
160 | { | ||
161 | for (int i = 0; i < Constants.TerrainPatchSize; i++) | ||
162 | block[k++] = (patchData[j * Constants.TerrainPatchSize + i] - sub) * premult; | ||
163 | } | ||
174 | 164 | ||
175 | layer.LayerData.Data = new byte[bitpack.BytePos + 1]; | 165 | float[] ftemp = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; |
176 | Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); | 166 | int[] iout = new int[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; |
177 | 167 | ||
178 | return layer; | 168 | wbits = (prequant >> 1); |
169 | |||
170 | dct16x16(block, iout, ref wbits); | ||
171 | |||
172 | return iout; | ||
179 | } | 173 | } |
180 | 174 | ||
181 | // Unused: left for historical reference. | 175 | // new using terrain data and patchs indexes |
182 | public static void CreatePatch(BitPack output, float[] patchData, int x, int y, int pRegionSizeX, int pRegionSizeY) | 176 | public static List<LayerDataPacket> CreateLayerDataPackets(TerrainData terrData, int[] x, int[] y, byte landPacketType) |
183 | { | 177 | { |
184 | TerrainPatch.Header header = PrescanPatch(patchData); | 178 | List<LayerDataPacket> ret = new List<LayerDataPacket>(); |
185 | header.QuantWBits = 136; | 179 | |
186 | if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize) | 180 | //create packet and global header |
187 | { | 181 | LayerDataPacket layer = new LayerDataPacket(); |
188 | header.PatchIDs = (y & 0xFFFF); | 182 | |
189 | header.PatchIDs += (x << 16); | 183 | layer.LayerID.Type = landPacketType; |
190 | } | 184 | |
191 | else | 185 | byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2]; |
186 | BitPack bitpack = new BitPack(data, 0); | ||
187 | bitpack.PackBits(STRIDE, 16); | ||
188 | bitpack.PackBits(Constants.TerrainPatchSize, 8); | ||
189 | bitpack.PackBits(landPacketType, 8); | ||
190 | |||
191 | for (int i = 0; i < x.Length; i++) | ||
192 | { | 192 | { |
193 | header.PatchIDs = (y & 0x1F); | 193 | CreatePatchFromTerrainData(bitpack, terrData, x[i], y[i]); |
194 | header.PatchIDs += (x << 5); | 194 | if (bitpack.BytePos > 980 && i != x.Length - 1) |
195 | { | ||
196 | //finish this packet | ||
197 | bitpack.PackBits(END_OF_PATCHES, 8); | ||
198 | |||
199 | layer.LayerData.Data = new byte[bitpack.BytePos + 1]; | ||
200 | Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); | ||
201 | ret.Add(layer); | ||
202 | |||
203 | // start another | ||
204 | layer = new LayerDataPacket(); | ||
205 | layer.LayerID.Type = landPacketType; | ||
206 | |||
207 | bitpack = new BitPack(data, 0); | ||
208 | bitpack.PackBits(STRIDE, 16); | ||
209 | bitpack.PackBits(Constants.TerrainPatchSize, 8); | ||
210 | bitpack.PackBits(landPacketType, 8); | ||
211 | } | ||
195 | } | 212 | } |
196 | 213 | ||
197 | // NOTE: No idea what prequant and postquant should be or what they do | 214 | bitpack.PackBits(END_OF_PATCHES, 8); |
198 | 215 | ||
199 | int wbits; | 216 | layer.LayerData.Data = new byte[bitpack.BytePos + 1]; |
200 | int[] patch = CompressPatch(patchData, header, 10, out wbits); | 217 | Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); |
201 | wbits = EncodePatchHeader(output, header, patch, Constants.RegionSize, Constants.RegionSize, wbits); | 218 | ret.Add(layer); |
202 | EncodePatch(output, patch, 0, wbits); | 219 | |
220 | return ret; | ||
203 | } | 221 | } |
204 | 222 | ||
205 | /// <summary> | 223 | public static void CreatePatchFromTerrainData(BitPack output, TerrainData terrData, int patchX, int patchY) |
206 | /// Add a patch of terrain to a BitPacker | ||
207 | /// </summary> | ||
208 | /// <param name="output">BitPacker to write the patch to</param> | ||
209 | /// <param name="heightmap"> | ||
210 | /// Heightmap of the simulator. Presumed to be an sizeX*sizeY array. | ||
211 | /// </param> | ||
212 | /// <param name="patchX"> | ||
213 | /// X offset of the patch to create. | ||
214 | /// </param> | ||
215 | /// <param name="patchY"> | ||
216 | /// Y offset of the patch to create. | ||
217 | /// </param> | ||
218 | /// <param name="pRegionSizeX"></param> | ||
219 | /// <param name="pRegionSizeY"></param> | ||
220 | public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY) | ||
221 | { | 224 | { |
222 | TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY); | 225 | float frange; |
223 | header.QuantWBits = 136; | 226 | TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY, out frange); |
227 | header.QuantWBits = 130; | ||
224 | 228 | ||
229 | bool largeRegion = false; | ||
225 | // If larger than legacy region size, pack patch X and Y info differently. | 230 | // If larger than legacy region size, pack patch X and Y info differently. |
226 | if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize) | 231 | if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize) |
227 | { | 232 | { |
228 | header.PatchIDs = (patchY & 0xFFFF); | 233 | header.PatchIDs = (patchY & 0xFFFF); |
229 | header.PatchIDs += (patchX << 16); | 234 | header.PatchIDs += (patchX << 16); |
235 | largeRegion = true; | ||
230 | } | 236 | } |
231 | else | 237 | else |
232 | { | 238 | { |
@@ -234,45 +240,45 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
234 | header.PatchIDs += (patchX << 5); | 240 | header.PatchIDs += (patchX << 5); |
235 | } | 241 | } |
236 | 242 | ||
237 | // m_log.DebugFormat("{0} CreatePatchFromHeightmap. patchX={1}, patchY={2}, DCOffset={3}, range={4}", | 243 | if (Math.Round((double)frange, 2) == 1.0) |
238 | // LogHeader, patchX, patchY, header.DCOffset, header.Range); | 244 | { |
245 | // flat terrain speed up things | ||
239 | 246 | ||
240 | // NOTE: No idea what prequant and postquant should be or what they do | 247 | header.DCOffset -= 0.5f; |
241 | int wbits; | ||
242 | int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits); | ||
243 | wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits); | ||
244 | EncodePatch(output, patch, 0, wbits); | ||
245 | } | ||
246 | 248 | ||
247 | private static TerrainPatch.Header PrescanPatch(float[] patch) | 249 | header.QuantWBits = 0x00; |
248 | { | 250 | output.PackBits(header.QuantWBits, 8); |
249 | TerrainPatch.Header header = new TerrainPatch.Header(); | 251 | output.PackFloat(header.DCOffset); |
250 | float zmax = -99999999.0f; | 252 | output.PackBits(1, 16); |
251 | float zmin = 99999999.0f; | 253 | if (largeRegion) |
254 | output.PackBits(header.PatchIDs, 32); | ||
255 | else | ||
256 | output.PackBits(header.PatchIDs, 10); | ||
252 | 257 | ||
253 | for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++) | 258 | // and thats all |
254 | { | 259 | output.PackBits(ZERO_EOB, 2); |
255 | float val = patch[i]; | 260 | return; |
256 | if (val > zmax) zmax = val; | ||
257 | if (val < zmin) zmin = val; | ||
258 | } | 261 | } |
259 | 262 | ||
260 | header.DCOffset = zmin; | 263 | int wbits; |
261 | header.Range = (int) ((zmax - zmin) + 1.0f); | 264 | int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits); |
262 | 265 | EncodePatchHeader(output, header, patch, largeRegion, ref wbits); | |
263 | return header; | 266 | EncodePatch(output, patch, 0, wbits); |
264 | } | 267 | } |
265 | 268 | ||
266 | // Scan the height info we're returning and return a patch packet header for this patch. | 269 | // Scan the height info we're returning and return a patch packet header for this patch. |
267 | private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY) | 270 | private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY, out float frange) |
268 | { | 271 | { |
269 | TerrainPatch.Header header = new TerrainPatch.Header(); | 272 | TerrainPatch.Header header = new TerrainPatch.Header(); |
270 | float zmax = -99999999.0f; | 273 | float zmax = float.MinValue; |
271 | float zmin = 99999999.0f; | 274 | float zmin = float.MaxValue; |
272 | 275 | ||
273 | for (int j = patchY*Constants.TerrainPatchSize; j < (patchY + 1)*Constants.TerrainPatchSize; j++) | 276 | int startx = patchX * Constants.TerrainPatchSize; |
277 | int starty = patchY * Constants.TerrainPatchSize; | ||
278 | |||
279 | for (int j = starty; j < starty + Constants.TerrainPatchSize; j++) | ||
274 | { | 280 | { |
275 | for (int i = patchX*Constants.TerrainPatchSize; i < (patchX + 1)*Constants.TerrainPatchSize; i++) | 281 | for (int i = startx; i < startx + Constants.TerrainPatchSize; i++) |
276 | { | 282 | { |
277 | float val = terrData[i, j]; | 283 | float val = terrData[i, j]; |
278 | if (val > zmax) zmax = val; | 284 | if (val > zmax) zmax = val; |
@@ -281,309 +287,430 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
281 | } | 287 | } |
282 | 288 | ||
283 | header.DCOffset = zmin; | 289 | header.DCOffset = zmin; |
284 | header.Range = (int)((zmax - zmin) + 1.0f); | 290 | frange = ((zmax - zmin) + 1.0f); |
285 | 291 | header.Range = (int)frange; | |
286 | return header; | ||
287 | } | ||
288 | |||
289 | public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack) | ||
290 | { | ||
291 | TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)}; | ||
292 | |||
293 | // Quantized word bits | ||
294 | if (header.QuantWBits == END_OF_PATCHES) | ||
295 | return header; | ||
296 | |||
297 | // DC offset | ||
298 | header.DCOffset = bitpack.UnpackFloat(); | ||
299 | |||
300 | // Range | ||
301 | header.Range = bitpack.UnpackBits(16); | ||
302 | |||
303 | // Patch IDs (10 bits) | ||
304 | header.PatchIDs = bitpack.UnpackBits(10); | ||
305 | |||
306 | // Word bits | ||
307 | header.WordBits = (uint) ((header.QuantWBits & 0x0f) + 2); | ||
308 | 292 | ||
309 | return header; | 293 | return header; |
310 | } | 294 | } |
311 | 295 | ||
312 | private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, uint pRegionSizeX, | 296 | private static void EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, bool largeRegion, ref int wbits) |
313 | uint pRegionSizeY, int wbits) | ||
314 | { | 297 | { |
315 | /* | ||
316 | int temp; | ||
317 | int wbits = (header.QuantWBits & 0x0f) + 2; | ||
318 | uint maxWbits = (uint)wbits + 5; | ||
319 | uint minWbits = ((uint)wbits >> 1); | ||
320 | int wbitsMaxValue; | ||
321 | */ | ||
322 | // goal is to determ minimum number of bits to use so all data fits | ||
323 | /* | ||
324 | wbits = (int)minWbits; | ||
325 | wbitsMaxValue = (1 << wbits); | ||
326 | |||
327 | for (int i = 0; i < patch.Length; i++) | ||
328 | { | ||
329 | temp = patch[i]; | ||
330 | if (temp != 0) | ||
331 | { | ||
332 | // Get the absolute value | ||
333 | if (temp < 0) temp *= -1; | ||
334 | |||
335 | no coments.. | ||
336 | |||
337 | for (int j = (int)maxWbits; j > (int)minWbits; j--) | ||
338 | { | ||
339 | if ((temp & (1 << j)) != 0) | ||
340 | { | ||
341 | if (j > wbits) wbits = j; | ||
342 | break; | ||
343 | } | ||
344 | } | ||
345 | |||
346 | while (temp > wbitsMaxValue) | ||
347 | { | ||
348 | wbits++; | ||
349 | if (wbits == maxWbits) | ||
350 | goto Done; | ||
351 | wbitsMaxValue = 1 << wbits; | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | |||
356 | Done: | ||
357 | |||
358 | // wbits += 1; | ||
359 | */ | ||
360 | // better check | ||
361 | if (wbits > 17) | 298 | if (wbits > 17) |
362 | wbits = 16; | 299 | wbits = 17; |
363 | else if (wbits < 3) | 300 | else if (wbits < 2) |
364 | wbits = 3; | 301 | wbits = 2; |
365 | 302 | ||
366 | header.QuantWBits &= 0xf0; | 303 | header.QuantWBits &= 0xf0; |
367 | |||
368 | header.QuantWBits |= (wbits - 2); | 304 | header.QuantWBits |= (wbits - 2); |
369 | 305 | ||
370 | output.PackBits(header.QuantWBits, 8); | 306 | output.PackBits(header.QuantWBits, 8); |
371 | output.PackFloat(header.DCOffset); | 307 | output.PackFloat(header.DCOffset); |
372 | output.PackBits(header.Range, 16); | 308 | output.PackBits(header.Range, 16); |
373 | if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize) | 309 | if (largeRegion) |
374 | output.PackBits(header.PatchIDs, 32); | 310 | output.PackBits(header.PatchIDs, 32); |
375 | else | 311 | else |
376 | output.PackBits(header.PatchIDs, 10); | 312 | output.PackBits(header.PatchIDs, 10); |
377 | |||
378 | return wbits; | ||
379 | } | 313 | } |
380 | 314 | ||
381 | private static void IDCTColumn16(float[] linein, float[] lineout, int column) | 315 | private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits) |
382 | { | 316 | { |
383 | for (int n = 0; n < Constants.TerrainPatchSize; n++) | 317 | int maxwbitssize = (1 << wbits) - 1; |
384 | { | 318 | int fullSize = Constants.TerrainPatchSize * Constants.TerrainPatchSize; |
385 | float total = OO_SQRT2*linein[column]; | ||
386 | |||
387 | for (int u = 1; u < Constants.TerrainPatchSize; u++) | ||
388 | { | ||
389 | int usize = u*Constants.TerrainPatchSize; | ||
390 | total += linein[usize + column]*CosineTable16[usize + n]; | ||
391 | } | ||
392 | 319 | ||
393 | lineout[Constants.TerrainPatchSize*n + column] = total; | 320 | if (postquant > fullSize || postquant < 0) |
321 | { | ||
322 | Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error); | ||
323 | return; | ||
394 | } | 324 | } |
395 | } | ||
396 | 325 | ||
397 | private static void IDCTLine16(float[] linein, float[] lineout, int line) | 326 | if (postquant != 0) |
398 | { | 327 | patch[fullSize - postquant] = 0; |
399 | const float oosob = 2.0f/Constants.TerrainPatchSize; | ||
400 | int lineSize = line*Constants.TerrainPatchSize; | ||
401 | 328 | ||
402 | for (int n = 0; n < Constants.TerrainPatchSize; n++) | 329 | int lastZeroindx = fullSize - postquant; |
330 | |||
331 | for (int i = 0; i < fullSize; i++) | ||
403 | { | 332 | { |
404 | float total = OO_SQRT2*linein[lineSize]; | 333 | int temp = patch[i]; |
405 | 334 | ||
406 | for (int u = 1; u < Constants.TerrainPatchSize; u++) | 335 | if (temp == 0) |
407 | { | 336 | { |
408 | total += linein[lineSize + u]*CosineTable16[u*Constants.TerrainPatchSize + n]; | 337 | bool eob = true; |
338 | |||
339 | for (int j = i; j < lastZeroindx; j++) | ||
340 | { | ||
341 | if (patch[j] != 0) | ||
342 | { | ||
343 | eob = false; | ||
344 | break; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | if (eob) | ||
349 | { | ||
350 | output.PackBits(ZERO_EOB, 2); | ||
351 | return; | ||
352 | } | ||
353 | output.PackBits(ZERO_CODE, 1); | ||
409 | } | 354 | } |
355 | else | ||
356 | { | ||
357 | if (temp < 0) | ||
358 | { | ||
359 | temp *= -1; | ||
360 | |||
361 | if (temp > maxwbitssize) temp = maxwbitssize; | ||
362 | |||
363 | output.PackBits(NEGATIVE_VALUE, 3); | ||
364 | output.PackBits(temp, wbits); | ||
365 | } | ||
366 | else | ||
367 | { | ||
368 | if (temp > maxwbitssize) temp = maxwbitssize; | ||
410 | 369 | ||
411 | lineout[lineSize + n] = total*oosob; | 370 | output.PackBits(POSITIVE_VALUE, 3); |
371 | output.PackBits(temp, wbits); | ||
372 | } | ||
373 | } | ||
412 | } | 374 | } |
413 | } | 375 | } |
414 | 376 | ||
415 | /* | 377 | private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header, |
416 | private static void DCTLine16(float[] linein, float[] lineout, int line) | 378 | int prequant, out int wbits) |
417 | { | 379 | { |
418 | float total = 0.0f; | 380 | float[] block = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; |
419 | int lineSize = line * Constants.TerrainPatchSize; | 381 | int[] iout = new int[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; |
420 | 382 | ||
421 | for (int n = 0; n < Constants.TerrainPatchSize; n++) | 383 | float oozrange = 1.0f / header.Range; |
422 | { | 384 | float invprequat = (1 << prequant); |
423 | total += linein[lineSize + n]; | 385 | float premult = oozrange * invprequat; |
424 | } | ||
425 | 386 | ||
426 | lineout[lineSize] = OO_SQRT2 * total; | 387 | float sub = 0.5f * header.Range + header.DCOffset; |
427 | 388 | ||
428 | int uptr = 0; | 389 | int wordsize = (prequant - 2) & 0x0f; |
429 | for (int u = 1; u < Constants.TerrainPatchSize; u++) | 390 | header.QuantWBits = wordsize; |
430 | { | 391 | header.QuantWBits |= wordsize << 4; |
431 | total = 0.0f; | ||
432 | uptr += Constants.TerrainPatchSize; | ||
433 | 392 | ||
434 | for (int n = 0; n < Constants.TerrainPatchSize; n++) | 393 | int k = 0; |
394 | int startX = patchX * Constants.TerrainPatchSize; | ||
395 | int startY = patchY * Constants.TerrainPatchSize; | ||
396 | for (int y = startY; y < startY + Constants.TerrainPatchSize; y++) | ||
397 | { | ||
398 | for (int x = startX; x < startX + Constants.TerrainPatchSize; x++) | ||
435 | { | 399 | { |
436 | total += linein[lineSize + n] * CosineTable16[uptr + n]; | 400 | block[k++] = (terrData[x, y] - sub) * premult; |
437 | } | 401 | } |
438 | |||
439 | lineout[lineSize + u] = total; | ||
440 | } | 402 | } |
403 | |||
404 | wbits = (prequant >> 1); | ||
405 | |||
406 | dct16x16(block, iout, ref wbits); | ||
407 | |||
408 | return iout; | ||
441 | } | 409 | } |
442 | */ | ||
443 | 410 | ||
444 | private static void DCTLine16(float[] linein, float[] lineout, int line) | 411 | #region Initialization |
445 | { | ||
446 | // outputs transpose data (lines exchanged with coluns ) | ||
447 | // so to save a bit of cpu when doing coluns | ||
448 | float total = 0.0f; | ||
449 | int lineSize = line*Constants.TerrainPatchSize; | ||
450 | 412 | ||
451 | for (int n = 0; n < Constants.TerrainPatchSize; n++) | 413 | private static void BuildDequantizeTable16() |
414 | { | ||
415 | for (int j = 0; j < Constants.TerrainPatchSize; j++) | ||
452 | { | 416 | { |
453 | total += linein[lineSize + n]; | 417 | for (int i = 0; i < Constants.TerrainPatchSize; i++) |
418 | { | ||
419 | DequantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f + 2.0f * (i + j); | ||
420 | } | ||
454 | } | 421 | } |
422 | } | ||
455 | 423 | ||
456 | lineout[line] = OO_SQRT2*total; | 424 | private static void BuildQuantizeTable16() |
457 | 425 | { | |
458 | for (int u = Constants.TerrainPatchSize; | 426 | const float oosob = 2.0f / Constants.TerrainPatchSize; |
459 | u < Constants.TerrainPatchSize*Constants.TerrainPatchSize; | 427 | for (int j = 0; j < Constants.TerrainPatchSize; j++) |
460 | u += Constants.TerrainPatchSize) | ||
461 | { | 428 | { |
462 | total = 0.0f; | 429 | for (int i = 0; i < Constants.TerrainPatchSize; i++) |
463 | for (int ptrn = lineSize, ptru = u; ptrn < lineSize + Constants.TerrainPatchSize; ptrn++,ptru++) | ||
464 | { | 430 | { |
465 | total += linein[ptrn]*CosineTable16[ptru]; | 431 | QuantizeTable16[j * Constants.TerrainPatchSize + i] = oosob / (1.0f + 2.0f * (i + (float)j)); |
466 | } | 432 | } |
467 | |||
468 | lineout[line + u] = total; | ||
469 | } | 433 | } |
470 | } | 434 | } |
471 | 435 | ||
436 | private static void BuildCopyMatrix16() | ||
437 | { | ||
438 | bool diag = false; | ||
439 | bool right = true; | ||
440 | int i = 0; | ||
441 | int j = 0; | ||
442 | int count = 0; | ||
443 | |||
444 | while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize) | ||
445 | { | ||
446 | CopyMatrix16[j * Constants.TerrainPatchSize + i] = count++; | ||
472 | 447 | ||
473 | /* | 448 | if (!diag) |
474 | private static void DCTColumn16(float[] linein, int[] lineout, int column) | ||
475 | { | 449 | { |
476 | float total = 0.0f; | 450 | if (right) |
477 | // const float oosob = 2.0f / Constants.TerrainPatchSize; | ||
478 | |||
479 | for (int n = 0; n < Constants.TerrainPatchSize; n++) | ||
480 | { | 451 | { |
481 | total += linein[Constants.TerrainPatchSize * n + column]; | 452 | if (i < Constants.TerrainPatchSize - 1) i++; |
482 | } | 453 | else j++; |
483 | |||
484 | // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]); | ||
485 | lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * QuantizeTable16[column]); | ||
486 | 454 | ||
487 | for (int uptr = Constants.TerrainPatchSize; uptr < Constants.TerrainPatchSize * Constants.TerrainPatchSize; uptr += Constants.TerrainPatchSize) | 455 | right = false; |
456 | diag = true; | ||
457 | } | ||
458 | else | ||
488 | { | 459 | { |
489 | total = 0.0f; | 460 | if (j < Constants.TerrainPatchSize - 1) j++; |
490 | 461 | else i++; | |
491 | for (int n = 0; n < Constants.TerrainPatchSize; n++) | ||
492 | { | ||
493 | total += linein[Constants.TerrainPatchSize * n + column] * CosineTable16[uptr + n]; | ||
494 | } | ||
495 | 462 | ||
496 | // lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]); | 463 | right = true; |
497 | lineout[CopyMatrix16[uptr + column]] = (int)(total * QuantizeTable16[uptr + column]); | 464 | diag = true; |
498 | } | 465 | } |
466 | } | ||
467 | else | ||
468 | { | ||
469 | if (right) | ||
470 | { | ||
471 | i++; | ||
472 | j--; | ||
473 | if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false; | ||
474 | } | ||
475 | else | ||
476 | { | ||
477 | i--; | ||
478 | j++; | ||
479 | if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false; | ||
480 | } | ||
499 | } | 481 | } |
482 | } | ||
483 | } | ||
500 | 484 | ||
501 | private static void DCTColumn16(float[] linein, int[] lineout, int column) | 485 | #endregion Initialization |
502 | { | ||
503 | // input columns are in fact stored in lines now | ||
504 | 486 | ||
505 | float total = 0.0f; | ||
506 | // const float oosob = 2.0f / Constants.TerrainPatchSize; | ||
507 | int inlinesptr = Constants.TerrainPatchSize*column; | ||
508 | 487 | ||
509 | for (int n = 0; n < Constants.TerrainPatchSize; n++) | ||
510 | { | ||
511 | total += linein[inlinesptr + n]; | ||
512 | } | ||
513 | 488 | ||
514 | // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]); | ||
515 | lineout[CopyMatrix16[column]] = (int) (OO_SQRT2*total*QuantizeTable16[column]); | ||
516 | 489 | ||
517 | for (int uptr = Constants.TerrainPatchSize; | 490 | #region DCT |
518 | uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize; | ||
519 | uptr += Constants.TerrainPatchSize) | ||
520 | { | ||
521 | total = 0.0f; | ||
522 | 491 | ||
523 | for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++) | 492 | /* DCT (Discrete Cosine Transform) |
524 | { | 493 | adaptation from |
525 | total += linein[n]*CosineTable16[ptru]; | 494 | General Purpose 2D,3D FFT (Fast Fourier Transform) Package |
526 | } | 495 | by Takuya OOURA (email: ooura@kurims.kyoto-u.ac.jp) |
527 | 496 | ||
528 | // lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]); | 497 | -------- 16x16 DCT (Discrete Cosine Transform) / Inverse of DCT -------- |
529 | lineout[CopyMatrix16[uptr + column]] = (int) (total*QuantizeTable16[uptr + column]); | 498 | [definition] |
530 | } | 499 | <case1> Normalized 16x16 IDCT |
531 | } | 500 | C[k1 + k2] = (1/8) * sum_j1=0^15 sum_j2=0^15 |
501 | tmp[j1 + j2] * s[j1] * s[j2] * | ||
502 | cos(pi*j1*(k1+1/2)/16) * | ||
503 | cos(pi*j2*(k2+1/2)/16), 0<=k1<16, 0<=k2<16 | ||
504 | (s[0] = 1/sqrt(2), s[j] = 1, j > 0) | ||
505 | <case2> Normalized 16x16 DCT | ||
506 | C[k1 + k2] = (1/8) * s[k1] * s[k2] * sum_j1=0^15 sum_j2=0^15 | ||
507 | tmp[j1 + j2] * | ||
508 | cos(pi*(j1+1/2)*k1/16) * | ||
509 | cos(pi*(j2+1/2)*k2/16), 0<=k1<16, 0<=k2<16 | ||
510 | (s[0] = 1/sqrt(2), s[j] = 1, j > 0) | ||
532 | */ | 511 | */ |
533 | 512 | ||
534 | private static int DCTColumn16Wbits(float[] linein, int[] lineout, int column, int wbits, int maxwbits) | 513 | /* Cn_kR = sqrt(2.0/n) * cos(pi/2*k/n) */ |
514 | /* Cn_kI = sqrt(2.0/n) * sin(pi/2*k/n) */ | ||
515 | /* Wn_kR = cos(pi/2*k/n) */ | ||
516 | /* Wn_kI = sin(pi/2*k/n) */ | ||
517 | |||
518 | const float C16_1R = 0.35185093438159561476f * 2.82842712474619f; | ||
519 | const float C16_1I = 0.03465429229977286565f * 2.82842712474619f; | ||
520 | const float C16_2R = 0.34675996133053686546f * 2.82842712474619f; | ||
521 | const float C16_2I = 0.06897484482073575308f * 2.82842712474619f; | ||
522 | const float C16_3R = 0.33832950029358816957f * 2.82842712474619f; | ||
523 | const float C16_3I = 0.10263113188058934529f * 2.82842712474619f; | ||
524 | const float C16_4R = 0.32664074121909413196f * 2.82842712474619f; | ||
525 | const float C16_4I = 0.13529902503654924610f * 2.82842712474619f; | ||
526 | const float C16_5R = 0.31180625324666780814f * 2.82842712474619f; | ||
527 | const float C16_5I = 0.16666391461943662432f * 2.82842712474619f; | ||
528 | const float C16_6R = 0.29396890060483967924f * 2.82842712474619f; | ||
529 | const float C16_6I = 0.19642373959677554532f * 2.82842712474619f; | ||
530 | const float C16_7R = 0.27330046675043937206f * 2.82842712474619f; | ||
531 | const float C16_7I = 0.22429189658565907106f * 2.82842712474619f; | ||
532 | const float C16_8R = 0.25f * 2.82842712474619f; | ||
533 | const float W16_4R = 0.92387953251128675613f; | ||
534 | const float W16_4I = 0.38268343236508977173f; | ||
535 | const float W16_8R = 0.70710678118654752440f; | ||
536 | |||
537 | static void dct16x16(float[] a, int[] iout, ref int wbits) | ||
535 | { | 538 | { |
536 | // input columns are in fact stored in lines now | 539 | float[] tmp = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; |
537 | 540 | ||
538 | bool dowbits = wbits != maxwbits; | 541 | float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; |
539 | int wbitsMaxValue = 1 << wbits; | 542 | float x4r, x4i, x5r, x5i, x6r, x6i, x7r, x7i; |
543 | float xr, xi; | ||
544 | float ftmp; | ||
540 | 545 | ||
541 | float total = 0.0f; | 546 | int fullSize = Constants.TerrainPatchSize * Constants.TerrainPatchSize; |
542 | // const float oosob = 2.0f / Constants.TerrainPatchSize; | 547 | int itmp; |
543 | int inlinesptr = Constants.TerrainPatchSize*column; | 548 | int j, k; |
549 | int indx; | ||
544 | 550 | ||
545 | for (int n = 0; n < Constants.TerrainPatchSize; n++) | 551 | const int maxwbits = 17; // per header encoding |
552 | int wbitsMaxValue = 1 << wbits; | ||
553 | bool dowbits = wbits < 17; | ||
554 | |||
555 | for (j = 0, k = 0; j < fullSize; j += Constants.TerrainPatchSize, k++) | ||
546 | { | 556 | { |
547 | total += linein[inlinesptr + n]; | 557 | x4r = a[0 + j] - a[15 + j]; |
558 | xr = a[0 + j] + a[15 + j]; | ||
559 | x4i = a[8 + j] - a[7 + j]; | ||
560 | xi = a[8 + j] + a[7 + j]; | ||
561 | x0r = xr + xi; | ||
562 | x0i = xr - xi; | ||
563 | x5r = a[2 + j] - a[13 + j]; | ||
564 | xr = a[2 + j] + a[13 + j]; | ||
565 | x5i = a[10 + j] - a[5 + j]; | ||
566 | xi = a[10 + j] + a[5 + j]; | ||
567 | x1r = xr + xi; | ||
568 | x1i = xr - xi; | ||
569 | x6r = a[4 + j] - a[11 + j]; | ||
570 | xr = a[4 + j] + a[11 + j]; | ||
571 | x6i = a[12 + j] - a[3 + j]; | ||
572 | xi = a[12 + j] + a[3 + j]; | ||
573 | x2r = xr + xi; | ||
574 | x2i = xr - xi; | ||
575 | x7r = a[6 + j] - a[9 + j]; | ||
576 | xr = a[6 + j] + a[9 + j]; | ||
577 | x7i = a[14 + j] - a[1 + j]; | ||
578 | xi = a[14 + j] + a[1 + j]; | ||
579 | x3r = xr + xi; | ||
580 | x3i = xr - xi; | ||
581 | xr = x0r + x2r; | ||
582 | xi = x1r + x3r; | ||
583 | tmp[k] = C16_8R * (xr + xi); // | ||
584 | tmp[8 * Constants.TerrainPatchSize + k] = C16_8R * (xr - xi); // | ||
585 | xr = x0r - x2r; | ||
586 | xi = x1r - x3r; | ||
587 | tmp[4 * Constants.TerrainPatchSize + k] = C16_4R * xr - C16_4I * xi; // | ||
588 | tmp[12 * Constants.TerrainPatchSize + k] = C16_4R * xi + C16_4I * xr; // | ||
589 | x0r = W16_8R * (x1i - x3i); | ||
590 | x2r = W16_8R * (x1i + x3i); | ||
591 | xr = x0i + x0r; | ||
592 | xi = x2r + x2i; | ||
593 | tmp[2 * Constants.TerrainPatchSize + k] = C16_2R * xr - C16_2I * xi; // | ||
594 | tmp[14 * Constants.TerrainPatchSize + k] = C16_2R * xi + C16_2I * xr; // | ||
595 | xr = x0i - x0r; | ||
596 | xi = x2r - x2i; | ||
597 | tmp[6 * Constants.TerrainPatchSize + k] = C16_6R * xr - C16_6I * xi; // | ||
598 | tmp[10 * Constants.TerrainPatchSize + k] = C16_6R * xi + C16_6I * xr; // | ||
599 | xr = W16_8R * (x6r - x6i); | ||
600 | xi = W16_8R * (x6i + x6r); | ||
601 | x6r = x4r - xr; | ||
602 | x6i = x4i - xi; | ||
603 | x4r += xr; | ||
604 | x4i += xi; | ||
605 | xr = W16_4I * x7r - W16_4R * x7i; | ||
606 | xi = W16_4I * x7i + W16_4R * x7r; | ||
607 | x7r = W16_4R * x5r - W16_4I * x5i; | ||
608 | x7i = W16_4R * x5i + W16_4I * x5r; | ||
609 | x5r = x7r + xr; | ||
610 | x5i = x7i + xi; | ||
611 | x7r -= xr; | ||
612 | x7i -= xi; | ||
613 | xr = x4r + x5r; | ||
614 | xi = x5i + x4i; | ||
615 | tmp[Constants.TerrainPatchSize + k] = C16_1R * xr - C16_1I * xi; // | ||
616 | tmp[15 * Constants.TerrainPatchSize + k] = C16_1R * xi + C16_1I * xr; // | ||
617 | xr = x4r - x5r; | ||
618 | xi = x5i - x4i; | ||
619 | tmp[7 * Constants.TerrainPatchSize + k] = C16_7R * xr - C16_7I * xi; // | ||
620 | tmp[9 * Constants.TerrainPatchSize + k] = C16_7R * xi + C16_7I * xr; // | ||
621 | xr = x6r - x7i; | ||
622 | xi = x7r + x6i; | ||
623 | tmp[5 * Constants.TerrainPatchSize + k] = C16_5R * xr - C16_5I * xi; // | ||
624 | tmp[11 * Constants.TerrainPatchSize + k] = C16_5R * xi + C16_5I * xr; // | ||
625 | xr = x6r + x7i; | ||
626 | xi = x7r - x6i; | ||
627 | tmp[3 * Constants.TerrainPatchSize + k] = C16_3R * xr - C16_3I * xi; // | ||
628 | tmp[13 * Constants.TerrainPatchSize + k] = C16_3R * xi + C16_3I * xr; // | ||
548 | } | 629 | } |
549 | 630 | ||
550 | // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]); | 631 | for (j = 0, k = 0; j < fullSize; j += Constants.TerrainPatchSize, k++) |
551 | int tmp = (int) (OO_SQRT2*total*QuantizeTable16[column]); | ||
552 | lineout[CopyMatrix16[column]] = tmp; | ||
553 | |||
554 | if (dowbits) | ||
555 | { | 632 | { |
556 | if (tmp < 0) tmp *= -1; | 633 | x4r = tmp[0 + j] - tmp[15 + j]; |
557 | while (tmp > wbitsMaxValue) | 634 | xr = tmp[0 + j] + tmp[15 + j]; |
635 | x4i = tmp[8 + j] - tmp[7 + j]; | ||
636 | xi = tmp[8 + j] + tmp[7 + j]; | ||
637 | x0r = xr + xi; | ||
638 | x0i = xr - xi; | ||
639 | x5r = tmp[2 + j] - tmp[13 + j]; | ||
640 | xr = tmp[2 + j] + tmp[13 + j]; | ||
641 | x5i = tmp[10 + j] - tmp[5 + j]; | ||
642 | xi = tmp[10 + j] + tmp[5 + j]; | ||
643 | x1r = xr + xi; | ||
644 | x1i = xr - xi; | ||
645 | x6r = tmp[4 + j] - tmp[11 + j]; | ||
646 | xr = tmp[4 + j] + tmp[11 + j]; | ||
647 | x6i = tmp[12 + j] - tmp[3 + j]; | ||
648 | xi = tmp[12 + j] + tmp[3 + j]; | ||
649 | x2r = xr + xi; | ||
650 | x2i = xr - xi; | ||
651 | x7r = tmp[6 + j] - tmp[9 + j]; | ||
652 | xr = tmp[6 + j] + tmp[9 + j]; | ||
653 | x7i = tmp[14 + j] - tmp[1 + j]; | ||
654 | xi = tmp[14 + j] + tmp[1 + j]; | ||
655 | x3r = xr + xi; | ||
656 | x3i = xr - xi; | ||
657 | xr = x0r + x2r; | ||
658 | xi = x1r + x3r; | ||
659 | |||
660 | //tmp[0 + k] = C16_8R * (xr + xi); // | ||
661 | ftmp = C16_8R * (xr + xi); | ||
662 | itmp = (int)(ftmp * QuantizeTable16[k]); | ||
663 | iout[CopyMatrix16[k]] = itmp; | ||
664 | |||
665 | if (dowbits) | ||
558 | { | 666 | { |
559 | wbits++; | 667 | if (itmp < 0) itmp *= -1; |
560 | wbitsMaxValue = 1 << wbits; | 668 | while (itmp > wbitsMaxValue) |
561 | if (wbits == maxwbits) | ||
562 | { | 669 | { |
563 | dowbits = false; | 670 | wbits++; |
564 | break; | 671 | wbitsMaxValue = 1 << wbits; |
672 | if (wbits == maxwbits) | ||
673 | { | ||
674 | dowbits = false; | ||
675 | break; | ||
676 | } | ||
565 | } | 677 | } |
566 | } | 678 | } |
567 | } | ||
568 | 679 | ||
569 | for (int uptr = Constants.TerrainPatchSize; | 680 | //tmp[8 * Constants.TerrainPatchSize + k] = C16_8R * (xr - xi); // |
570 | uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize; | 681 | ftmp = C16_8R * (xr - xi); |
571 | uptr += Constants.TerrainPatchSize) | 682 | indx = 8 * Constants.TerrainPatchSize + k; |
572 | { | 683 | itmp = (int)(ftmp * QuantizeTable16[indx]); |
573 | total = 0.0f; | 684 | iout[CopyMatrix16[indx]] = itmp; |
574 | 685 | ||
575 | for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++) | 686 | if (dowbits) |
576 | { | 687 | { |
577 | total += linein[n]*CosineTable16[ptru]; | 688 | if (itmp < 0) itmp *= -1; |
689 | while (itmp > wbitsMaxValue) | ||
690 | { | ||
691 | wbits++; | ||
692 | wbitsMaxValue = 1 << wbits; | ||
693 | if (wbits == maxwbits) | ||
694 | { | ||
695 | dowbits = false; | ||
696 | break; | ||
697 | } | ||
698 | } | ||
578 | } | 699 | } |
579 | 700 | ||
580 | tmp = (int) (total*QuantizeTable16[uptr + column]); | 701 | xr = x0r - x2r; |
581 | lineout[CopyMatrix16[uptr + column]] = tmp; | 702 | xi = x1r - x3r; |
703 | |||
704 | //tmp[4 * Constants.TerrainPatchSize + k] = C16_4R * xr - C16_4I * xi; // | ||
705 | ftmp = C16_4R * xr - C16_4I * xi; | ||
706 | indx = 4 * Constants.TerrainPatchSize + k; | ||
707 | itmp = (int)(ftmp * QuantizeTable16[indx]); | ||
708 | iout[CopyMatrix16[indx]] = itmp; | ||
582 | 709 | ||
583 | if (dowbits) | 710 | if (dowbits) |
584 | { | 711 | { |
585 | if (tmp < 0) tmp *= -1; | 712 | if (itmp < 0) itmp *= -1; |
586 | while (tmp > wbitsMaxValue) | 713 | while (itmp > wbitsMaxValue) |
587 | { | 714 | { |
588 | wbits++; | 715 | wbits++; |
589 | wbitsMaxValue = 1 << wbits; | 716 | wbitsMaxValue = 1 << wbits; |
@@ -594,355 +721,605 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
594 | } | 721 | } |
595 | } | 722 | } |
596 | } | 723 | } |
597 | } | ||
598 | return wbits; | ||
599 | } | ||
600 | 724 | ||
601 | public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size) | 725 | //tmp[12 * Constants.TerrainPatchSize + k] = C16_4R * xi + C16_4I * xr; // |
602 | { | 726 | ftmp = C16_4R * xi + C16_4I * xr; |
603 | for (int n = 0; n < size*size; n++) | 727 | indx = 12 * Constants.TerrainPatchSize + k; |
604 | { | 728 | itmp = (int)(ftmp * QuantizeTable16[indx]); |
605 | // ? | 729 | iout[CopyMatrix16[indx]] = itmp; |
606 | int temp = bitpack.UnpackBits(1); | 730 | |
607 | if (temp != 0) | 731 | if (dowbits) |
608 | { | 732 | { |
609 | // Value or EOB | 733 | if (itmp < 0) itmp *= -1; |
610 | temp = bitpack.UnpackBits(1); | 734 | while (itmp > wbitsMaxValue) |
611 | if (temp != 0) | ||
612 | { | 735 | { |
613 | // Value | 736 | wbits++; |
614 | temp = bitpack.UnpackBits(1); | 737 | wbitsMaxValue = 1 << wbits; |
615 | if (temp != 0) | 738 | if (wbits == maxwbits) |
616 | { | ||
617 | // Negative | ||
618 | temp = bitpack.UnpackBits((int) header.WordBits); | ||
619 | patches[n] = temp*-1; | ||
620 | } | ||
621 | else | ||
622 | { | 739 | { |
623 | // Positive | 740 | dowbits = false; |
624 | temp = bitpack.UnpackBits((int) header.WordBits); | 741 | break; |
625 | patches[n] = temp; | ||
626 | } | 742 | } |
627 | } | 743 | } |
628 | else | 744 | } |
745 | |||
746 | x0r = W16_8R * (x1i - x3i); | ||
747 | x2r = W16_8R * (x1i + x3i); | ||
748 | xr = x0i + x0r; | ||
749 | xi = x2r + x2i; | ||
750 | |||
751 | //tmp[2 * Constants.TerrainPatchSize + k] = C16_2R * xr - C16_2I * xi; // | ||
752 | ftmp = C16_2R * xr - C16_2I * xi; | ||
753 | indx = 2 * Constants.TerrainPatchSize + k; | ||
754 | itmp = (int)(ftmp * QuantizeTable16[indx]); | ||
755 | iout[CopyMatrix16[indx]] = itmp; | ||
756 | |||
757 | if (dowbits) | ||
758 | { | ||
759 | if (itmp < 0) itmp *= -1; | ||
760 | while (itmp > wbitsMaxValue) | ||
629 | { | 761 | { |
630 | // Set the rest to zero | 762 | wbits++; |
631 | // TODO: This might not be necessary | 763 | wbitsMaxValue = 1 << wbits; |
632 | for (int o = n; o < size*size; o++) | 764 | if (wbits == maxwbits) |
633 | { | 765 | { |
634 | patches[o] = 0; | 766 | dowbits = false; |
767 | break; | ||
635 | } | 768 | } |
636 | break; | ||
637 | } | 769 | } |
638 | } | 770 | } |
639 | else | ||
640 | { | ||
641 | patches[n] = 0; | ||
642 | } | ||
643 | } | ||
644 | } | ||
645 | 771 | ||
646 | private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits) | 772 | //tmp[14 * Constants.TerrainPatchSize + k] = C16_2R * xi + C16_2I * xr; // |
647 | { | 773 | ftmp = C16_2R * xi + C16_2I * xr; |
648 | int maxwbitssize = (1 << wbits) - 1; | 774 | indx = 14 * Constants.TerrainPatchSize + k; |
775 | itmp = (int)(ftmp * QuantizeTable16[indx]); | ||
776 | iout[CopyMatrix16[indx]] = itmp; | ||
649 | 777 | ||
650 | if (postquant > Constants.TerrainPatchSize*Constants.TerrainPatchSize || postquant < 0) | 778 | if (dowbits) |
651 | { | 779 | { |
652 | Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error); | 780 | if (itmp < 0) itmp *= -1; |
653 | return; | 781 | while (itmp > wbitsMaxValue) |
654 | } | 782 | { |
783 | wbits++; | ||
784 | wbitsMaxValue = 1 << wbits; | ||
785 | if (wbits == maxwbits) | ||
786 | { | ||
787 | dowbits = false; | ||
788 | break; | ||
789 | } | ||
790 | } | ||
791 | } | ||
655 | 792 | ||
656 | if (postquant != 0) patch[Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant] = 0; | 793 | xr = x0i - x0r; |
794 | xi = x2r - x2i; | ||
657 | 795 | ||
658 | for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++) | 796 | //tmp[6 * Constants.TerrainPatchSize + k] = C16_6R * xr - C16_6I * xi; // |
659 | { | 797 | ftmp = C16_6R * xr - C16_6I * xi; |
660 | int temp = patch[i]; | 798 | indx = 6 * Constants.TerrainPatchSize + k; |
799 | itmp = (int)(ftmp * QuantizeTable16[indx]); | ||
800 | iout[CopyMatrix16[indx]] = itmp; | ||
661 | 801 | ||
662 | if (temp == 0) | 802 | if (dowbits) |
663 | { | 803 | { |
664 | bool eob = true; | 804 | if (itmp < 0) itmp *= -1; |
665 | 805 | while (itmp > wbitsMaxValue) | |
666 | for (int j = i; j < Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant; j++) | ||
667 | { | 806 | { |
668 | if (patch[j] != 0) | 807 | wbits++; |
808 | wbitsMaxValue = 1 << wbits; | ||
809 | if (wbits == maxwbits) | ||
669 | { | 810 | { |
670 | eob = false; | 811 | dowbits = false; |
671 | break; | 812 | break; |
672 | } | 813 | } |
673 | } | 814 | } |
815 | } | ||
674 | 816 | ||
675 | if (eob) | 817 | //tmp[10 * Constants.TerrainPatchSize + k] = C16_6R * xi + C16_6I * xr; // |
818 | ftmp = C16_6R * xi + C16_6I * xr; | ||
819 | indx = 10 * Constants.TerrainPatchSize + k; | ||
820 | itmp = (int)(ftmp * QuantizeTable16[indx]); | ||
821 | iout[CopyMatrix16[indx]] = itmp; | ||
822 | |||
823 | if (dowbits) | ||
824 | { | ||
825 | if (itmp < 0) itmp *= -1; | ||
826 | while (itmp > wbitsMaxValue) | ||
676 | { | 827 | { |
677 | output.PackBits(ZERO_EOB, 2); | 828 | wbits++; |
678 | return; | 829 | wbitsMaxValue = 1 << wbits; |
830 | if (wbits == maxwbits) | ||
831 | { | ||
832 | dowbits = false; | ||
833 | break; | ||
834 | } | ||
679 | } | 835 | } |
680 | output.PackBits(ZERO_CODE, 1); | ||
681 | } | 836 | } |
682 | else | ||
683 | { | ||
684 | if (temp < 0) | ||
685 | { | ||
686 | temp *= -1; | ||
687 | 837 | ||
688 | if (temp > maxwbitssize) temp = maxwbitssize; | 838 | xr = W16_8R * (x6r - x6i); |
839 | xi = W16_8R * (x6i + x6r); | ||
840 | x6r = x4r - xr; | ||
841 | x6i = x4i - xi; | ||
842 | x4r += xr; | ||
843 | x4i += xi; | ||
844 | xr = W16_4I * x7r - W16_4R * x7i; | ||
845 | xi = W16_4I * x7i + W16_4R * x7r; | ||
846 | x7r = W16_4R * x5r - W16_4I * x5i; | ||
847 | x7i = W16_4R * x5i + W16_4I * x5r; | ||
848 | x5r = x7r + xr; | ||
849 | x5i = x7i + xi; | ||
850 | x7r -= xr; | ||
851 | x7i -= xi; | ||
852 | xr = x4r + x5r; | ||
853 | xi = x5i + x4i; | ||
854 | |||
855 | //tmp[1 * Constants.TerrainPatchSize + k] = C16_1R * xr - C16_1I * xi; // | ||
856 | ftmp = C16_1R * xr - C16_1I * xi; | ||
857 | indx = Constants.TerrainPatchSize + k; | ||
858 | itmp = (int)(ftmp * QuantizeTable16[indx]); | ||
859 | iout[CopyMatrix16[indx]] = itmp; | ||
689 | 860 | ||
690 | output.PackBits(NEGATIVE_VALUE, 3); | 861 | if (dowbits) |
691 | output.PackBits(temp, wbits); | 862 | { |
692 | } | 863 | if (itmp < 0) itmp *= -1; |
693 | else | 864 | while (itmp > wbitsMaxValue) |
694 | { | 865 | { |
695 | if (temp > maxwbitssize) temp = maxwbitssize; | 866 | wbits++; |
696 | 867 | wbitsMaxValue = 1 << wbits; | |
697 | output.PackBits(POSITIVE_VALUE, 3); | 868 | if (wbits == maxwbits) |
698 | output.PackBits(temp, wbits); | 869 | { |
870 | dowbits = false; | ||
871 | break; | ||
872 | } | ||
699 | } | 873 | } |
700 | } | 874 | } |
701 | } | ||
702 | } | ||
703 | 875 | ||
704 | public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group) | 876 | //tmp[15 * Constants.TerrainPatchSize + k] = C16_1R * xi + C16_1I * xr; // |
705 | { | 877 | ftmp = C16_1R * xi + C16_1I * xr; |
706 | float[] block = new float[group.PatchSize*group.PatchSize]; | 878 | indx = 15 * Constants.TerrainPatchSize + k; |
707 | float[] output = new float[group.PatchSize*group.PatchSize]; | 879 | itmp = (int)(ftmp * QuantizeTable16[indx]); |
708 | int prequant = (header.QuantWBits >> 4) + 2; | 880 | iout[CopyMatrix16[indx]] = itmp; |
709 | int quantize = 1 << prequant; | 881 | |
710 | float ooq = 1.0f/quantize; | 882 | if (dowbits) |
711 | float mult = ooq*header.Range; | ||
712 | float addval = mult*(1 << (prequant - 1)) + header.DCOffset; | ||
713 | |||
714 | if (group.PatchSize == Constants.TerrainPatchSize) | ||
715 | { | ||
716 | for (int n = 0; n < Constants.TerrainPatchSize*Constants.TerrainPatchSize; n++) | ||
717 | { | 883 | { |
718 | block[n] = patches[CopyMatrix16[n]]*DequantizeTable16[n]; | 884 | if (itmp < 0) itmp *= -1; |
885 | while (itmp > wbitsMaxValue) | ||
886 | { | ||
887 | wbits++; | ||
888 | wbitsMaxValue = 1 << wbits; | ||
889 | if (wbits == maxwbits) | ||
890 | { | ||
891 | dowbits = false; | ||
892 | break; | ||
893 | } | ||
894 | } | ||
719 | } | 895 | } |
720 | 896 | ||
721 | float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | 897 | xr = x4r - x5r; |
898 | xi = x5i - x4i; | ||
722 | 899 | ||
723 | for (int o = 0; o < Constants.TerrainPatchSize; o++) | 900 | //tmp[7 * Constants.TerrainPatchSize + k] = C16_7R * xr - C16_7I * xi; // |
724 | IDCTColumn16(block, ftemp, o); | 901 | ftmp = C16_7R * xr - C16_7I * xi; |
725 | for (int o = 0; o < Constants.TerrainPatchSize; o++) | 902 | indx = 7 * Constants.TerrainPatchSize + k; |
726 | IDCTLine16(ftemp, block, o); | 903 | itmp = (int)(ftmp * QuantizeTable16[indx]); |
727 | } | 904 | iout[CopyMatrix16[indx]] = itmp; |
728 | else | 905 | |
729 | { | 906 | if (dowbits) |
730 | for (int n = 0; n < Constants.TerrainPatchSize*2*Constants.TerrainPatchSize*2; n++) | ||
731 | { | 907 | { |
732 | block[n] = patches[CopyMatrix32[n]]*DequantizeTable32[n]; | 908 | if (itmp < 0) itmp *= -1; |
909 | while (itmp > wbitsMaxValue) | ||
910 | { | ||
911 | wbits++; | ||
912 | wbitsMaxValue = 1 << wbits; | ||
913 | if (wbits == maxwbits) | ||
914 | { | ||
915 | dowbits = false; | ||
916 | break; | ||
917 | } | ||
918 | } | ||
733 | } | 919 | } |
734 | 920 | ||
735 | Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error); | 921 | //tmp[9 * Constants.TerrainPatchSize + k] = C16_7R * xi + C16_7I * xr; // |
736 | } | 922 | ftmp = C16_7R * xi + C16_7I * xr; |
737 | 923 | indx = 9 * Constants.TerrainPatchSize + k; | |
738 | for (int j = 0; j < block.Length; j++) | 924 | itmp = (int)(ftmp * QuantizeTable16[indx]); |
739 | { | 925 | iout[CopyMatrix16[indx]] = itmp; |
740 | output[j] = block[j]*mult + addval; | ||
741 | } | ||
742 | |||
743 | return output; | ||
744 | } | ||
745 | 926 | ||
746 | private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits) | 927 | if (dowbits) |
747 | { | 928 | { |
748 | float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | 929 | if (itmp < 0) itmp *= -1; |
749 | int wordsize = (prequant - 2) & 0x0f; | 930 | while (itmp > wbitsMaxValue) |
750 | float oozrange = 1.0f/header.Range; | 931 | { |
751 | float range = (1 << prequant); | 932 | wbits++; |
752 | float premult = oozrange*range; | 933 | wbitsMaxValue = 1 << wbits; |
753 | float sub = (1 << (prequant - 1)) + header.DCOffset*premult; | 934 | if (wbits == maxwbits) |
935 | { | ||
936 | dowbits = false; | ||
937 | break; | ||
938 | } | ||
939 | } | ||
940 | } | ||
754 | 941 | ||
755 | header.QuantWBits = wordsize; | 942 | xr = x6r - x7i; |
756 | header.QuantWBits |= wordsize << 4; | 943 | xi = x7r + x6i; |
757 | 944 | ||
758 | int k = 0; | 945 | //tmp[5 * Constants.TerrainPatchSize + k] = C16_5R * xr - C16_5I * xi; // |
759 | for (int j = 0; j < Constants.TerrainPatchSize; j++) | 946 | ftmp = C16_5R * xr - C16_5I * xi; |
760 | { | 947 | indx = 5 * Constants.TerrainPatchSize + k; |
761 | for (int i = 0; i < Constants.TerrainPatchSize; i++) | 948 | itmp = (int)(ftmp * QuantizeTable16[indx]); |
762 | block[k++] = patchData[j*Constants.TerrainPatchSize + i]*premult - sub; | 949 | iout[CopyMatrix16[indx]] = itmp; |
763 | } | ||
764 | 950 | ||
765 | float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | 951 | if (dowbits) |
766 | int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | 952 | { |
953 | if (itmp < 0) itmp *= -1; | ||
954 | while (itmp > wbitsMaxValue) | ||
955 | { | ||
956 | wbits++; | ||
957 | wbitsMaxValue = 1 << wbits; | ||
958 | if (wbits == maxwbits) | ||
959 | { | ||
960 | dowbits = false; | ||
961 | break; | ||
962 | } | ||
963 | } | ||
964 | } | ||
767 | 965 | ||
966 | //tmp[11 * Constants.TerrainPatchSize + k] = C16_5R * xi + C16_5I * xr; // | ||
967 | ftmp = C16_5R * xi + C16_5I * xr; | ||
968 | indx = 11 * Constants.TerrainPatchSize + k; | ||
969 | itmp = (int)(ftmp * QuantizeTable16[indx]); | ||
970 | iout[CopyMatrix16[indx]] = itmp; | ||
768 | 971 | ||
769 | int maxWbits = prequant + 5; | 972 | if (dowbits) |
770 | wbits = (prequant >> 1); | 973 | { |
974 | if (itmp < 0) itmp *= -1; | ||
975 | while (itmp > wbitsMaxValue) | ||
976 | { | ||
977 | wbits++; | ||
978 | wbitsMaxValue = 1 << wbits; | ||
979 | if (wbits == maxwbits) | ||
980 | { | ||
981 | dowbits = false; | ||
982 | break; | ||
983 | } | ||
984 | } | ||
985 | } | ||
771 | 986 | ||
772 | for (int o = 0; o < Constants.TerrainPatchSize; o++) | 987 | xr = x6r + x7i; |
773 | DCTLine16(block, ftemp, o); | 988 | xi = x7r - x6i; |
774 | for (int o = 0; o < Constants.TerrainPatchSize; o++) | ||
775 | wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits); | ||
776 | 989 | ||
777 | return itemp; | 990 | //tmp[3 * Constants.TerrainPatchSize + k] = C16_3R * xr - C16_3I * xi; // |
778 | } | 991 | ftmp = C16_3R * xr - C16_3I * xi; |
992 | indx = 3 * Constants.TerrainPatchSize + k; | ||
993 | itmp = (int)(ftmp * QuantizeTable16[indx]); | ||
994 | iout[CopyMatrix16[indx]] = itmp; | ||
779 | 995 | ||
780 | private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant, out int wbits) | 996 | if (dowbits) |
781 | { | 997 | { |
782 | float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | 998 | if (itmp < 0) itmp *= -1; |
783 | float oozrange = 1.0f/header.Range; | 999 | while (itmp > wbitsMaxValue) |
784 | float range = (1 << prequant); | 1000 | { |
785 | float premult = oozrange*range; | 1001 | wbits++; |
786 | float sub = (1 << (prequant - 1)) + header.DCOffset*premult; | 1002 | wbitsMaxValue = 1 << wbits; |
787 | int wordsize = (prequant - 2) & 0x0f; | 1003 | if (wbits == maxwbits) |
1004 | { | ||
1005 | dowbits = false; | ||
1006 | break; | ||
1007 | } | ||
1008 | } | ||
1009 | } | ||
788 | 1010 | ||
789 | header.QuantWBits = wordsize; | 1011 | //tmp[13 * Constants.TerrainPatchSize + k] = C16_3R * xi + C16_3I * xr; // |
790 | header.QuantWBits |= wordsize << 4; | 1012 | ftmp = C16_3R * xi + C16_3I * xr; |
1013 | indx = 13 * Constants.TerrainPatchSize + k; | ||
1014 | itmp = (int)(ftmp * QuantizeTable16[indx]); | ||
1015 | iout[CopyMatrix16[indx]] = itmp; | ||
791 | 1016 | ||
792 | int k = 0; | 1017 | if (dowbits) |
793 | for (int j = 0; j < Constants.TerrainPatchSize; j++) | 1018 | { |
794 | { | 1019 | if (itmp < 0) itmp *= -1; |
795 | for (int i = 0; i < Constants.TerrainPatchSize; i++) | 1020 | while (itmp > wbitsMaxValue) |
796 | block[k++] = patchData[j, i]*premult - sub; | 1021 | { |
1022 | wbits++; | ||
1023 | wbitsMaxValue = 1 << wbits; | ||
1024 | if (wbits == maxwbits) | ||
1025 | { | ||
1026 | dowbits = false; | ||
1027 | break; | ||
1028 | } | ||
1029 | } | ||
1030 | } | ||
797 | } | 1031 | } |
1032 | } | ||
798 | 1033 | ||
799 | float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | 1034 | #endregion DCT |
800 | int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | ||
801 | |||
802 | int maxWbits = prequant + 5; | ||
803 | wbits = (prequant >> 1); | ||
804 | 1035 | ||
805 | for (int o = 0; o < Constants.TerrainPatchSize; o++) | 1036 | #region Decode |
806 | DCTLine16(block, ftemp, o); | 1037 | /* |
807 | for (int o = 0; o < Constants.TerrainPatchSize; o++) | 1038 | public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack) |
808 | wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits); | 1039 | { |
1040 | TerrainPatch.Header header = new TerrainPatch.Header { QuantWBits = bitpack.UnpackBits(8) }; | ||
809 | 1041 | ||
810 | return itemp; | 1042 | // Quantized word bits |
811 | } | 1043 | if (header.QuantWBits == END_OF_PATCHES) |
1044 | return header; | ||
812 | 1045 | ||
813 | private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header, | 1046 | // DC offset |
814 | int prequant, out int wbits) | 1047 | header.DCOffset = bitpack.UnpackFloat(); |
815 | { | ||
816 | float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | ||
817 | int wordsize = prequant; | ||
818 | float oozrange = 1.0f/header.Range; | ||
819 | float range = (1 << prequant); | ||
820 | float premult = oozrange*range; | ||
821 | float sub = (1 << (prequant - 1)) + header.DCOffset*premult; | ||
822 | 1048 | ||
823 | header.QuantWBits = wordsize - 2; | 1049 | // Range |
824 | header.QuantWBits |= (prequant - 2) << 4; | 1050 | header.Range = bitpack.UnpackBits(16); |
825 | 1051 | ||
826 | int k = 0; | 1052 | // Patch IDs (10 bits) |
1053 | header.PatchIDs = bitpack.UnpackBits(10); | ||
827 | 1054 | ||
828 | int yPatchLimit = patchY >= (terrData.SizeY / Constants.TerrainPatchSize) ? | 1055 | // Word bits |
829 | (terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchY; | 1056 | header.WordBits = (uint)((header.QuantWBits & 0x0f) + 2); |
830 | yPatchLimit = (yPatchLimit + 1) * Constants.TerrainPatchSize; | ||
831 | 1057 | ||
832 | int xPatchLimit = patchX >= (terrData.SizeX / Constants.TerrainPatchSize) ? | 1058 | return header; |
833 | (terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchX; | 1059 | } |
834 | xPatchLimit = (xPatchLimit + 1) * Constants.TerrainPatchSize; | 1060 | */ |
835 | 1061 | ||
836 | for (int yy = patchY * Constants.TerrainPatchSize; yy < yPatchLimit; yy++) | 1062 | /* |
837 | { | 1063 | public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size) |
838 | for (int xx = patchX * Constants.TerrainPatchSize; xx < xPatchLimit; xx++) | ||
839 | { | 1064 | { |
840 | block[k++] = terrData[xx, yy] * premult - sub; | 1065 | for (int n = 0; n < size * size; n++) |
1066 | { | ||
1067 | // ? | ||
1068 | int temp = bitpack.UnpackBits(1); | ||
1069 | if (temp != 0) | ||
1070 | { | ||
1071 | // Value or EOB | ||
1072 | temp = bitpack.UnpackBits(1); | ||
1073 | if (temp != 0) | ||
1074 | { | ||
1075 | // Value | ||
1076 | temp = bitpack.UnpackBits(1); | ||
1077 | if (temp != 0) | ||
1078 | { | ||
1079 | // Negative | ||
1080 | temp = bitpack.UnpackBits((int)header.WordBits); | ||
1081 | patches[n] = temp * -1; | ||
1082 | } | ||
1083 | else | ||
1084 | { | ||
1085 | // Positive | ||
1086 | temp = bitpack.UnpackBits((int)header.WordBits); | ||
1087 | patches[n] = temp; | ||
1088 | } | ||
1089 | } | ||
1090 | else | ||
1091 | { | ||
1092 | // Set the rest to zero | ||
1093 | // TODO: This might not be necessary | ||
1094 | for (int o = n; o < size * size; o++) | ||
1095 | { | ||
1096 | patches[o] = 0; | ||
1097 | } | ||
1098 | break; | ||
1099 | } | ||
1100 | } | ||
1101 | else | ||
1102 | { | ||
1103 | patches[n] = 0; | ||
1104 | } | ||
1105 | } | ||
841 | } | 1106 | } |
842 | } | 1107 | */ |
843 | 1108 | #region IDCT | |
844 | float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | 1109 | /* not in use |
845 | int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; | 1110 | private static void IDCTColumn16(float[] linein, float[] lineout, int column) |
846 | |||
847 | int maxWbits = prequant + 5; | ||
848 | wbits = (prequant >> 1); | ||
849 | |||
850 | for (int o = 0; o < Constants.TerrainPatchSize; o++) | ||
851 | DCTLine16(block, ftemp, o); | ||
852 | for (int o = 0; o < Constants.TerrainPatchSize; o++) | ||
853 | wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits); | ||
854 | |||
855 | return itemp; | ||
856 | } | ||
857 | |||
858 | #region Initialization | ||
859 | |||
860 | private static void BuildDequantizeTable16() | ||
861 | { | 1111 | { |
862 | for (int j = 0; j < Constants.TerrainPatchSize; j++) | 1112 | for (int n = 0; n < Constants.TerrainPatchSize; n++) |
863 | { | 1113 | { |
864 | for (int i = 0; i < Constants.TerrainPatchSize; i++) | 1114 | float total = OO_SQRT2 * linein[column]; |
1115 | |||
1116 | for (int u = 1; u < Constants.TerrainPatchSize; u++) | ||
865 | { | 1117 | { |
866 | DequantizeTable16[j*Constants.TerrainPatchSize + i] = 1.0f + 2.0f*(i + j); | 1118 | int usize = u * Constants.TerrainPatchSize; |
1119 | total += linein[usize + column] * CosineTable16[usize + n]; | ||
867 | } | 1120 | } |
1121 | |||
1122 | lineout[Constants.TerrainPatchSize * n + column] = total; | ||
868 | } | 1123 | } |
869 | } | 1124 | } |
870 | 1125 | ||
871 | private static void BuildQuantizeTable16() | 1126 | private static void IDCTLine16(float[] linein, float[] lineout, int line) |
872 | { | 1127 | { |
873 | const float oosob = 2.0f/Constants.TerrainPatchSize; | 1128 | const float oosob = 2.0f / Constants.TerrainPatchSize; |
874 | for (int j = 0; j < Constants.TerrainPatchSize; j++) | 1129 | int lineSize = line * Constants.TerrainPatchSize; |
1130 | |||
1131 | for (int n = 0; n < Constants.TerrainPatchSize; n++) | ||
875 | { | 1132 | { |
876 | for (int i = 0; i < Constants.TerrainPatchSize; i++) | 1133 | float total = OO_SQRT2 * linein[lineSize]; |
1134 | |||
1135 | for (int u = 1; u < Constants.TerrainPatchSize; u++) | ||
877 | { | 1136 | { |
878 | // QuantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j)); | 1137 | total += linein[lineSize + u] * CosineTable16[u * Constants.TerrainPatchSize + n]; |
879 | QuantizeTable16[j*Constants.TerrainPatchSize + i] = oosob/(1.0f + 2.0f*(i + (float) j)); | ||
880 | } | 1138 | } |
1139 | |||
1140 | lineout[lineSize + n] = total * oosob; | ||
881 | } | 1141 | } |
882 | } | 1142 | } |
883 | 1143 | ||
1144 | /* | ||
884 | private static void SetupCosines16() | 1145 | private static void SetupCosines16() |
885 | { | 1146 | { |
886 | const float hposz = (float) Math.PI*0.5f/Constants.TerrainPatchSize; | 1147 | const float hposz = (float)Math.PI * 0.5f / Constants.TerrainPatchSize; |
887 | 1148 | ||
888 | for (int u = 0; u < Constants.TerrainPatchSize; u++) | 1149 | for (int u = 0; u < Constants.TerrainPatchSize; u++) |
889 | { | 1150 | { |
890 | for (int n = 0; n < Constants.TerrainPatchSize; n++) | 1151 | for (int n = 0; n < Constants.TerrainPatchSize; n++) |
891 | { | 1152 | { |
892 | CosineTable16[u*Constants.TerrainPatchSize + n] = (float) Math.Cos((2.0f*n + 1.0f)*u*hposz); | 1153 | CosineTable16[u * Constants.TerrainPatchSize + n] = (float)Math.Cos((2.0f * n + 1.0f) * u * hposz); |
893 | } | 1154 | } |
894 | } | 1155 | } |
895 | } | 1156 | } |
1157 | */ | ||
1158 | //not in use, and still not fixed | ||
1159 | /* | ||
1160 | static void idct16x16(float[] a) | ||
1161 | { | ||
1162 | int j; | ||
1163 | float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; | ||
1164 | float x4r, x4i, x5r, x5i, x6r, x6i, x7r, x7i; | ||
1165 | float xr, xi; | ||
896 | 1166 | ||
897 | private static void BuildCopyMatrix16() | 1167 | int fullSize = Constants.TerrainPatchSize * Constants.TerrainPatchSize; |
898 | { | ||
899 | bool diag = false; | ||
900 | bool right = true; | ||
901 | int i = 0; | ||
902 | int j = 0; | ||
903 | int count = 0; | ||
904 | |||
905 | while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize) | ||
906 | { | ||
907 | CopyMatrix16[j*Constants.TerrainPatchSize + i] = count++; | ||
908 | |||
909 | if (!diag) | ||
910 | { | ||
911 | if (right) | ||
912 | { | ||
913 | if (i < Constants.TerrainPatchSize - 1) i++; | ||
914 | else j++; | ||
915 | |||
916 | right = false; | ||
917 | diag = true; | ||
918 | } | ||
919 | else | ||
920 | { | ||
921 | if (j < Constants.TerrainPatchSize - 1) j++; | ||
922 | else i++; | ||
923 | 1168 | ||
924 | right = true; | 1169 | for (j = 0; j < fullSize; j += Constants.TerrainPatchSize) |
925 | diag = true; | 1170 | { |
926 | } | 1171 | x5r = C16_1R * tmp[1 + j] + C16_1I * tmp[15 + j]; |
927 | } | 1172 | x5i = C16_1R * tmp[15 + j] - C16_1I * tmp[1 + j]; |
928 | else | 1173 | xr = C16_7R * tmp[7 + j] + C16_7I * tmp[9 + j]; |
929 | { | 1174 | xi = C16_7R * tmp[9 + j] - C16_7I * tmp[7 + j]; |
930 | if (right) | 1175 | x4r = x5r + xr; |
931 | { | 1176 | x4i = x5i - xi; |
932 | i++; | 1177 | x5r -= xr; |
933 | j--; | 1178 | x5i += xi; |
934 | if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false; | 1179 | x7r = C16_5R * tmp[5 + j] + C16_5I * tmp[11 + j]; |
935 | } | 1180 | x7i = C16_5R * tmp[11 + j] - C16_5I * tmp[5 + j]; |
936 | else | 1181 | xr = C16_3R * tmp[3 + j] + C16_3I * tmp[13 + j]; |
937 | { | 1182 | xi = C16_3R * tmp[13 + j] - C16_3I * tmp[3 + j]; |
938 | i--; | 1183 | x6r = x7r + xr; |
939 | j++; | 1184 | x6i = x7i - xi; |
940 | if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false; | 1185 | x7r -= xr; |
941 | } | 1186 | x7i += xi; |
942 | } | 1187 | xr = x4r - x6r; |
943 | } | 1188 | xi = x4i - x6i; |
944 | } | 1189 | x4r += x6r; |
945 | 1190 | x4i += x6i; | |
946 | #endregion Initialization | 1191 | x6r = W16_8R * (xi + xr); |
1192 | x6i = W16_8R * (xi - xr); | ||
1193 | xr = x5r + x7i; | ||
1194 | xi = x5i - x7r; | ||
1195 | x5r -= x7i; | ||
1196 | x5i += x7r; | ||
1197 | x7r = W16_4I * x5r + W16_4R * x5i; | ||
1198 | x7i = W16_4I * x5i - W16_4R * x5r; | ||
1199 | x5r = W16_4R * xr + W16_4I * xi; | ||
1200 | x5i = W16_4R * xi - W16_4I * xr; | ||
1201 | xr = C16_4R * tmp[4 + j] + C16_4I * tmp[12 + j]; | ||
1202 | xi = C16_4R * tmp[12 + j] - C16_4I * tmp[4 + j]; | ||
1203 | x2r = C16_8R * (tmp[0 + j] + tmp[8 + j]); | ||
1204 | x3r = C16_8R * (tmp[0 + j] - tmp[8 + j]); | ||
1205 | x0r = x2r + xr; | ||
1206 | x1r = x3r + xi; | ||
1207 | x2r -= xr; | ||
1208 | x3r -= xi; | ||
1209 | x0i = C16_2R * tmp[2 + j] + C16_2I * tmp[14 + j]; | ||
1210 | x2i = C16_2R * tmp[14 + j] - C16_2I * tmp[2 + j]; | ||
1211 | x1i = C16_6R * tmp[6 + j] + C16_6I * tmp[10 + j]; | ||
1212 | x3i = C16_6R * tmp[10 + j] - C16_6I * tmp[6 + j]; | ||
1213 | xr = x0i - x1i; | ||
1214 | xi = x2i + x3i; | ||
1215 | x0i += x1i; | ||
1216 | x2i -= x3i; | ||
1217 | x1i = W16_8R * (xi + xr); | ||
1218 | x3i = W16_8R * (xi - xr); | ||
1219 | xr = x0r + x0i; | ||
1220 | xi = x0r - x0i; | ||
1221 | tmp[0 + j] = xr + x4r; | ||
1222 | tmp[15 + j] = xr - x4r; | ||
1223 | tmp[8 + j] = xi + x4i; | ||
1224 | tmp[7 + j] = xi - x4i; | ||
1225 | xr = x1r + x1i; | ||
1226 | xi = x1r - x1i; | ||
1227 | tmp[2 + j] = xr + x5r; | ||
1228 | tmp[13 + j] = xr - x5r; | ||
1229 | tmp[10 + j] = xi + x5i; | ||
1230 | tmp[5 + j] = xi - x5i; | ||
1231 | xr = x2r + x2i; | ||
1232 | xi = x2r - x2i; | ||
1233 | tmp[4 + j] = xr + x6r; | ||
1234 | tmp[11 + j] = xr - x6r; | ||
1235 | tmp[12 + j] = xi + x6i; | ||
1236 | tmp[3 + j] = xi - x6i; | ||
1237 | xr = x3r + x3i; | ||
1238 | xi = x3r - x3i; | ||
1239 | tmp[6 + j] = xr + x7r; | ||
1240 | tmp[9 + j] = xr - x7r; | ||
1241 | tmp[14 + j] = xi + x7i; | ||
1242 | tmp[1 + j] = xi - x7i; | ||
1243 | } | ||
1244 | for (j = 0; j < fullSize; j += Constants.TerrainPatchSize) | ||
1245 | { | ||
1246 | x5r = C16_1R * tmp[j + 1] + C16_1I * tmp[j + 15]; | ||
1247 | x5i = C16_1R * tmp[j + 15] - C16_1I * tmp[j + 1]; | ||
1248 | xr = C16_7R * tmp[j + 7] + C16_7I * tmp[j + 9]; | ||
1249 | xi = C16_7R * tmp[j + 9] - C16_7I * tmp[j + 7]; | ||
1250 | x4r = x5r + xr; | ||
1251 | x4i = x5i - xi; | ||
1252 | x5r -= xr; | ||
1253 | x5i += xi; | ||
1254 | x7r = C16_5R * tmp[j + 5] + C16_5I * tmp[j + 11]; | ||
1255 | x7i = C16_5R * tmp[j + 11] - C16_5I * tmp[j + 5]; | ||
1256 | xr = C16_3R * tmp[j + 3] + C16_3I * tmp[j + 13]; | ||
1257 | xi = C16_3R * tmp[j + 13] - C16_3I * tmp[j + 3]; | ||
1258 | x6r = x7r + xr; | ||
1259 | x6i = x7i - xi; | ||
1260 | x7r -= xr; | ||
1261 | x7i += xi; | ||
1262 | xr = x4r - x6r; | ||
1263 | xi = x4i - x6i; | ||
1264 | x4r += x6r; | ||
1265 | x4i += x6i; | ||
1266 | x6r = W16_8R * (xi + xr); | ||
1267 | x6i = W16_8R * (xi - xr); | ||
1268 | xr = x5r + x7i; | ||
1269 | xi = x5i - x7r; | ||
1270 | x5r -= x7i; | ||
1271 | x5i += x7r; | ||
1272 | x7r = W16_4I * x5r + W16_4R * x5i; | ||
1273 | x7i = W16_4I * x5i - W16_4R * x5r; | ||
1274 | x5r = W16_4R * xr + W16_4I * xi; | ||
1275 | x5i = W16_4R * xi - W16_4I * xr; | ||
1276 | xr = C16_4R * tmp[j + 4] + C16_4I * tmp[j + 12]; | ||
1277 | xi = C16_4R * tmp[j + 12] - C16_4I * tmp[j + 4]; | ||
1278 | x2r = C16_8R * (tmp[j + 0] + tmp[j + 8]); | ||
1279 | x3r = C16_8R * (tmp[j + 0] - tmp[j + 8]); | ||
1280 | x0r = x2r + xr; | ||
1281 | x1r = x3r + xi; | ||
1282 | x2r -= xr; | ||
1283 | x3r -= xi; | ||
1284 | x0i = C16_2R * tmp[j + 2] + C16_2I * tmp[j + 14]; | ||
1285 | x2i = C16_2R * tmp[j + 14] - C16_2I * tmp[j + 2]; | ||
1286 | x1i = C16_6R * tmp[j + 6] + C16_6I * tmp[j + 10]; | ||
1287 | x3i = C16_6R * tmp[j + 10] - C16_6I * tmp[j + 6]; | ||
1288 | xr = x0i - x1i; | ||
1289 | xi = x2i + x3i; | ||
1290 | x0i += x1i; | ||
1291 | x2i -= x3i; | ||
1292 | x1i = W16_8R * (xi + xr); | ||
1293 | x3i = W16_8R * (xi - xr); | ||
1294 | xr = x0r + x0i; | ||
1295 | xi = x0r - x0i; | ||
1296 | tmp[j + 0] = xr + x4r; | ||
1297 | tmp[j + 15] = xr - x4r; | ||
1298 | tmp[j + 8] = xi + x4i; | ||
1299 | tmp[j + 7] = xi - x4i; | ||
1300 | xr = x1r + x1i; | ||
1301 | xi = x1r - x1i; | ||
1302 | tmp[j + 2] = xr + x5r; | ||
1303 | tmp[j + 13] = xr - x5r; | ||
1304 | tmp[j + 10] = xi + x5i; | ||
1305 | tmp[j + 5] = xi - x5i; | ||
1306 | xr = x2r + x2i; | ||
1307 | xi = x2r - x2i; | ||
1308 | tmp[j + 4] = xr + x6r; | ||
1309 | tmp[j + 11] = xr - x6r; | ||
1310 | tmp[j + 12] = xi + x6i; | ||
1311 | tmp[j + 3] = xi - x6i; | ||
1312 | xr = x3r + x3i; | ||
1313 | xi = x3r - x3i; | ||
1314 | tmp[j + 6] = xr + x7r; | ||
1315 | tmp[j + 9] = xr - x7r; | ||
1316 | tmp[j + 14] = xi + x7i; | ||
1317 | tmp[j + 1] = xi - x7i; | ||
1318 | } | ||
1319 | } | ||
1320 | */ | ||
1321 | #endregion IDCT | ||
1322 | #endregion Decode | ||
947 | } | 1323 | } |
1324 | |||
948 | } | 1325 | } |