/*
* Copyright 2013 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.world.chunks.deflate;
import org.terasology.world.chunks.blockdata.TeraArray;
import org.terasology.world.chunks.blockdata.TeraSparseArray16Bit;
import org.terasology.world.chunks.blockdata.TeraSparseArray4Bit;
import org.terasology.world.chunks.blockdata.TeraSparseArray8Bit;
/**
* TeraStandardDeflator implements a simple deflation algorithm for 4, 8 and 16-bit dense and sparse arrays.
*
* @author Manuel Brotz <manu.brotz@gmx.ch>
* @note Currently it is optimized for chunks of size 16x256x16 blocks.
* @todo Implement deflation for sparse arrays.
*/
public class TeraStandardDeflator extends TeraVisitingDeflator {
/*
* 16-bit variant
* ==============
*
* dense chunk : 4 + 12 + (65536 * 2) = 131088
* sparse chunk : (4 + 12 + (256 * 2)) + (4 + 12 + (256 × 4)) + ((12 + (256 * 2)) × 256) = 135712
* difference : 135712 - 131088 = 4624
* min. deflate : 4624 / (12 + (256 * 2)) = 8.8
*
*
* 8-bit variant
* =============
*
* dense chunk : 4 + 12 + 65536 = 65552
* sparse chunk : (4 + 12 + 256) + (4 + 12 + (256 × 4)) + ((12 + 256) × 256) = 69920
* difference : 69920 - 65552 = 4368
* min. deflate : 4368 / (12 + 256) = 16.3
*
*
* 4-bit variant
* =============
*
* dense chunk : 4 + 12 + (65536 / 2) = 32784
* sparse chunk : (4 + 12 + 256) + (4 + 12 + (256 × 4)) + ((12 + (256 / 2)) × 256) = 37152
* difference : 37152 - 32784 = 4368
* min. deflate : 4368 / (12 + (256 / 2)) = 31.2
*
*/
// TODO dynamically calculate DEFLATE_MINIMUM_*, they only work for chunks with dimension 16x256x16
protected static final int DEFLATE_MINIMUM_16BIT = 8;
protected static final int DEFLATE_MINIMUM_8BIT = 16;
protected static final int DEFLATE_MINIMUM_4BIT = 31;
public TeraStandardDeflator() {
}
@Override
public TeraArray deflateDenseArray16Bit(short[] data, int rowSize, int sizeX, int sizeY, int sizeZ) {
final short[][] inflated = new short[sizeY][];
final short[] deflated = new short[sizeY];
int packed = 0;
for (int y = 0; y < sizeY; y++) {
final int start = y * rowSize;
final short first = data[start];
boolean packable = true;
for (int i = 1; i < rowSize; i++) {
if (data[start + i] != first) {
packable = false;
break;
}
}
if (packable) {
deflated[y] = first;
++packed;
} else {
short[] tmp = new short[rowSize];
System.arraycopy(data, start, tmp, 0, rowSize);
inflated[y] = tmp;
}
}
if (packed == sizeY) {
final short first = deflated[0];
boolean packable = true;
for (int i = 1; i < sizeY; i++) {
if (deflated[i] != first) {
packable = false;
break;
}
}
if (packable) {
return new TeraSparseArray16Bit(sizeX, sizeY, sizeZ, first);
}
}
if (packed > DEFLATE_MINIMUM_16BIT) {
return new TeraSparseArray16Bit(sizeX, sizeY, sizeZ, inflated, deflated);
}
return null;
}
@Override
public TeraArray deflateDenseArray8Bit(final byte[] data, final int rowSize, final int sizeX, final int sizeY, final int sizeZ) {
final byte[][] inflated = new byte[sizeY][];
final byte[] deflated = new byte[sizeY];
int packed = 0;
for (int y = 0; y < sizeY; y++) {
final int start = y * rowSize;
final byte first = data[start];
boolean packable = true;
for (int i = 1; i < rowSize; i++) {
if (data[start + i] != first) {
packable = false;
break;
}
}
if (packable) {
deflated[y] = first;
++packed;
} else {
byte[] tmp = new byte[rowSize];
System.arraycopy(data, start, tmp, 0, rowSize);
inflated[y] = tmp;
}
}
if (packed == sizeY) {
final byte first = deflated[0];
boolean packable = true;
for (int i = 1; i < sizeY; i++) {
if (deflated[i] != first) {
packable = false;
break;
}
}
if (packable) {
return new TeraSparseArray8Bit(sizeX, sizeY, sizeZ, first);
}
}
if (packed > DEFLATE_MINIMUM_8BIT) {
return new TeraSparseArray8Bit(sizeX, sizeY, sizeZ, inflated, deflated);
}
return null;
}
@Override
public TeraArray deflateDenseArray4Bit(final byte[] data, final int rowSize, final int sizeX, final int sizeY, final int sizeZ) {
final byte[][] inflated = new byte[sizeY][];
final byte[] deflated = new byte[sizeY];
int packed = 0;
for (int y = 0; y < sizeY; y++) {
final int start = y * rowSize;
final byte first = data[start];
boolean packable = true;
for (int i = 1; i < rowSize; i++) {
if (data[start + i] != first) {
packable = false;
break;
}
}
if (packable) {
deflated[y] = first;
++packed;
} else {
byte[] tmp = new byte[rowSize];
System.arraycopy(data, start, tmp, 0, rowSize);
inflated[y] = tmp;
}
}
if (packed == sizeY) {
final byte first = deflated[0];
boolean packable = true;
for (int i = 1; i < sizeY; i++) {
if (deflated[i] != first) {
packable = false;
break;
}
}
if (packable) {
return new TeraSparseArray4Bit(sizeX, sizeY, sizeZ, first);
}
}
if (packed > DEFLATE_MINIMUM_4BIT) {
return new TeraSparseArray4Bit(sizeX, sizeY, sizeZ, inflated, deflated);
}
return null;
}
@Override
public TeraArray deflateSparseArray16Bit(short[][] inflated, short[] deflated, short fill, int rowSize, int sizeX, int sizeY, int sizeZ) {
return null;
}
@Override
public TeraArray deflateSparseArray8Bit(final byte[][] inflated, final byte[] deflated, final byte fill, final int rowSize,
final int sizeX, final int sizeY, final int sizeZ) {
return null;
}
@Override
public TeraArray deflateSparseArray4Bit(final byte[][] inflated, final byte[] deflated, final byte fill, final int rowSize,
final int sizeX, final int sizeY, final int sizeZ) {
return null;
}
}