PBO ускоряет очистку чанков
This commit is contained in:
@@ -11,7 +11,6 @@ public final class FogChunkStreamer {
|
||||
LOADED
|
||||
}
|
||||
|
||||
// Очередь изменений блоков (потокобезопасная)
|
||||
private static final ConcurrentLinkedQueue<BlockChangeEvent> blockChangeQueue =
|
||||
new ConcurrentLinkedQueue<>();
|
||||
|
||||
@@ -39,6 +38,13 @@ public final class FogChunkStreamer {
|
||||
|
||||
private static boolean firstUpdate = true;
|
||||
|
||||
private static final int MAX_REGIONS = 16;
|
||||
private static final int[] regionPhysX = new int[MAX_REGIONS];
|
||||
private static final int[] regionPhysZ = new int[MAX_REGIONS];
|
||||
private static final int[] regionWidth = new int[MAX_REGIONS];
|
||||
private static final int[] regionDepth = new int[MAX_REGIONS];
|
||||
private static int regionCount = 0;
|
||||
|
||||
private FogChunkStreamer() {
|
||||
}
|
||||
|
||||
@@ -51,13 +57,9 @@ public final class FogChunkStreamer {
|
||||
BlockState newState
|
||||
) {}
|
||||
|
||||
// Вызывается из любого потока (в том числе серверного)
|
||||
public static void onBlockChanged(
|
||||
int chunkX,
|
||||
int chunkZ,
|
||||
int blockX,
|
||||
int blockY,
|
||||
int blockZ,
|
||||
int chunkX, int chunkZ,
|
||||
int blockX, int blockY, int blockZ,
|
||||
BlockState newState
|
||||
) {
|
||||
blockChangeQueue.add(new BlockChangeEvent(chunkX, chunkZ, blockX, blockY, blockZ, newState));
|
||||
@@ -97,48 +99,124 @@ public final class FogChunkStreamer {
|
||||
return;
|
||||
}
|
||||
|
||||
regionCount = 0;
|
||||
|
||||
if (dx > 0) {
|
||||
for (int i = 0; i < dx; i++) {
|
||||
int worldChunkX = newOriginChunkX + FogWorldVolume.CHUNKS_X - dx + i;
|
||||
for (int z = 0; z < FogWorldVolume.CHUNKS_Z; z++) {
|
||||
markSlotPending(worldChunkX, newOriginChunkZ + z);
|
||||
}
|
||||
}
|
||||
int worldX = newOriginChunkX + FogWorldVolume.CHUNKS_X - dx;
|
||||
int worldZ = newOriginChunkZ;
|
||||
collectRegions(worldX, worldZ, dx, FogWorldVolume.CHUNKS_Z);
|
||||
markPendingRange(worldX, worldZ, dx, FogWorldVolume.CHUNKS_Z);
|
||||
}
|
||||
|
||||
if (dx < 0) {
|
||||
for (int i = 0; i < -dx; i++) {
|
||||
int worldChunkX = newOriginChunkX + i;
|
||||
for (int z = 0; z < FogWorldVolume.CHUNKS_Z; z++) {
|
||||
markSlotPending(worldChunkX, newOriginChunkZ + z);
|
||||
}
|
||||
}
|
||||
int worldX = newOriginChunkX;
|
||||
int worldZ = newOriginChunkZ;
|
||||
collectRegions(worldX, worldZ, -dx, FogWorldVolume.CHUNKS_Z);
|
||||
markPendingRange(worldX, worldZ, -dx, FogWorldVolume.CHUNKS_Z);
|
||||
}
|
||||
|
||||
if (dz > 0) {
|
||||
for (int x = 0; x < FogWorldVolume.CHUNKS_X; x++) {
|
||||
int worldChunkX = newOriginChunkX + x;
|
||||
for (int i = 0; i < dz; i++) {
|
||||
int worldChunkZ = newOriginChunkZ + FogWorldVolume.CHUNKS_Z - dz + i;
|
||||
markSlotPending(worldChunkX, worldChunkZ);
|
||||
}
|
||||
}
|
||||
int worldX = newOriginChunkX;
|
||||
int worldZ = newOriginChunkZ + FogWorldVolume.CHUNKS_Z - dz;
|
||||
collectRegions(worldX, worldZ, FogWorldVolume.CHUNKS_X, dz);
|
||||
markPendingRange(worldX, worldZ, FogWorldVolume.CHUNKS_X, dz);
|
||||
}
|
||||
|
||||
if (dz < 0) {
|
||||
for (int x = 0; x < FogWorldVolume.CHUNKS_X; x++) {
|
||||
int worldChunkX = newOriginChunkX + x;
|
||||
for (int i = 0; i < -dz; i++) {
|
||||
int worldChunkZ = newOriginChunkZ + i;
|
||||
markSlotPending(worldChunkX, worldChunkZ);
|
||||
}
|
||||
int worldX = newOriginChunkX;
|
||||
int worldZ = newOriginChunkZ;
|
||||
collectRegions(worldX, worldZ, FogWorldVolume.CHUNKS_X, -dz);
|
||||
markPendingRange(worldX, worldZ, FogWorldVolume.CHUNKS_X, -dz);
|
||||
}
|
||||
|
||||
if (regionCount > 0) {
|
||||
FogWorldVolume.clearRegions(regionPhysX, regionPhysZ, regionWidth, regionDepth, regionCount);
|
||||
FogDensityTextures.clearRegions(regionPhysX, regionPhysZ, regionWidth, regionDepth, regionCount);
|
||||
}
|
||||
|
||||
uploadReadyData();
|
||||
}
|
||||
|
||||
// Обрабатывает очередь изменений блоков (только в render thread)
|
||||
private static void collectRegions(
|
||||
int worldX, int worldZ,
|
||||
int countX, int countZ
|
||||
) {
|
||||
int[] xStarts = new int[2];
|
||||
int[] xCounts = new int[2];
|
||||
int xSegCount = splitIntoSegments(worldX, countX, FogWorldVolume.CHUNKS_X, xStarts, xCounts);
|
||||
|
||||
int[] zStarts = new int[2];
|
||||
int[] zCounts = new int[2];
|
||||
int zSegCount = splitIntoSegments(worldZ, countZ, FogWorldVolume.CHUNKS_Z, zStarts, zCounts);
|
||||
|
||||
for (int i = 0; i < xSegCount; i++) {
|
||||
for (int j = 0; j < zSegCount; j++) {
|
||||
if (regionCount >= MAX_REGIONS) return;
|
||||
regionPhysX[regionCount] = xStarts[i];
|
||||
regionPhysZ[regionCount] = zStarts[j];
|
||||
regionWidth[regionCount] = xCounts[i];
|
||||
regionDepth[regionCount] = zCounts[j];
|
||||
regionCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int splitIntoSegments(
|
||||
int start, int count, int dim,
|
||||
int[] outStarts, int[] outCounts
|
||||
) {
|
||||
if (count == 0) return 0;
|
||||
|
||||
int first = Math.floorMod(start, dim);
|
||||
int last = Math.floorMod(start + count - 1, dim);
|
||||
|
||||
if (first <= last) {
|
||||
outStarts[0] = first;
|
||||
outCounts[0] = count;
|
||||
return 1;
|
||||
} else {
|
||||
int firstCount = dim - first;
|
||||
outStarts[0] = first;
|
||||
outCounts[0] = firstCount;
|
||||
outStarts[1] = 0;
|
||||
outCounts[1] = count - firstCount;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
private static void markPendingRange(
|
||||
int worldX, int worldZ,
|
||||
int countX, int countZ
|
||||
) {
|
||||
for (int i = 0; i < countX; i++) {
|
||||
for (int j = 0; j < countZ; j++) {
|
||||
int wx = worldX + i;
|
||||
int wz = worldZ + j;
|
||||
int physicalX = Math.floorMod(wx, FogWorldVolume.CHUNKS_X);
|
||||
int physicalZ = Math.floorMod(wz, FogWorldVolume.CHUNKS_Z);
|
||||
int physicalIndex = physicalZ * FogWorldVolume.CHUNKS_X + physicalX;
|
||||
statuses[physicalIndex] = ChunkStatus.PENDING;
|
||||
readyToUpload[physicalIndex] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void markAllPending(int originChunkX, int originChunkZ) {
|
||||
regionCount = 1;
|
||||
regionPhysX[0] = 0;
|
||||
regionPhysZ[0] = 0;
|
||||
regionWidth[0] = FogWorldVolume.CHUNKS_X;
|
||||
regionDepth[0] = FogWorldVolume.CHUNKS_Z;
|
||||
|
||||
for (int i = 0; i < TOTAL_CHUNKS; i++) {
|
||||
statuses[i] = ChunkStatus.PENDING;
|
||||
readyToUpload[i] = false;
|
||||
}
|
||||
|
||||
FogWorldVolume.clearRegions(regionPhysX, regionPhysZ, regionWidth, regionDepth, regionCount);
|
||||
FogDensityTextures.clearRegions(regionPhysX, regionPhysZ, regionWidth, regionDepth, regionCount);
|
||||
}
|
||||
|
||||
public static void processBlockChanges() {
|
||||
BlockChangeEvent event;
|
||||
while ((event = blockChangeQueue.poll()) != null) {
|
||||
@@ -152,40 +230,28 @@ public final class FogChunkStreamer {
|
||||
int ringOffsetX = currentRingChunkOffsetX;
|
||||
int ringOffsetZ = currentRingChunkOffsetZ;
|
||||
|
||||
// Проверяем, находится ли чанк в нашей области
|
||||
int relativeX = event.chunkX - originX;
|
||||
int relativeZ = event.chunkZ - originZ;
|
||||
int relativeX = event.chunkX() - originX;
|
||||
int relativeZ = event.chunkZ() - originZ;
|
||||
|
||||
if (relativeX < 0 || relativeX >= FogWorldVolume.CHUNKS_X ||
|
||||
relativeZ < 0 || relativeZ >= FogWorldVolume.CHUNKS_Z) {
|
||||
return; // Чанк вне области обработки
|
||||
return;
|
||||
}
|
||||
|
||||
// Вычисляем физический индекс
|
||||
int physicalX = Math.floorMod(relativeX + ringOffsetX, FogWorldVolume.CHUNKS_X);
|
||||
int physicalZ = Math.floorMod(relativeZ + ringOffsetZ, FogWorldVolume.CHUNKS_Z);
|
||||
|
||||
// Вычисляем позицию вокселя
|
||||
int localX = event.blockX & 15;
|
||||
int localZ = event.blockZ & 15;
|
||||
int yIndex = event.blockY - FogWorldVolume.MIN_Y;
|
||||
int localX = event.blockX() & 15;
|
||||
int localZ = event.blockZ() & 15;
|
||||
int yIndex = event.blockY() - FogWorldVolume.MIN_Y;
|
||||
|
||||
if (yIndex < 0 || yIndex >= FogWorldVolume.SIZE_Y) {
|
||||
return; // Y вне диапазона
|
||||
return;
|
||||
}
|
||||
|
||||
// Вычисляем значение для этого вокселя
|
||||
byte value = FogChunkProvider.computePackedVoxelValue(event.newState());
|
||||
|
||||
// Обновляем один воксель в текстуре
|
||||
FogWorldVolume.updateSingleVoxel(
|
||||
physicalX,
|
||||
physicalZ,
|
||||
localX,
|
||||
yIndex,
|
||||
localZ,
|
||||
value
|
||||
);
|
||||
FogWorldVolume.updateSingleVoxel(physicalX, physicalZ, localX, yIndex, localZ, value);
|
||||
}
|
||||
|
||||
public static void processPending() {
|
||||
@@ -226,28 +292,6 @@ public final class FogChunkStreamer {
|
||||
}
|
||||
}
|
||||
|
||||
private static void markAllPending(int originChunkX, int originChunkZ) {
|
||||
for (int physicalZ = 0; physicalZ < FogWorldVolume.CHUNKS_Z; physicalZ++) {
|
||||
for (int physicalX = 0; physicalX < FogWorldVolume.CHUNKS_X; physicalX++) {
|
||||
int worldChunkX = originChunkX + physicalX;
|
||||
int worldChunkZ = originChunkZ + physicalZ;
|
||||
markSlotPending(worldChunkX, worldChunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void markSlotPending(int worldChunkX, int worldChunkZ) {
|
||||
int physicalX = Math.floorMod(worldChunkX, FogWorldVolume.CHUNKS_X);
|
||||
int physicalZ = Math.floorMod(worldChunkZ, FogWorldVolume.CHUNKS_Z);
|
||||
int physicalIndex = physicalZ * FogWorldVolume.CHUNKS_X + physicalX;
|
||||
|
||||
FogWorldVolume.uploadZeros(physicalX, physicalZ);
|
||||
FogDensityTextures.clearColumn(physicalX, physicalZ);
|
||||
|
||||
statuses[physicalIndex] = ChunkStatus.PENDING;
|
||||
readyToUpload[physicalIndex] = false;
|
||||
}
|
||||
|
||||
public static void uploadReadyData() {
|
||||
int originX = currentOriginChunkX;
|
||||
int originZ = currentOriginChunkZ;
|
||||
|
||||
@@ -3,7 +3,9 @@ package su.divan2000.veila.client.render.fog;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
@@ -14,28 +16,42 @@ public final class FogDensityTextures {
|
||||
private static int textureB = -1;
|
||||
private static int readIndex = 0;
|
||||
|
||||
// Float буфер с нулями для одного столбца 16×384×16
|
||||
private static final FloatBuffer ZEROS_BUFFER =
|
||||
BufferUtils.createFloatBuffer(
|
||||
FogWorldVolume.CHUNK_SIZE *
|
||||
FogWorldVolume.SIZE_Y *
|
||||
FogWorldVolume.CHUNK_SIZE
|
||||
);
|
||||
|
||||
static {
|
||||
int size = FogWorldVolume.CHUNK_SIZE * FogWorldVolume.SIZE_Y * FogWorldVolume.CHUNK_SIZE;
|
||||
for (int i = 0; i < size; i++) {
|
||||
ZEROS_BUFFER.put(0.0f);
|
||||
}
|
||||
ZEROS_BUFFER.flip();
|
||||
}
|
||||
// PBO для быстрой очистки регионов (half float нули)
|
||||
private static int clearPBO = -1;
|
||||
private static final int MAX_CLEAR_SIZE = FogWorldVolume.SIZE_X * FogWorldVolume.SIZE_Y * FogWorldVolume.SIZE_Z;
|
||||
private static final int MAX_CLEAR_SIZE_BYTES = MAX_CLEAR_SIZE * 2; // 2 байта на half float
|
||||
|
||||
private FogDensityTextures() {
|
||||
}
|
||||
|
||||
private static void initClearPBO() {
|
||||
if (clearPBO != -1) return;
|
||||
|
||||
clearPBO = GL15.glGenBuffers();
|
||||
GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, clearPBO);
|
||||
|
||||
// Выделяем буфер в VRAM
|
||||
GL15.glBufferData(GL31.GL_PIXEL_UNPACK_BUFFER, MAX_CLEAR_SIZE_BYTES, GL15.GL_STATIC_DRAW);
|
||||
|
||||
// Заполняем нулями (half float 0.0 = 2 нулевых байта: 0x0000)
|
||||
ByteBuffer mapped = GL15.glMapBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, GL15.GL_WRITE_ONLY);
|
||||
if (mapped != null) {
|
||||
// Заполняем нулями - это даст half float 0.0
|
||||
for (int i = 0; i < MAX_CLEAR_SIZE_BYTES; i++) {
|
||||
mapped.put((byte) 0);
|
||||
}
|
||||
GL15.glUnmapBuffer(GL31.GL_PIXEL_UNPACK_BUFFER);
|
||||
}
|
||||
|
||||
GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
if (textureA != -1) return;
|
||||
|
||||
// Инициализируем PBO ДО создания текстур
|
||||
initClearPBO();
|
||||
|
||||
textureA = createDensityTexture();
|
||||
textureB = createDensityTexture();
|
||||
}
|
||||
@@ -54,7 +70,7 @@ public final class FogDensityTextures {
|
||||
FogWorldVolume.SIZE_Z,
|
||||
0,
|
||||
GL11.GL_RED,
|
||||
GL11.GL_FLOAT,
|
||||
GL30.GL_HALF_FLOAT, // Исправлено: GL_HALF_FLOAT для 16-bit float
|
||||
(ByteBuffer) null
|
||||
);
|
||||
|
||||
@@ -83,39 +99,51 @@ public final class FogDensityTextures {
|
||||
}
|
||||
|
||||
/**
|
||||
* Обнуляет столбец (один чанк) в ОБОИХ density текстурах.
|
||||
* Вызывается при смене окна, чтобы не было фантомного тумана.
|
||||
* Очищает несколько непрерывных физических регионов в обеих density текстурах через PBO.
|
||||
*/
|
||||
public static void clearColumn(int textureChunkX, int textureChunkZ) {
|
||||
clearColumnInTexture(textureA, textureChunkX, textureChunkZ);
|
||||
clearColumnInTexture(textureB, textureChunkX, textureChunkZ);
|
||||
public static void clearRegions(
|
||||
int[] physX, int[] physZ,
|
||||
int[] widthChunks, int[] depthChunks,
|
||||
int count
|
||||
) {
|
||||
clearRegionsInTexture(textureA, physX, physZ, widthChunks, depthChunks, count);
|
||||
clearRegionsInTexture(textureB, physX, physZ, widthChunks, depthChunks, count);
|
||||
}
|
||||
|
||||
private static void clearColumnInTexture(int texture, int textureChunkX, int textureChunkZ) {
|
||||
private static void clearRegionsInTexture(
|
||||
int texture,
|
||||
int[] physX, int[] physZ,
|
||||
int[] widthChunks, int[] depthChunks,
|
||||
int count
|
||||
) {
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
||||
GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, clearPBO);
|
||||
|
||||
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
|
||||
GL11.glPixelStorei(GL11.GL_UNPACK_ROW_LENGTH, 0);
|
||||
GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_PIXELS, 0);
|
||||
GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_ROWS, 0);
|
||||
|
||||
// Сбрасываем position буфера
|
||||
ZEROS_BUFFER.rewind();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int w = widthChunks[i] * FogWorldVolume.CHUNK_SIZE;
|
||||
int h = FogWorldVolume.SIZE_Y;
|
||||
int d = depthChunks[i] * FogWorldVolume.CHUNK_SIZE;
|
||||
|
||||
GL30.glTexSubImage3D(
|
||||
// 0L = offset 0 внутри PBO (начало буфера)
|
||||
GL12.glTexSubImage3D(
|
||||
GL12.GL_TEXTURE_3D,
|
||||
0,
|
||||
textureChunkX * FogWorldVolume.CHUNK_SIZE,
|
||||
physX[i] * FogWorldVolume.CHUNK_SIZE,
|
||||
0,
|
||||
textureChunkZ * FogWorldVolume.CHUNK_SIZE,
|
||||
FogWorldVolume.CHUNK_SIZE,
|
||||
FogWorldVolume.SIZE_Y,
|
||||
FogWorldVolume.CHUNK_SIZE,
|
||||
physZ[i] * FogWorldVolume.CHUNK_SIZE,
|
||||
w, h, d,
|
||||
GL11.GL_RED,
|
||||
GL11.GL_FLOAT,
|
||||
ZEROS_BUFFER
|
||||
GL30.GL_HALF_FLOAT,
|
||||
0L // ← long offset вместо ByteBuffer
|
||||
);
|
||||
}
|
||||
|
||||
GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, 0);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ package su.divan2000.veila.client.render.fog;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@@ -23,11 +25,12 @@ public final class FogWorldVolume {
|
||||
|
||||
private static int texture = -1;
|
||||
|
||||
private static final byte AIR_VALUE = new FogBlockProperties(false, 0, 0).pack();
|
||||
|
||||
private static final byte[] ZEROS_ARRAY;
|
||||
static {
|
||||
ZEROS_ARRAY = new byte[CHUNK_SIZE * SIZE_Y * CHUNK_SIZE];
|
||||
byte airValue = new FogBlockProperties(false, 0, 0).pack();
|
||||
java.util.Arrays.fill(ZEROS_ARRAY, airValue);
|
||||
java.util.Arrays.fill(ZEROS_ARRAY, AIR_VALUE);
|
||||
}
|
||||
|
||||
private static final ByteBuffer CHUNK_BUFFER =
|
||||
@@ -36,12 +39,40 @@ public final class FogWorldVolume {
|
||||
private static final ByteBuffer SINGLE_VOXEL_BUFFER =
|
||||
BufferUtils.createByteBuffer(1);
|
||||
|
||||
// PBO для быстрой очистки регионов
|
||||
private static int clearPBO = -1;
|
||||
private static final int MAX_CLEAR_SIZE = SIZE_X * SIZE_Y * SIZE_Z;
|
||||
|
||||
private FogWorldVolume() {
|
||||
}
|
||||
|
||||
private static void initClearPBO() {
|
||||
if (clearPBO != -1) return;
|
||||
|
||||
clearPBO = GL15.glGenBuffers();
|
||||
GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, clearPBO);
|
||||
|
||||
// Выделяем буфер в VRAM
|
||||
GL15.glBufferData(GL31.GL_PIXEL_UNPACK_BUFFER, MAX_CLEAR_SIZE, GL15.GL_STATIC_DRAW);
|
||||
|
||||
// Заполняем AIR_VALUE через mapping
|
||||
ByteBuffer mapped = GL15.glMapBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, GL15.GL_WRITE_ONLY);
|
||||
if (mapped != null) {
|
||||
for (int i = 0; i < MAX_CLEAR_SIZE; i++) {
|
||||
mapped.put(AIR_VALUE);
|
||||
}
|
||||
GL15.glUnmapBuffer(GL31.GL_PIXEL_UNPACK_BUFFER);
|
||||
}
|
||||
|
||||
GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
if (texture != -1) return;
|
||||
|
||||
// Инициализируем PBO ДО создания текстуры
|
||||
initClearPBO();
|
||||
|
||||
texture = GL11.glGenTextures();
|
||||
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
||||
@@ -173,4 +204,44 @@ public final class FogWorldVolume {
|
||||
public static int getTexture() {
|
||||
return texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Очищает несколько непрерывных физических регионов через PBO (асинхронно).
|
||||
* Размеры widthChunks и depthChunks задаются в чанках (не в блоках!).
|
||||
*/
|
||||
public static void clearRegions(
|
||||
int[] physX, int[] physZ,
|
||||
int[] widthChunks, int[] depthChunks,
|
||||
int count
|
||||
) {
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
||||
GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, clearPBO);
|
||||
|
||||
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
|
||||
GL11.glPixelStorei(GL11.GL_UNPACK_ROW_LENGTH, 0);
|
||||
GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_PIXELS, 0);
|
||||
GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_ROWS, 0);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int w = widthChunks[i] * CHUNK_SIZE;
|
||||
int h = SIZE_Y;
|
||||
int d = depthChunks[i] * CHUNK_SIZE;
|
||||
|
||||
// 0L = offset 0 внутри PBO (начало буфера)
|
||||
GL12.glTexSubImage3D(
|
||||
GL12.GL_TEXTURE_3D,
|
||||
0,
|
||||
physX[i] * CHUNK_SIZE,
|
||||
0,
|
||||
physZ[i] * CHUNK_SIZE,
|
||||
w, h, d,
|
||||
GL30.GL_RED_INTEGER,
|
||||
GL11.GL_UNSIGNED_BYTE,
|
||||
0L // ← long offset вместо ByteBuffer
|
||||
);
|
||||
}
|
||||
|
||||
GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user