mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-12-29 12:09:07 +00:00
Parallax 2
This commit is contained in:
125
src/main/java/com/volmit/iris/util/DataPalette.java
Normal file
125
src/main/java/com/volmit/iris/util/DataPalette.java
Normal file
@@ -0,0 +1,125 @@
|
||||
package com.volmit.iris.util;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class DataPalette<T> implements Writable
|
||||
{
|
||||
private static final int DEFAULT_BITS_PER_BLOCK = 4;
|
||||
private static final int CAPACITY = 4096;
|
||||
private int bpb;
|
||||
private NibbleArray data;
|
||||
private KList<T> palette;
|
||||
|
||||
public DataPalette(T defaultValue)
|
||||
{
|
||||
palette = new KList<>();
|
||||
bpb = DEFAULT_BITS_PER_BLOCK;
|
||||
data = new NibbleArray(bpb, CAPACITY);
|
||||
data.setAll(Byte.MIN_VALUE);
|
||||
getPaletteId(defaultValue);
|
||||
}
|
||||
|
||||
public abstract T readType(DataInputStream i) throws IOException;
|
||||
|
||||
public abstract void writeType(T t, DataOutputStream o) throws IOException;
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream o) throws IOException
|
||||
{
|
||||
o.writeByte(bpb + Byte.MIN_VALUE);
|
||||
o.writeByte(palette.size() + Byte.MIN_VALUE);
|
||||
|
||||
for(T i : palette)
|
||||
{
|
||||
writeType(i, o);
|
||||
}
|
||||
|
||||
data.write(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream i) throws IOException
|
||||
{
|
||||
bpb = i.readByte() - Byte.MIN_VALUE;
|
||||
palette = new KList<>();
|
||||
int v = i.readByte() - Byte.MIN_VALUE;
|
||||
|
||||
for(int j = 0; j < v; j++)
|
||||
{
|
||||
palette.add(readType(i));
|
||||
}
|
||||
|
||||
data = new NibbleArray(CAPACITY, i);
|
||||
}
|
||||
|
||||
private final void expand()
|
||||
{
|
||||
if(bpb < 8)
|
||||
{
|
||||
changeBitsPerBlock(bpb + 1);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
throw new IndexOutOfBoundsException("The Data Palette can only handle at most 256 block types per 16x16x16 region. We cannot use more than 8 bits per block!");
|
||||
}
|
||||
}
|
||||
|
||||
public final void optimize()
|
||||
{
|
||||
int targetBits = bpb;
|
||||
int needed = palette.size();
|
||||
|
||||
for(int i = 1; i < bpb; i++)
|
||||
{
|
||||
if(Math.pow(2, i) > needed)
|
||||
{
|
||||
targetBits = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
changeBitsPerBlock(targetBits);
|
||||
}
|
||||
|
||||
private final void changeBitsPerBlock(int bits)
|
||||
{
|
||||
bpb = bits;
|
||||
data = new NibbleArray(bpb, CAPACITY, data);
|
||||
}
|
||||
|
||||
public final void set(int x, int y, int z, T d)
|
||||
{
|
||||
data.set(getCoordinateIndex(x, y, z), getPaletteId(d));
|
||||
}
|
||||
|
||||
public final T get(int x, int y, int z)
|
||||
{
|
||||
return palette.get(data.get(getCoordinateIndex(x, y, z)));
|
||||
}
|
||||
|
||||
private final int getPaletteId(T d)
|
||||
{
|
||||
int index = palette.indexOf(d);
|
||||
|
||||
if(index == -1)
|
||||
{
|
||||
index = palette.size();
|
||||
palette.add(d);
|
||||
|
||||
if(palette.size() > Math.pow(2, bpb))
|
||||
{
|
||||
expand();
|
||||
}
|
||||
}
|
||||
|
||||
return index + Byte.MIN_VALUE;
|
||||
}
|
||||
|
||||
private final int getCoordinateIndex(int x, int y, int z)
|
||||
{
|
||||
return y << 8 | z << 4 | x;
|
||||
}
|
||||
}
|
||||
212
src/main/java/com/volmit/iris/util/NibbleArray.java
Normal file
212
src/main/java/com/volmit/iris/util/NibbleArray.java
Normal file
@@ -0,0 +1,212 @@
|
||||
package com.volmit.iris.util;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
public class NibbleArray implements Writable
|
||||
{
|
||||
private byte[] data;
|
||||
private int depth;
|
||||
private final int size;
|
||||
private byte mask;
|
||||
private final Object lock = new Object();
|
||||
|
||||
public NibbleArray(int capacity, DataInputStream in) throws IOException
|
||||
{
|
||||
size = capacity;
|
||||
read(in);
|
||||
}
|
||||
|
||||
public NibbleArray(int nibbleDepth, int capacity)
|
||||
{
|
||||
if(nibbleDepth > 8 || nibbleDepth < 1)
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
int neededBits = nibbleDepth * capacity;
|
||||
|
||||
size = capacity;
|
||||
depth = nibbleDepth;
|
||||
data = new byte[(neededBits + neededBits % 8) / 8];
|
||||
mask = (byte) maskFor(nibbleDepth);
|
||||
}
|
||||
|
||||
public NibbleArray(int nibbleDepth, int capacity, NibbleArray existing)
|
||||
{
|
||||
if(nibbleDepth > 8 || nibbleDepth < 1)
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
int neededBits = nibbleDepth * capacity;
|
||||
size = capacity;
|
||||
depth = nibbleDepth;
|
||||
data = new byte[(neededBits + neededBits % 8) / 8];
|
||||
mask = (byte) maskFor(nibbleDepth);
|
||||
|
||||
for(int i = 0; i < Math.min(size, existing.size()); i++)
|
||||
{
|
||||
set(i, existing.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream o) throws IOException
|
||||
{
|
||||
o.writeByte(depth + Byte.MIN_VALUE);
|
||||
o.write(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream i) throws IOException
|
||||
{
|
||||
depth = i.readByte() - Byte.MIN_VALUE;
|
||||
int neededBits = depth * size;
|
||||
data = new byte[(neededBits + neededBits % 8) / 8];
|
||||
mask = (byte) maskFor(depth);
|
||||
i.read(data);
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
public byte get(int index)
|
||||
{
|
||||
synchronized(lock)
|
||||
{
|
||||
bitIndex = index * depth;
|
||||
byteIndex = bitIndex >> 3;
|
||||
bitInByte = bitIndex & 7;
|
||||
int value = data[byteIndex] >> bitInByte;
|
||||
|
||||
if(bitInByte + depth > 8)
|
||||
{
|
||||
value |= data[byteIndex + 1] << bitInByte;
|
||||
}
|
||||
|
||||
return (byte) (value & mask);
|
||||
}
|
||||
}
|
||||
|
||||
public byte getAsync(int index)
|
||||
{
|
||||
int bitIndex = index * depth;
|
||||
int byteIndex = bitIndex >> 3;
|
||||
int bitInByte = bitIndex & 7;
|
||||
int value = data[byteIndex] >> bitInByte;
|
||||
|
||||
if(bitInByte + depth > 8)
|
||||
{
|
||||
value |= data[byteIndex + 1] << bitInByte;
|
||||
}
|
||||
|
||||
return (byte) (value & mask);
|
||||
}
|
||||
|
||||
private transient int bitIndex, byteIndex, bitInByte;
|
||||
|
||||
public void set(int index, int nibble)
|
||||
{
|
||||
set(index, (byte) nibble);
|
||||
}
|
||||
|
||||
public void set(int index, byte nybble)
|
||||
{
|
||||
synchronized(lock)
|
||||
{
|
||||
bitIndex = index * depth;
|
||||
byteIndex = bitIndex >> 3;
|
||||
bitInByte = bitIndex & 7;
|
||||
data[byteIndex] = (byte) (((~(data[byteIndex] & (mask << bitInByte)) & data[byteIndex]) | ((nybble & mask) << bitInByte)) & 0xff);
|
||||
|
||||
if(bitInByte + depth > 8)
|
||||
{
|
||||
data[byteIndex + 1] = (byte) (((~(data[byteIndex + 1] & MASKS[bitInByte + depth - 8]) & data[byteIndex + 1]) | ((nybble & mask) >> (8 - bitInByte))) & 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String toBitsString()
|
||||
{
|
||||
return toBitsString(ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
public String toBitsString(ByteOrder byteOrder)
|
||||
{
|
||||
StringJoiner joiner = new StringJoiner(" ");
|
||||
|
||||
for(int i = 0; i < data.length; i++)
|
||||
{
|
||||
joiner.add(binaryString(data[i], byteOrder));
|
||||
}
|
||||
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
Arrays.fill(data, (byte) 0);
|
||||
}
|
||||
|
||||
public void setAll(byte nibble)
|
||||
{
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
set(i, nibble);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAll(int nibble)
|
||||
{
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
set(i, (byte) nibble);
|
||||
}
|
||||
}
|
||||
|
||||
public static int maskFor(int amountOfBits)
|
||||
{
|
||||
return powerOfTwo(amountOfBits) - 1;
|
||||
}
|
||||
|
||||
public static int powerOfTwo(int power)
|
||||
{
|
||||
int result = 1;
|
||||
|
||||
for(int i = 0; i < power; i++)
|
||||
{
|
||||
result *= 2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final int[] MASKS = new int[8];
|
||||
|
||||
static
|
||||
{
|
||||
for(int i = 0; i < MASKS.length; i++)
|
||||
{
|
||||
MASKS[i] = maskFor(i);
|
||||
}
|
||||
}
|
||||
|
||||
public static String binaryString(byte b, ByteOrder byteOrder)
|
||||
{
|
||||
String str = String.format("%8s", Integer.toBinaryString(b & 0xff)).replace(' ', '0');
|
||||
|
||||
return byteOrder.equals(ByteOrder.BIG_ENDIAN) ? str : reverse(str);
|
||||
}
|
||||
|
||||
public static String reverse(String str)
|
||||
{
|
||||
return new StringBuilder(str).reverse().toString();
|
||||
}
|
||||
}
|
||||
12
src/main/java/com/volmit/iris/util/Writable.java
Normal file
12
src/main/java/com/volmit/iris/util/Writable.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package com.volmit.iris.util;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Writable
|
||||
{
|
||||
public void write(DataOutputStream o) throws IOException;
|
||||
|
||||
public void read(DataInputStream i) throws IOException;
|
||||
}
|
||||
Reference in New Issue
Block a user