233 lines
5.9 KiB
Java
233 lines
5.9 KiB
Java
package speiger.src.coreengine.rendering.texturesOld.normal;
|
|
|
|
import java.nio.ByteBuffer;
|
|
import java.util.Arrays;
|
|
import java.util.Iterator;
|
|
import java.util.concurrent.locks.Lock;
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
|
|
import org.lwjgl.opengl.GL11;
|
|
import org.lwjgl.opengl.GL46;
|
|
import org.lwjgl.system.MemoryStack;
|
|
import org.lwjgl.system.MemoryUtil;
|
|
|
|
import speiger.src.collections.ints.collections.IntIterator;
|
|
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectLinkedOpenHashMap;
|
|
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
|
|
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap.Entry;
|
|
import speiger.src.collections.ints.sets.IntLinkedOpenHashSet;
|
|
import speiger.src.collections.ints.sets.IntSet;
|
|
import speiger.src.collections.ints.utils.maps.Int2ObjectMaps;
|
|
import speiger.src.collections.utils.ITrimmable;
|
|
import speiger.src.coreengine.math.BitUtil;
|
|
import speiger.src.coreengine.rendering.texturesOld.base.AbstractTexture;
|
|
import speiger.src.coreengine.rendering.texturesOld.base.TextureManager;
|
|
import speiger.src.coreengine.rendering.texturesOld.custom.IDynamicTexture;
|
|
import speiger.src.coreengine.rendering.utils.AllocationTracker;
|
|
|
|
public class DynamicTexture extends AbstractTexture implements IDynamicTexture
|
|
{
|
|
public static final int R = 0xFF << 16;
|
|
public static final int G = 0xFF << 8;
|
|
public static final int B = 0xFF;
|
|
public static final int A = 0xFF << 24;
|
|
Int2ObjectMap<IntSet> dirtyChunks = new Int2ObjectLinkedOpenHashMap<IntSet>();
|
|
Lock lock = new ReentrantLock();
|
|
int[] data;
|
|
int width;
|
|
int height;
|
|
|
|
public DynamicTexture(int width, int height)
|
|
{
|
|
this.width = width;
|
|
this.height = height;
|
|
setTextureID(GL11.glGenTextures());
|
|
data = new int[width * height];
|
|
}
|
|
|
|
public DynamicTexture(int width, int height, int defaultValue)
|
|
{
|
|
this(width, height);
|
|
Arrays.fill(data, defaultValue);
|
|
processChanges(true);
|
|
}
|
|
|
|
public int[] getTextureData()
|
|
{
|
|
return data;
|
|
}
|
|
|
|
@Override
|
|
public void markDirty(int x, int z)
|
|
{
|
|
lock.lock();
|
|
dirtyChunks.supplyIfAbsent(BitUtil.toInt(x >> 4, z >> 4), IntLinkedOpenHashSet::new).add((x & 15) << 4 | (z & 15));
|
|
lock.unlock();
|
|
}
|
|
|
|
@Override
|
|
public void setData(int index, int value)
|
|
{
|
|
data[index] = value;
|
|
markDirty(index);
|
|
}
|
|
|
|
@Override
|
|
public void setRed(int index, int red)
|
|
{
|
|
if(getRed(index) == red) return;
|
|
data[index] = (data[index] & ~R) | (red & 0xFF) << 16;
|
|
markDirty(index);
|
|
}
|
|
|
|
@Override
|
|
public void setGreen(int index, int green)
|
|
{
|
|
if(getGreen(index) == green) return;
|
|
data[index] = (data[index] & ~G) | (green & 0xFF) << 8;
|
|
markDirty(index);
|
|
}
|
|
|
|
@Override
|
|
public void setBlue(int index, int blue)
|
|
{
|
|
if(getBlue(index) == blue) return;
|
|
data[index] = (data[index] & ~B) | (blue & 0xFF);
|
|
markDirty(index);
|
|
}
|
|
|
|
@Override
|
|
public void setAlpha(int index, int alpha)
|
|
{
|
|
if(getAlpha(index) == alpha) return;
|
|
data[index] = (data[index] & ~A) | (alpha & 0xFF) << 24;
|
|
markDirty(index);
|
|
}
|
|
|
|
@Override
|
|
public int getRGB(int index)
|
|
{
|
|
return data[index];
|
|
}
|
|
|
|
@Override
|
|
public int getRed(int index)
|
|
{
|
|
return (data[index] >> 16) & 0xFF;
|
|
}
|
|
|
|
@Override
|
|
public int getGreen(int index)
|
|
{
|
|
return (data[index] >> 8) & 0xFF;
|
|
}
|
|
|
|
@Override
|
|
public int getBlue(int index)
|
|
{
|
|
return data[index] & 0xFF;
|
|
}
|
|
|
|
@Override
|
|
public int getAlpha(int index)
|
|
{
|
|
return (data[index] >> 24) & 0xFF;
|
|
}
|
|
|
|
@Override
|
|
public boolean isDirty()
|
|
{
|
|
return dirtyChunks.size() > 0;
|
|
}
|
|
|
|
@Override
|
|
public void processChanges(boolean full)
|
|
{
|
|
lock.lock();
|
|
if(full)
|
|
{
|
|
ByteBuffer buffer = MemoryUtil.memAlloc(data.length * 4);
|
|
for(int i = 0;i<data.length;i++)
|
|
{
|
|
int pixel = data[i];
|
|
buffer.put((byte)((pixel >> 16) & 0xFF));
|
|
buffer.put((byte)((pixel >> 8) & 0xFF));
|
|
buffer.put((byte)(pixel & 0xFF));
|
|
buffer.put((byte)((pixel >> 24) & 0xFF));
|
|
}
|
|
buffer.flip();
|
|
bindTexture();
|
|
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
|
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
|
AllocationTracker.INSTANCE.addGPUBytes(buffer.remaining());
|
|
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
|
|
MemoryUtil.memFree(buffer);
|
|
dirtyChunks.clear();
|
|
}
|
|
else
|
|
{
|
|
bindTexture();
|
|
Thread thread = Thread.currentThread();
|
|
for(Iterator<Entry<IntSet>> iter = Int2ObjectMaps.fastIterator(dirtyChunks);iter.hasNext() && !thread.isInterrupted();iter.remove())
|
|
{
|
|
Entry<IntSet> values = iter.next();
|
|
int key = values.getIntKey();
|
|
int chunkX = BitUtil.toFirstShort(key) * 16;
|
|
int chunkZ = BitUtil.toSecondShort(key) * 16;
|
|
int width = 0;
|
|
int height = 0;
|
|
for(IntIterator subIt = values.getValue().iterator();subIt.hasNext();)
|
|
{
|
|
int index = subIt.nextInt();
|
|
width = Math.max(width, ((index >> 4) & 0xF) + 1);
|
|
height = Math.max(height, (index & 0xF) + 1);
|
|
}
|
|
try(MemoryStack stack = MemoryStack.stackPush())
|
|
{
|
|
ByteBuffer buffer = stack.malloc(width * height * 4);
|
|
for(int y = 0;y<height;y++)
|
|
{
|
|
for(int x = 0;x<width;x++)
|
|
{
|
|
int pixel = data[((chunkZ + y) * this.width) + chunkX + x];
|
|
buffer.put((byte)((pixel >> 16) & 0xFF));
|
|
buffer.put((byte)((pixel >> 8) & 0xFF));
|
|
buffer.put((byte)(pixel & 0xFF));
|
|
buffer.put((byte)((pixel >> 24) & 0xFF));
|
|
}
|
|
}
|
|
buffer.flip();
|
|
AllocationTracker.INSTANCE.addGPUBytes(buffer.remaining());
|
|
GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, chunkX, chunkZ, width, height, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
|
|
}
|
|
}
|
|
}
|
|
if(dirtyChunks.isEmpty())
|
|
{
|
|
((ITrimmable)dirtyChunks).trim();
|
|
}
|
|
lock.unlock();
|
|
}
|
|
|
|
@Override
|
|
public void reload()
|
|
{
|
|
int old = getTextureId();
|
|
setTextureID(GL11.glGenTextures());
|
|
TextureManager.INSTANCE.removeTexture(old);
|
|
processChanges(true);
|
|
}
|
|
|
|
@Override
|
|
public int getWidth()
|
|
{
|
|
return width;
|
|
}
|
|
|
|
@Override
|
|
public int getHeight()
|
|
{
|
|
return height;
|
|
}
|
|
}
|