Merge
This commit is contained in:
+3
@@ -92,8 +92,11 @@ public class LodBufferBuilderFactory {
|
||||
* when need be to fit the larger sizes.
|
||||
*/
|
||||
public static final int DEFAULT_MEMORY_ALLOCATION = (LodUtil.LOD_VERTEX_FORMAT.getByteSize() * 3) * 8;
|
||||
public static final int QUADS_BYTE_SIZE = LodUtil.LOD_VERTEX_FORMAT.getByteSize() * (LodRenderer.ENABLE_IBO ? 4 : 6);
|
||||
public static final int MAX_TRIANGLES_PER_BUFFER = (1024 * 1024 * 1)
|
||||
/ (LodUtil.LOD_VERTEX_FORMAT.getByteSize() * 3);
|
||||
public static final int MAX_QUADS_PER_BUFFER = (1024 * 1024 * 1) / QUADS_BYTE_SIZE;
|
||||
public static final int FULL_SIZED_BUFFER = MAX_QUADS_PER_BUFFER * QUADS_BYTE_SIZE;
|
||||
|
||||
public static int skyLightPlayer = 15;
|
||||
|
||||
|
||||
+109
-27
@@ -30,7 +30,8 @@ import com.seibel.lod.core.enums.LodDirection;
|
||||
import com.seibel.lod.core.enums.LodDirection.Axis;
|
||||
import com.seibel.lod.core.enums.config.GpuUploadMethod;
|
||||
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.objects.opengl.LodVertexBuffer;
|
||||
import com.seibel.lod.core.render.LodRenderer;
|
||||
import com.seibel.lod.core.render.objects.GLVertexBuffer;
|
||||
import com.seibel.lod.core.util.ColorUtil;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||
@@ -44,10 +45,6 @@ import static com.seibel.lod.core.render.LodRenderer.EVENT_LOGGER;
|
||||
*/
|
||||
public class LodQuadBuilder
|
||||
{
|
||||
static final int MAX_BUFFER_SIZE = (1024 * 1024);
|
||||
static final int QUAD_BYTE_SIZE = (12 * 4);
|
||||
static final int MAX_QUADS_PER_BUFFER = MAX_BUFFER_SIZE / QUAD_BYTE_SIZE;
|
||||
|
||||
static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
|
||||
|
||||
public final boolean skipQuadsWithZeroSkylight;
|
||||
@@ -55,7 +52,7 @@ public class LodQuadBuilder
|
||||
|
||||
final ArrayList<BufferQuad>[] quads = (ArrayList<BufferQuad>[]) new ArrayList[6];
|
||||
|
||||
public static final int[][][] DIRECTION_VERTEX_QUAD = new int[][][]
|
||||
public static final int[][][] DIRECTION_VERTEX_IBO_QUAD = new int[][][]
|
||||
{
|
||||
// X,Z //
|
||||
{ // UP
|
||||
@@ -103,7 +100,68 @@ public class LodQuadBuilder
|
||||
{ 0, 0 }, // 3
|
||||
},
|
||||
};
|
||||
|
||||
public static final int[][][] DIRECTION_VERTEX_QUAD = new int[][][]
|
||||
{
|
||||
// X,Z //
|
||||
{ // UP
|
||||
{ 1, 0 }, // 0
|
||||
{ 1, 1 }, // 1
|
||||
{ 0, 1 }, // 2
|
||||
|
||||
{ 1, 0 }, // 0
|
||||
{ 0, 1 }, // 2
|
||||
{ 0, 0 }, // 3
|
||||
},
|
||||
{ // DOWN
|
||||
{ 0, 0 }, // 0
|
||||
{ 0, 1 }, // 1
|
||||
{ 1, 1 }, // 2
|
||||
|
||||
{ 0, 0 }, // 0
|
||||
{ 1, 1 }, // 2
|
||||
{ 1, 0 }, // 3
|
||||
},
|
||||
|
||||
// X,Y //
|
||||
{ // NORTH
|
||||
{ 0, 0 }, // 0
|
||||
{ 0, 1 }, // 1
|
||||
{ 1, 1 }, // 2
|
||||
|
||||
{ 0, 0 }, // 0
|
||||
{ 1, 1 }, // 2
|
||||
{ 1, 0 }, // 3
|
||||
},
|
||||
{ // SOUTH
|
||||
{ 1, 0 }, // 0
|
||||
{ 1, 1 }, // 1
|
||||
{ 0, 1 }, // 2
|
||||
|
||||
{ 1, 0 }, // 0
|
||||
{ 0, 1 }, // 2
|
||||
{ 0, 0 }, // 3
|
||||
},
|
||||
|
||||
// Z,Y //
|
||||
{ // WEST
|
||||
{ 0, 0 }, // 0
|
||||
{ 1, 0 }, // 1
|
||||
{ 1, 1 }, // 2
|
||||
|
||||
{ 0, 0 }, // 0
|
||||
{ 1, 1 }, // 2
|
||||
{ 0, 1 }, // 3
|
||||
},
|
||||
{ // EAST
|
||||
{ 0, 1 }, // 0
|
||||
{ 1, 1 }, // 1
|
||||
{ 1, 0 }, // 2
|
||||
|
||||
{ 0, 1 }, // 0
|
||||
{ 1, 0 }, // 2
|
||||
{ 0, 0 }, // 3
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
public LodQuadBuilder(boolean enableSkylightCulling, int skyLightCullingBelow)
|
||||
@@ -176,7 +234,7 @@ public class LodQuadBuilder
|
||||
|
||||
|
||||
|
||||
private static void putVertex(ByteBuffer bb, short x, short y, short z, int color, byte skylight, byte blocklight)
|
||||
private static void putVertex(ByteBuffer bb, short x, short y, short z, int color, byte skylight, byte blocklight, int mx, int my, int mz)
|
||||
{
|
||||
skylight %= 16;
|
||||
blocklight %= 16;
|
||||
@@ -184,8 +242,21 @@ public class LodQuadBuilder
|
||||
bb.putShort(x);
|
||||
bb.putShort(y);
|
||||
bb.putShort(z);
|
||||
|
||||
bb.putShort((short) (skylight | (blocklight << 4)));
|
||||
|
||||
short meta = 0;
|
||||
meta |= (skylight | (blocklight << 4));
|
||||
byte mirco = 0;
|
||||
// mirco offset which is a xyz 2bit value
|
||||
// 0b00 = no offset
|
||||
// 0b01 = positive offset
|
||||
// 0b11 = negative offset
|
||||
// format is: 0b00zzyyxx
|
||||
if (mx != 0) mirco |= mx > 0 ? 0b01 : 0b11;
|
||||
if (my != 0) mirco |= my > 0 ? 0b0100 : 0b1100;
|
||||
if (mz != 0) mirco |= mz > 0 ? 0b010000 : 0b110000;
|
||||
meta |= mirco << 8;
|
||||
|
||||
bb.putShort(meta);
|
||||
byte r = (byte) ColorUtil.getRed(color);
|
||||
byte g = (byte) ColorUtil.getGreen(color);
|
||||
byte b = (byte) ColorUtil.getBlue(color);
|
||||
@@ -198,35 +269,45 @@ public class LodQuadBuilder
|
||||
|
||||
private static void putQuad(ByteBuffer bb, BufferQuad quad)
|
||||
{
|
||||
int[][] quadBase = DIRECTION_VERTEX_QUAD[quad.direction.ordinal()];
|
||||
int[][] quadBase = LodRenderer.ENABLE_IBO ? DIRECTION_VERTEX_IBO_QUAD[quad.direction.ordinal()] : DIRECTION_VERTEX_QUAD[quad.direction.ordinal()];
|
||||
short widthEastWest = quad.widthEastWest;
|
||||
short widthNorthSouth = quad.widthNorthSouthOrUpDown;
|
||||
Axis axis = quad.direction.getAxis();
|
||||
for (int i = 0; i < quadBase.length; i++)
|
||||
{
|
||||
short dx, dy, dz;
|
||||
int mx, my, mz;
|
||||
switch (axis)
|
||||
{
|
||||
case X: // ZY
|
||||
dx = 0;
|
||||
dy = quadBase[i][1] == 1 ? widthNorthSouth : 0;
|
||||
dz = quadBase[i][0] == 1 ? widthEastWest : 0;
|
||||
mx = 0;
|
||||
my = quadBase[i][1] == 1 ? 1 : -1;
|
||||
mz = quadBase[i][0] == 1 ? 1 : -1;
|
||||
break;
|
||||
case Y: // XZ
|
||||
dx = quadBase[i][0] == 1 ? widthEastWest : 0;
|
||||
dy = 0;
|
||||
dz = quadBase[i][1] == 1 ? widthNorthSouth : 0;
|
||||
mx = quadBase[i][0] == 1 ? 1 : -1;
|
||||
my = 0;
|
||||
mz = quadBase[i][1] == 1 ? 1 : -1;
|
||||
break;
|
||||
case Z: // XY
|
||||
dx = quadBase[i][0] == 1 ? widthEastWest : 0;
|
||||
dy = quadBase[i][1] == 1 ? widthNorthSouth : 0;
|
||||
dz = 0;
|
||||
mx = quadBase[i][0] == 1 ? 1 : -1;
|
||||
my = quadBase[i][1] == 1 ? 1 : -1;
|
||||
mz = 0;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid Axis enum: " + axis);
|
||||
}
|
||||
putVertex(bb, (short) (quad.x + dx), (short) (quad.y + dy), (short) (quad.z + dz), quad.color,
|
||||
quad.skyLight, quad.blockLight);
|
||||
quad.skyLight, quad.blockLight, mx, my, mz);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +371,7 @@ public class LodQuadBuilder
|
||||
{
|
||||
return new Iterator<ByteBuffer>()
|
||||
{
|
||||
final ByteBuffer bb = ByteBuffer.allocateDirect(MAX_QUADS_PER_BUFFER * QUAD_BYTE_SIZE)
|
||||
final ByteBuffer bb = ByteBuffer.allocateDirect(LodBufferBuilderFactory.FULL_SIZED_BUFFER)
|
||||
.order(ByteOrder.nativeOrder());
|
||||
int dir = skipEmpty(0);
|
||||
int quad = 0;
|
||||
@@ -316,7 +397,7 @@ public class LodQuadBuilder
|
||||
return null;
|
||||
}
|
||||
bb.clear();
|
||||
bb.limit(MAX_QUADS_PER_BUFFER * QUAD_BYTE_SIZE);
|
||||
bb.limit(LodBufferBuilderFactory.FULL_SIZED_BUFFER);
|
||||
while (bb.hasRemaining() && dir < 6)
|
||||
{
|
||||
writeData();
|
||||
@@ -355,7 +436,7 @@ public class LodQuadBuilder
|
||||
public interface BufferFiller
|
||||
{
|
||||
/** If true: more data needs to be filled */
|
||||
boolean fill(LodVertexBuffer vbo);
|
||||
boolean fill(GLVertexBuffer vbo);
|
||||
}
|
||||
|
||||
public BufferFiller makeBufferFiller(GpuUploadMethod method)
|
||||
@@ -365,34 +446,35 @@ public class LodQuadBuilder
|
||||
int dir = 0;
|
||||
int quad = 0;
|
||||
|
||||
public boolean fill(LodVertexBuffer vbo)
|
||||
public boolean fill(GLVertexBuffer vbo)
|
||||
{
|
||||
if (dir >= 6)
|
||||
{
|
||||
vbo.vertexCount = 0;
|
||||
vbo.setVertexCount(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
int numOfQuads = _countRemainingQuads();
|
||||
if (numOfQuads > MAX_QUADS_PER_BUFFER)
|
||||
numOfQuads = MAX_QUADS_PER_BUFFER;
|
||||
if (numOfQuads > LodBufferBuilderFactory.MAX_QUADS_PER_BUFFER)
|
||||
numOfQuads = LodBufferBuilderFactory.MAX_QUADS_PER_BUFFER;
|
||||
if (numOfQuads == 0)
|
||||
{
|
||||
vbo.vertexCount = 0;
|
||||
vbo.setVertexCount(0);
|
||||
return false;
|
||||
}
|
||||
ByteBuffer bb = vbo.mapBuffer(numOfQuads * QUAD_BYTE_SIZE, method, MAX_QUADS_PER_BUFFER * QUAD_BYTE_SIZE);
|
||||
ByteBuffer bb = vbo.mapBuffer(numOfQuads * LodBufferBuilderFactory.QUADS_BYTE_SIZE, method,
|
||||
LodBufferBuilderFactory.FULL_SIZED_BUFFER);
|
||||
if (bb == null)
|
||||
throw new NullPointerException("mapBuffer returned null");
|
||||
bb.clear();
|
||||
bb.limit(numOfQuads * QUAD_BYTE_SIZE);
|
||||
bb.limit(numOfQuads * LodBufferBuilderFactory.QUADS_BYTE_SIZE);
|
||||
while (bb.hasRemaining() && dir < 6)
|
||||
{
|
||||
writeData(bb);
|
||||
}
|
||||
bb.rewind();
|
||||
vbo.unmapBuffer(method);
|
||||
vbo.vertexCount = numOfQuads * 4;
|
||||
vbo.unmapBuffer();
|
||||
vbo.setVertexCount(LodRenderer.ENABLE_IBO ? numOfQuads*4 : numOfQuads*6);
|
||||
return dir < 6;
|
||||
}
|
||||
|
||||
@@ -444,11 +526,11 @@ public class LodQuadBuilder
|
||||
i += qs.size();
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/** Returns how many Buffers will be needed to render everything in this builder. */
|
||||
public int getCurrentNeededVertexBufferCount()
|
||||
{
|
||||
return LodUtil.ceilDiv(getCurrentQuadsCount(), MAX_QUADS_PER_BUFFER);
|
||||
return LodUtil.ceilDiv(getCurrentQuadsCount(), LodBufferBuilderFactory.MAX_QUADS_PER_BUFFER);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU GPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.objects.opengl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.seibel.lod.core.api.ApiShared;
|
||||
import com.seibel.lod.core.util.UnitBytes;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.opengl.GL44;
|
||||
|
||||
import com.seibel.lod.core.enums.config.GpuUploadMethod;
|
||||
import com.seibel.lod.core.enums.rendering.GLProxyContext;
|
||||
import com.seibel.lod.core.render.GLProxy;
|
||||
|
||||
/**
|
||||
* This is a container for a OpenGL
|
||||
* VBO (Vertex Buffer Object).
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-20-2021
|
||||
*/
|
||||
public class LodVertexBuffer implements AutoCloseable
|
||||
{
|
||||
/**
|
||||
* When uploading to a buffer that is too small, recreate it this many times
|
||||
* bigger than the upload payload
|
||||
*/
|
||||
public static final double BUFFER_EXPANSION_MULTIPLIER = 1.3;
|
||||
public static int count = 0;
|
||||
public int id;
|
||||
public int vertexCount;
|
||||
public boolean isBufferStorage;
|
||||
public long size = 0;
|
||||
|
||||
public LodVertexBuffer(boolean isBufferStorage)
|
||||
{
|
||||
_create(isBufferStorage);
|
||||
}
|
||||
|
||||
private void _create(boolean asBufferStorage) {
|
||||
if (GLProxy.getInstance().getGlContext() == GLProxyContext.NONE)
|
||||
throw new IllegalStateException("Thread [" +Thread.currentThread().getName() + "] tried to create a [" + LodVertexBuffer.class.getSimpleName() + "] outside a OpenGL contex.");
|
||||
this.id = GL32.glGenBuffers();
|
||||
this.isBufferStorage = asBufferStorage;
|
||||
count++;
|
||||
}
|
||||
|
||||
private void _destroy() {
|
||||
if (GLProxy.getInstance().getGlContext() == GLProxyContext.PROXY_WORKER) {
|
||||
GL32.glDeleteBuffers(this.id);
|
||||
} else {
|
||||
final int id = this.id;
|
||||
GLProxy.getInstance().recordOpenGlCall(() -> GL32.glDeleteBuffers(id));
|
||||
}
|
||||
this.id = -1;
|
||||
size = 0;
|
||||
vertexCount = 0;
|
||||
count--;
|
||||
}
|
||||
|
||||
private void _uploadBufferStorage(ByteBuffer bb) {
|
||||
if (!isBufferStorage) throw new IllegalStateException("Buffer is not bufferStorage but its trying to use bufferStorage upload method!");
|
||||
int bbSize = bb.limit() - bb.position();
|
||||
GL32.glDeleteBuffers(id);
|
||||
id = GL32.glGenBuffers();
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, id);
|
||||
GL44.glBufferStorage(GL32.GL_ARRAY_BUFFER, bb, 0);
|
||||
size = bbSize;
|
||||
}
|
||||
|
||||
// bufferData
|
||||
// simplest/most compatible
|
||||
private void _uploadData(ByteBuffer bb) {
|
||||
if (isBufferStorage) throw new IllegalStateException("Buffer is bufferStorage but its trying to use Data upload method!");
|
||||
int bbSize = bb.limit() - bb.position();
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, id);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, bb, GL32.GL_STATIC_DRAW);
|
||||
size = bbSize;
|
||||
}
|
||||
|
||||
// bufferSubData
|
||||
// less stutter, low GPU usage?
|
||||
private void _uploadSubData(ByteBuffer bb, int maxExpensionSize) {
|
||||
if (isBufferStorage) throw new IllegalStateException("Buffer is bufferStorage but its trying to use SubData upload method!");
|
||||
int bbSize = bb.limit() - bb.position();
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, id);
|
||||
if (size < bbSize || size > bbSize * BUFFER_EXPANSION_MULTIPLIER * BUFFER_EXPANSION_MULTIPLIER) {
|
||||
int newSize = (int) (bbSize * BUFFER_EXPANSION_MULTIPLIER);
|
||||
if (newSize > maxExpensionSize) newSize = maxExpensionSize;
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, newSize, GL32.GL_STATIC_DRAW);
|
||||
size = newSize;
|
||||
}
|
||||
GL32.glBufferSubData(GL32.GL_ARRAY_BUFFER, 0, bb);
|
||||
}
|
||||
|
||||
public void uploadBuffer(ByteBuffer bb, int vertCount, GpuUploadMethod uploadMethod, int maxExpensionSize) {
|
||||
if (vertCount < 0) throw new IllegalArgumentException("VertCount is negative!");
|
||||
if (uploadMethod.useEarlyMapping)
|
||||
throw new IllegalArgumentException("UploadMethod signal that this should use Mapping instead of uploadBuffer!");
|
||||
vertexCount = vertCount;
|
||||
int bbSize = bb.limit()-bb.position();
|
||||
if (bbSize > maxExpensionSize)
|
||||
throw new IllegalArgumentException("maxExpensionSize is "+maxExpensionSize+" but buffer size is "+bbSize+"!");
|
||||
GLProxy.GL_LOGGER.debug("Uploading {} buffer with {} vertices.", new UnitBytes(bbSize), vertCount);
|
||||
// If size is zero, just ignore it.
|
||||
if (bbSize == 0) return;
|
||||
boolean useBuffStorage = uploadMethod.useBufferStorage;
|
||||
if (useBuffStorage != isBufferStorage) {
|
||||
_destroy();
|
||||
_create(useBuffStorage);
|
||||
}
|
||||
switch (uploadMethod) {
|
||||
case AUTO:
|
||||
throw new IllegalArgumentException("GpuUploadMethod AUTO must be resolved before call to uploadBuffer()!");
|
||||
case BUFFER_STORAGE:
|
||||
_uploadBufferStorage(bb);
|
||||
break;
|
||||
case DATA:
|
||||
_uploadData(bb);
|
||||
break;
|
||||
case SUB_DATA:
|
||||
_uploadSubData(bb, maxExpensionSize);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid GpuUploadMethod enum");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
if (this.id >= 0)
|
||||
{
|
||||
_destroy();
|
||||
if (count==0) ApiShared.LOGGER.info("All LodVerrtexBuffer is freed.");
|
||||
} else {
|
||||
ApiShared.LOGGER.error("LodVertexBuffer double close!");
|
||||
|
||||
}
|
||||
}
|
||||
private boolean isMapped = false;
|
||||
|
||||
public ByteBuffer mapBuffer(int targetSize, GpuUploadMethod uploadMethod, int maxExpensionSize)
|
||||
{
|
||||
if (targetSize == 0) throw new IllegalArgumentException("MapBuffer targetSize is 0!");
|
||||
if (!uploadMethod.useEarlyMapping) throw new IllegalStateException("Upload method must be one that use mappings in order to call mapBuffer!");
|
||||
if (isMapped) throw new IllegalStateException("Map Buffer called but buffer is already mapped!");
|
||||
boolean useBuffStorage = uploadMethod.useBufferStorage;
|
||||
if (useBuffStorage != isBufferStorage) {
|
||||
_destroy();
|
||||
_create(useBuffStorage);
|
||||
}
|
||||
|
||||
ByteBuffer vboBuffer;
|
||||
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, id);
|
||||
|
||||
if (size < targetSize || size > targetSize * BUFFER_EXPANSION_MULTIPLIER * BUFFER_EXPANSION_MULTIPLIER) {
|
||||
int newSize = (int) (targetSize * BUFFER_EXPANSION_MULTIPLIER);
|
||||
if (newSize > maxExpensionSize) newSize = maxExpensionSize;
|
||||
size = newSize;
|
||||
if (uploadMethod.useBufferStorage) {
|
||||
GL32.glDeleteBuffers(id);
|
||||
id = GL32.glGenBuffers();
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, id);
|
||||
GL44.glBufferStorage(GL32.GL_ARRAY_BUFFER, newSize, GL44.GL_MAP_WRITE_BIT);
|
||||
} else {
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, newSize, GL32.GL_STATIC_DRAW);
|
||||
}
|
||||
}
|
||||
|
||||
vboBuffer = GL32.glMapBufferRange(GL32.GL_ARRAY_BUFFER, 0, targetSize,
|
||||
GL32.GL_MAP_WRITE_BIT | GL32.GL_MAP_UNSYNCHRONIZED_BIT | GL32.GL_MAP_INVALIDATE_BUFFER_BIT);
|
||||
isMapped = true;
|
||||
return vboBuffer;
|
||||
}
|
||||
|
||||
public void unmapBuffer(GpuUploadMethod uploadMethod)
|
||||
{
|
||||
if (!uploadMethod.useEarlyMapping) throw new IllegalStateException("Upload method must be one that use mappings in order to call unmapBuffer!");
|
||||
if (!isMapped) throw new IllegalStateException("Unmap Buffer called but buffer is already not mapped!");
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, id);
|
||||
GL32.glUnmapBuffer(GL32.GL_ARRAY_BUFFER);
|
||||
isMapped = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (isBufferStorage ? "VertexBufferStorage" : "BufferStorage")+
|
||||
"[vboId:"+id+", size:"+size+", vertCount:"+vertexCount+(isMapped?", MAPPED" : "")+"]";
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU GPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.objects.opengl;
|
||||
|
||||
import com.seibel.lod.core.api.ApiShared;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import static org.lwjgl.opengl.GL11C.GL_UNSIGNED_INT;
|
||||
import static org.lwjgl.opengl.GL15.*;
|
||||
import static org.lwjgl.opengl.GL31.GL_COPY_WRITE_BUFFER;
|
||||
|
||||
/**
|
||||
* Represents a OpenGL Index Buffer Object.
|
||||
*
|
||||
* @author Cotex
|
||||
* @version 2022-4-13
|
||||
*/
|
||||
public class QuadIBO
|
||||
{
|
||||
/**
|
||||
* Datatype of the stored indices
|
||||
* (can be GL_UNSIGNED_INT, GL_UNSIGNED_SHORT, GL_UNSIGNED_BYTE)
|
||||
*/
|
||||
public int type;
|
||||
|
||||
/** OpenGL ID of this IBO object */
|
||||
int id;
|
||||
|
||||
/** Current capacity (in quads) */
|
||||
int currentQuadCapacity;
|
||||
|
||||
/** Global IBO object, used for sharing the IBO for any draw calls */
|
||||
public static QuadIBO GLOBAL = new QuadIBO();
|
||||
|
||||
|
||||
|
||||
public QuadIBO()
|
||||
{
|
||||
id = glGenBuffers();
|
||||
}
|
||||
|
||||
|
||||
/** Should only be called on a thread that has a OpenGL context. */
|
||||
public void resizeIfNecessary(int newQuadCapacity)
|
||||
{
|
||||
//If the requested capacity is less than or equal to current capacity, ignore
|
||||
if (newQuadCapacity <= currentQuadCapacity)
|
||||
return;
|
||||
|
||||
// create the new capacity bigger than necessary to prevent constant updates
|
||||
newQuadCapacity *= 1.5;
|
||||
ApiShared.LOGGER.info("Quad IBO Resizing from [" + currentQuadCapacity + "] to [" + newQuadCapacity + "]");
|
||||
|
||||
currentQuadCapacity = newQuadCapacity;
|
||||
|
||||
//TODO: DO DYNAMIC TYPES, just makes things more efficient
|
||||
type = GL_UNSIGNED_INT;
|
||||
int DT_SIZE = 4; //Datatype size (int: 4, short: 2, byte: 1)
|
||||
|
||||
glBindBuffer(GL_COPY_WRITE_BUFFER, id);
|
||||
//Resize the buffer
|
||||
glBufferData(GL_COPY_WRITE_BUFFER, (long) DT_SIZE * 6 * newQuadCapacity, GL_STATIC_DRAW);// 4L is datatype
|
||||
//Map and write the index data to the buffer
|
||||
long arrayPointer = nglMapBuffer(GL_COPY_WRITE_BUFFER, GL_WRITE_ONLY);
|
||||
for (int base = 0; base < newQuadCapacity; base++)
|
||||
{
|
||||
// Add the new quad's indices
|
||||
MemoryUtil.memPutInt(arrayPointer + (base * 6L * DT_SIZE + DT_SIZE * 0), (int) (base * 4 + 0));
|
||||
MemoryUtil.memPutInt(arrayPointer + (base * 6L * DT_SIZE + DT_SIZE * 1), (int) (base * 4 + 1));
|
||||
MemoryUtil.memPutInt(arrayPointer + (base * 6L * DT_SIZE + DT_SIZE * 2), (int) (base * 4 + 2));
|
||||
MemoryUtil.memPutInt(arrayPointer + (base * 6L * DT_SIZE + DT_SIZE * 3), (int) (base * 4 + 2));
|
||||
MemoryUtil.memPutInt(arrayPointer + (base * 6L * DT_SIZE + DT_SIZE * 4), (int) (base * 4 + 3));
|
||||
MemoryUtil.memPutInt(arrayPointer + (base * 6L * DT_SIZE + DT_SIZE * 5), (int) (base * 4 + 0));
|
||||
}
|
||||
glUnmapBuffer(GL_COPY_WRITE_BUFFER);
|
||||
}
|
||||
|
||||
/** Binds the IBO */
|
||||
public void bind()
|
||||
{
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);
|
||||
}
|
||||
|
||||
/** Unbinds the IBO */
|
||||
public void unbind()
|
||||
{
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,10 @@ import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.seibel.lod.core.api.ClientApi;
|
||||
import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodQuadBuilder;
|
||||
import com.seibel.lod.core.render.LodRenderer;
|
||||
import com.seibel.lod.core.render.objects.GLVertexBuffer;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import com.seibel.lod.core.api.ApiShared;
|
||||
@@ -42,16 +45,14 @@ import static com.seibel.lod.core.render.GLProxy.GL_LOGGER;
|
||||
public class SimpleRenderBuffer extends RenderBuffer
|
||||
{
|
||||
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
|
||||
private static final int FULL_SIZED_BUFFERS =
|
||||
LodBufferBuilderFactory.MAX_TRIANGLES_PER_BUFFER * LodUtil.LOD_VERTEX_FORMAT.getByteSize() * 3;
|
||||
private static final long MAX_BUFFER_UPLOAD_TIMEOUT_NANOSECONDS = 1_000_000;
|
||||
|
||||
LodVertexBuffer[] vbos;
|
||||
|
||||
GLVertexBuffer[] vbos;
|
||||
|
||||
// public void onReuse() {}
|
||||
|
||||
public SimpleRenderBuffer() {
|
||||
vbos = new LodVertexBuffer[0];
|
||||
vbos = new GLVertexBuffer[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,14 +75,17 @@ public class SimpleRenderBuffer extends RenderBuffer
|
||||
public boolean render(LodRenderProgram shaderProgram)
|
||||
{
|
||||
boolean hasRendered = false;
|
||||
for (LodVertexBuffer vbo : vbos) {
|
||||
for (GLVertexBuffer vbo : vbos) {
|
||||
if (vbo == null) continue;
|
||||
if (vbo.vertexCount == 0) continue;
|
||||
if (vbo.getVertexCount() == 0) continue;
|
||||
hasRendered = true;
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, vbo.id);
|
||||
shaderProgram.bindVertexBuffer(vbo.id);
|
||||
QuadIBO.GLOBAL.resizeIfNecessary(vbo.vertexCount/4);
|
||||
GL32.glDrawElements(GL32.GL_TRIANGLES, (vbo.vertexCount/4)*6, QuadIBO.GLOBAL.type, 0);
|
||||
vbo.bind();
|
||||
shaderProgram.bindVertexBuffer(vbo.getId());
|
||||
if (LodRenderer.ENABLE_IBO) {
|
||||
GL32.glDrawElements(GL32.GL_TRIANGLES, (vbo.getVertexCount()/4)*6, ClientApi.renderer.quadIBO.getType(), 0);
|
||||
} else {
|
||||
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, vbo.getVertexCount());
|
||||
}
|
||||
//LodRenderer.tickLogger.info("Vertex buffer: {}", vbo);
|
||||
}
|
||||
return hasRendered;
|
||||
@@ -92,14 +96,14 @@ public class SimpleRenderBuffer extends RenderBuffer
|
||||
{
|
||||
statsMap.incStat("RenderBuffers");
|
||||
statsMap.incStat("SimpleRenderBuffers");
|
||||
for (LodVertexBuffer b : vbos) {
|
||||
for (GLVertexBuffer b : vbos) {
|
||||
if (b == null) continue;
|
||||
statsMap.incStat("VBOs");
|
||||
if (b.size == FULL_SIZED_BUFFERS) {
|
||||
if (b.getSize() == LodBufferBuilderFactory.FULL_SIZED_BUFFER) {
|
||||
statsMap.incStat("FullsizedVBOs");
|
||||
}
|
||||
if (b.size == 0) GL_LOGGER.warn("VBO with size 0");
|
||||
statsMap.incBytesStat("TotalUsage", b.size);
|
||||
if (b.getSize() == 0) GL_LOGGER.warn("VBO with size 0");
|
||||
statsMap.incBytesStat("TotalUsage", b.getSize());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,8 +111,8 @@ public class SimpleRenderBuffer extends RenderBuffer
|
||||
public void close()
|
||||
{
|
||||
GLProxy.getInstance().recordOpenGlCall(() -> {
|
||||
for (LodVertexBuffer b : vbos) {
|
||||
b.close();
|
||||
for (GLVertexBuffer b : vbos) {
|
||||
b.destroy(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -122,10 +126,11 @@ public class SimpleRenderBuffer extends RenderBuffer
|
||||
Iterator<ByteBuffer> iter = builder.makeVertexBuffers();
|
||||
while (iter.hasNext()) {
|
||||
ByteBuffer bb = iter.next();
|
||||
LodVertexBuffer vbo = getOrMakeVbo(i++, method.useBufferStorage);
|
||||
GLVertexBuffer vbo = getOrMakeVbo(i++, method.useBufferStorage);
|
||||
int size = bb.limit() - bb.position();
|
||||
try {
|
||||
vbo.uploadBuffer(bb, size/LodUtil.LOD_VERTEX_FORMAT.getByteSize(), method, FULL_SIZED_BUFFERS);
|
||||
vbo.bind();
|
||||
vbo.uploadBuffer(bb, size/LodUtil.LOD_VERTEX_FORMAT.getByteSize(), method, LodBufferBuilderFactory.FULL_SIZED_BUFFER);
|
||||
} catch (Exception e) {
|
||||
vbos[i-1] = null;
|
||||
vbo.close();
|
||||
@@ -151,23 +156,23 @@ public class SimpleRenderBuffer extends RenderBuffer
|
||||
{
|
||||
resize(builder.getCurrentNeededVertexBufferCount());
|
||||
for (int i=0; i<vbos.length; i++) {
|
||||
if (vbos[i]==null) vbos[i] = new LodVertexBuffer(method.useBufferStorage);
|
||||
if (vbos[i]==null) vbos[i] = new GLVertexBuffer(method.useBufferStorage);
|
||||
}
|
||||
BufferFiller func = builder.makeBufferFiller(method);
|
||||
int i = 0;
|
||||
while (i < vbos.length && func.fill(vbos[i++])) {}
|
||||
}
|
||||
|
||||
private LodVertexBuffer getOrMakeVbo(int iIndex, boolean useBuffStorage) {
|
||||
private GLVertexBuffer getOrMakeVbo(int iIndex, boolean useBuffStorage) {
|
||||
if (vbos[iIndex] == null) {
|
||||
vbos[iIndex] = new LodVertexBuffer(useBuffStorage);
|
||||
vbos[iIndex] = new GLVertexBuffer(useBuffStorage);
|
||||
}
|
||||
return vbos[iIndex];
|
||||
}
|
||||
|
||||
private void resize(int size) {
|
||||
if (vbos.length != size) {
|
||||
LodVertexBuffer[] newVbos = new LodVertexBuffer[size];
|
||||
GLVertexBuffer[] newVbos = new GLVertexBuffer[size];
|
||||
if (vbos.length > size) {
|
||||
for (int i=size; i<vbos.length; i++) {
|
||||
if (vbos[i]!=null) vbos[i].close();
|
||||
@@ -178,7 +183,7 @@ public class SimpleRenderBuffer extends RenderBuffer
|
||||
newVbos[i] = vbos[i];
|
||||
vbos[i] = null;
|
||||
}
|
||||
for (LodVertexBuffer b : vbos) {
|
||||
for (GLVertexBuffer b : vbos) {
|
||||
if (b != null) throw new RuntimeException("LEAKING VBO!");
|
||||
}
|
||||
vbos = newVbos;
|
||||
|
||||
@@ -40,6 +40,8 @@ public class LodRenderProgram extends ShaderProgram {
|
||||
public final int modelOffsetUniform;
|
||||
public final int worldYOffsetUniform;
|
||||
|
||||
public final int mircoOffsetUniform;
|
||||
|
||||
public final int lightMapUniform;
|
||||
// Fog Uniforms
|
||||
public final int fogColorUniform;
|
||||
@@ -61,6 +63,7 @@ public class LodRenderProgram extends ShaderProgram {
|
||||
combinedMatUniform = getUniformLocation("combinedMatrix");
|
||||
modelOffsetUniform = getUniformLocation("modelOffset");
|
||||
worldYOffsetUniform = tryGetUniformLocation("worldYOffset");
|
||||
mircoOffsetUniform = getUniformLocation("mircoOffset");
|
||||
|
||||
lightMapUniform = getUniformLocation("lightMap");
|
||||
|
||||
@@ -81,9 +84,9 @@ public class LodRenderProgram extends ShaderProgram {
|
||||
vao = new VertexAttributePreGL43(); // also binds VertexAttribute
|
||||
vao.bind();
|
||||
// Now a pos+light.
|
||||
vao.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addUnsignedShortsPointer(4, false)); // 2+2+2+2
|
||||
vao.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addUnsignedShortsPointer(4, false, true)); // 2+2+2+2
|
||||
//vao.setVertexAttribute(0, posAttrib, VertexAttribute.VertexPointer.addVec3Pointer(false)); // 4+4+4
|
||||
vao.setVertexAttribute(0, 1, VertexAttribute.VertexPointer.addUnsignedBytesPointer(4, true)); // +4
|
||||
vao.setVertexAttribute(0, 1, VertexAttribute.VertexPointer.addUnsignedBytesPointer(4, true, false)); // +4
|
||||
//vao.setVertexAttribute(0, lightAttrib, VertexAttribute.VertexPointer.addUnsignedBytesPointer(2, false)); // +4 due to how it aligns
|
||||
try {
|
||||
vao.completeAndCheck(vertexByteCount);
|
||||
@@ -132,6 +135,7 @@ public class LodRenderProgram extends ShaderProgram {
|
||||
vanillaDrawDistance += 32; // Give it a 2 chunk boundary for near fog.
|
||||
// uniforms
|
||||
setUniform(combinedMatUniform, combinedMatrix);
|
||||
setUniform(mircoOffsetUniform, 0.005f); // 0.005 block offset
|
||||
|
||||
// setUniform(skyLightUniform, skyLight);
|
||||
setUniform(lightMapUniform, lightmapBindPoint);
|
||||
|
||||
@@ -26,10 +26,9 @@ import java.util.concurrent.TimeUnit;
|
||||
import com.seibel.lod.core.api.ApiShared;
|
||||
import com.seibel.lod.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.lod.core.logging.ConfigBasedSpamLogger;
|
||||
import com.seibel.lod.core.logging.SpamReducedLogger;
|
||||
import com.seibel.lod.core.objects.BoolType;
|
||||
import com.seibel.lod.core.objects.Pos2D;
|
||||
import com.seibel.lod.core.objects.opengl.QuadIBO;
|
||||
import com.seibel.lod.core.render.objects.QuadElementBuffer;
|
||||
import com.seibel.lod.core.render.objects.GLState;
|
||||
import com.seibel.lod.core.util.*;
|
||||
import com.seibel.lod.core.util.gridList.*;
|
||||
@@ -47,7 +46,6 @@ import com.seibel.lod.core.objects.math.Mat4f;
|
||||
import com.seibel.lod.core.objects.math.Vec3d;
|
||||
import com.seibel.lod.core.objects.math.Vec3f;
|
||||
import com.seibel.lod.core.objects.opengl.RenderRegion;
|
||||
import com.seibel.lod.core.render.objects.LightmapTexture;
|
||||
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
@@ -73,6 +71,8 @@ public class LodRenderer
|
||||
public static final boolean ENABLE_DRAW_LAG_SPIKE_LOGGING = false;
|
||||
public static final boolean ENABLE_DUMP_GL_STATE = true;
|
||||
public static final long DRAW_LAG_SPIKE_THRESHOLD_NS = TimeUnit.NANOSECONDS.convert(20, TimeUnit.MILLISECONDS);
|
||||
|
||||
public static final boolean ENABLE_IBO = true;
|
||||
|
||||
public static class LagSpikeCatcher {
|
||||
|
||||
@@ -108,6 +108,7 @@ public class LodRenderer
|
||||
|
||||
/** This is used to determine if the LODs should be regenerated */
|
||||
private AbstractBlockPosWrapper lastUpdatedPos = null;
|
||||
public QuadElementBuffer quadIBO = null;
|
||||
|
||||
// these variables are used to determine if the buffers should be rebuilt
|
||||
private int prevRenderDistance = 0;
|
||||
@@ -319,12 +320,15 @@ public class LodRenderer
|
||||
LagSpikeCatcher drawFillLightmap = new LagSpikeCatcher();
|
||||
ILightMapWrapper lightmap = MC_RENDER.getLightmapWrapper();
|
||||
lightmap.bind();
|
||||
|
||||
QuadIBO.GLOBAL.bind();
|
||||
|
||||
|
||||
if (ENABLE_IBO) quadIBO.bind();
|
||||
|
||||
//lightmapTexture.fillData(MC_RENDER.getLightmapTextureWidth(), MC_RENDER.getLightmapTextureHeight(), MC_RENDER.getLightmapPixels());
|
||||
drawFillLightmap.end("drawFillLightmap");
|
||||
drawFillData.end("DrawFillData");
|
||||
//GL32.glEnable( GL32.GL_POLYGON_OFFSET_FILL );
|
||||
//GL32.glPolygonOffset( 1f, 1f );
|
||||
|
||||
//===========//
|
||||
// rendering //
|
||||
//===========//
|
||||
@@ -376,7 +380,7 @@ public class LodRenderer
|
||||
profiler.popPush("LOD cleanup");
|
||||
LagSpikeCatcher drawCleanup = new LagSpikeCatcher();
|
||||
lightmap.unbind();
|
||||
QuadIBO.GLOBAL.unbind();
|
||||
if (ENABLE_IBO) quadIBO.unbind();
|
||||
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, 0);
|
||||
|
||||
@@ -410,6 +414,10 @@ public class LodRenderer
|
||||
EVENT_LOGGER.info("Setting up renderer");
|
||||
isSetupComplete = true;
|
||||
shaderProgram = new LodRenderProgram(LodFogConfig.generateFogConfig());
|
||||
if (ENABLE_IBO) {
|
||||
quadIBO = new QuadElementBuffer();
|
||||
quadIBO.reserve(LodBufferBuilderFactory.MAX_QUADS_PER_BUFFER);
|
||||
}
|
||||
EVENT_LOGGER.info("Renderer setup complete");
|
||||
}
|
||||
|
||||
@@ -492,6 +500,7 @@ public class LodRenderer
|
||||
isSetupComplete = false;
|
||||
EVENT_LOGGER.info("Renderer Cleanup Started");
|
||||
shaderProgram.free();
|
||||
if (quadIBO != null) quadIBO.destroy(false);
|
||||
EVENT_LOGGER.info("Renderer Cleanup Complete");
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||
import com.seibel.lod.core.logging.ConfigBasedLogger;
|
||||
|
||||
import com.seibel.lod.core.logging.ConfigBasedSpamLogger;
|
||||
import com.seibel.lod.core.objects.opengl.LodVertexBuffer;
|
||||
import com.seibel.lod.core.render.objects.GLVertexBuffer;
|
||||
import com.seibel.lod.core.render.objects.GLState;
|
||||
import com.seibel.lod.core.render.objects.ShaderProgram;
|
||||
import com.seibel.lod.core.render.objects.VertexAttribute;
|
||||
@@ -48,8 +48,8 @@ public class RenderSystemTest {
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonHandler.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
ShaderProgram basicShader;
|
||||
LodVertexBuffer sameContextBuffer;
|
||||
LodVertexBuffer sharedContextBuffer;
|
||||
GLVertexBuffer sameContextBuffer;
|
||||
GLVertexBuffer sharedContextBuffer;
|
||||
VertexAttribute va;
|
||||
boolean init = false;
|
||||
|
||||
@@ -77,8 +77,8 @@ public class RenderSystemTest {
|
||||
-0.2f, 0.2f, 0.0f, 1.0f, 1.0f, 1.0f
|
||||
};
|
||||
|
||||
private static LodVertexBuffer createTextingBuffer() {
|
||||
LodVertexBuffer vbo = new LodVertexBuffer(false);
|
||||
private static GLVertexBuffer createTextingBuffer() {
|
||||
GLVertexBuffer vbo = new GLVertexBuffer(false);
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect(vertices.length * Float.BYTES);
|
||||
// Fill buffer with the vertices.
|
||||
buffer = buffer.order(ByteOrder.nativeOrder());
|
||||
@@ -113,12 +113,12 @@ public class RenderSystemTest {
|
||||
|
||||
// Switch between the two buffers per second
|
||||
if (System.currentTimeMillis() % 2000 < 1000) {
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, sameContextBuffer.id);
|
||||
va.bindBufferToAllBindingPoint(sameContextBuffer.id);
|
||||
sameContextBuffer.bind();
|
||||
va.bindBufferToAllBindingPoint(sameContextBuffer.getId());
|
||||
spamLogger.debug("same context buffer");
|
||||
} else {
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, sharedContextBuffer.id);
|
||||
va.bindBufferToAllBindingPoint(sharedContextBuffer.id);
|
||||
sameContextBuffer.bind();
|
||||
va.bindBufferToAllBindingPoint(sharedContextBuffer.getId());
|
||||
spamLogger.debug("shared context buffer");
|
||||
}
|
||||
// Render the square
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
package com.seibel.lod.core.render.objects;
|
||||
|
||||
import com.seibel.lod.core.api.ApiShared;
|
||||
import com.seibel.lod.core.enums.config.GpuUploadMethod;
|
||||
import com.seibel.lod.core.enums.rendering.GLProxyContext;
|
||||
import com.seibel.lod.core.render.GLProxy;
|
||||
import com.seibel.lod.core.util.UnitBytes;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.opengl.GL44;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class GLBuffer implements AutoCloseable {
|
||||
public static final double BUFFER_EXPANSION_MULTIPLIER = 1.3;
|
||||
public static final double BUFFER_SHRINK_TRIGGER = BUFFER_EXPANSION_MULTIPLIER * BUFFER_EXPANSION_MULTIPLIER;
|
||||
public static int count = 0;
|
||||
protected int id;
|
||||
public final int getId() {
|
||||
return id;
|
||||
}
|
||||
protected int size = 0;
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
protected boolean bufferStorage;
|
||||
public final boolean isBufferStorage() {
|
||||
return bufferStorage;
|
||||
}
|
||||
protected boolean isMapped = false;
|
||||
|
||||
public GLBuffer(boolean isBufferStorage)
|
||||
{
|
||||
create(isBufferStorage);
|
||||
}
|
||||
|
||||
// Should be override by subclasses
|
||||
public int getBufferBindingTarget() {
|
||||
return GL32.GL_COPY_READ_BUFFER;
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
GL32.glBindBuffer(getBufferBindingTarget(), id);
|
||||
}
|
||||
public void unbind() {
|
||||
GL32.glBindBuffer(getBufferBindingTarget(), 0);
|
||||
}
|
||||
|
||||
protected void create(boolean asBufferStorage) {
|
||||
if (GLProxy.getInstance().getGlContext() == GLProxyContext.NONE)
|
||||
throw new IllegalStateException("Thread [" +Thread.currentThread().getName() + "] tried to create a GLBuffer outside a OpenGL context.");
|
||||
this.id = GL32.glGenBuffers();
|
||||
this.bufferStorage = asBufferStorage;
|
||||
count++;
|
||||
}
|
||||
|
||||
protected void destroy(boolean async) {
|
||||
if (this.id == 0) {
|
||||
ApiShared.LOGGER.warn("Buffer double close!");
|
||||
return;
|
||||
}
|
||||
if (async && GLProxy.getInstance().getGlContext() != GLProxyContext.PROXY_WORKER) {
|
||||
GLProxy.getInstance().recordOpenGlCall(() -> destroy((false)));
|
||||
} else {
|
||||
GL32.glDeleteBuffers(id);
|
||||
}
|
||||
id = 0;
|
||||
size = 0;
|
||||
count--;
|
||||
if (count==0) ApiShared.LOGGER.info("All GLBuffer is freed.");
|
||||
}
|
||||
|
||||
// Requires already binded
|
||||
protected void uploadBufferStorage(ByteBuffer bb, int bufferStorageHint) {
|
||||
if (!bufferStorage) throw new IllegalStateException("Buffer is not bufferStorage but its trying to use bufferStorage upload method!");
|
||||
int bbSize = bb.limit() - bb.position();
|
||||
destroy(false);
|
||||
create(true);
|
||||
bind();
|
||||
GL44.glBufferStorage(getBufferBindingTarget(), bb, bufferStorageHint);
|
||||
size = bbSize;
|
||||
}
|
||||
|
||||
// Requires already binded
|
||||
protected void uploadBufferData(ByteBuffer bb, int bufferDataHint) {
|
||||
if (bufferStorage) throw new IllegalStateException("Buffer is bufferStorage but its trying to use Data upload method!");
|
||||
int bbSize = bb.limit() - bb.position();
|
||||
GL32.glBufferData(getBufferBindingTarget(), bb, bufferDataHint);
|
||||
size = bbSize;
|
||||
}
|
||||
|
||||
// Requires already binded
|
||||
protected void uploadSubData(ByteBuffer bb, int maxExpansionSize, int bufferDataHint) {
|
||||
if (bufferStorage) throw new IllegalStateException("Buffer is bufferStorage but its trying to use SubData upload method!");
|
||||
int bbSize = bb.limit() - bb.position();
|
||||
if (size < bbSize || size > bbSize * BUFFER_SHRINK_TRIGGER) {
|
||||
int newSize = (int) (bbSize * BUFFER_EXPANSION_MULTIPLIER);
|
||||
if (newSize > maxExpansionSize) newSize = maxExpansionSize;
|
||||
GL32.glBufferData(getBufferBindingTarget(), newSize, bufferDataHint);
|
||||
size = newSize;
|
||||
}
|
||||
GL32.glBufferSubData(getBufferBindingTarget(), 0, bb);
|
||||
}
|
||||
|
||||
// Requires already binded
|
||||
public void uploadBuffer(ByteBuffer bb, GpuUploadMethod uploadMethod, int maxExpansionSize, int bufferHint) {
|
||||
if (uploadMethod.useEarlyMapping)
|
||||
throw new IllegalArgumentException("UploadMethod signal that this should use Mapping instead of uploadBuffer!");
|
||||
int bbSize = bb.limit()-bb.position();
|
||||
if (bbSize > maxExpansionSize)
|
||||
throw new IllegalArgumentException("maxExpansionSize is "+maxExpansionSize+" but buffer size is "+bbSize+"!");
|
||||
GLProxy.GL_LOGGER.debug("Uploading buffer with {}.", new UnitBytes(bbSize));
|
||||
// If size is zero, just ignore it.
|
||||
if (bbSize == 0) return;
|
||||
boolean useBuffStorage = uploadMethod.useBufferStorage;
|
||||
if (useBuffStorage != bufferStorage) {
|
||||
destroy(false);
|
||||
create(useBuffStorage);
|
||||
bind();
|
||||
}
|
||||
switch (uploadMethod) {
|
||||
case AUTO:
|
||||
throw new IllegalArgumentException("GpuUploadMethod AUTO must be resolved before call to uploadBuffer()!");
|
||||
case BUFFER_STORAGE:
|
||||
uploadBufferStorage(bb, bufferHint);
|
||||
break;
|
||||
case DATA:
|
||||
uploadBufferData(bb, bufferHint);
|
||||
break;
|
||||
case SUB_DATA:
|
||||
uploadSubData(bb, maxExpansionSize, bufferHint);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid GpuUploadMethod enum");
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuffer mapBuffer(int targetSize, GpuUploadMethod uploadMethod, int maxExpensionSize, int bufferHint, int mapFlags) {
|
||||
if (targetSize == 0) throw new IllegalArgumentException("MapBuffer targetSize is 0!");
|
||||
if (!uploadMethod.useEarlyMapping) throw new IllegalStateException("Upload method must be one that use mappings in order to call mapBuffer!");
|
||||
if (isMapped) throw new IllegalStateException("Map Buffer called but buffer is already mapped!");
|
||||
boolean useBuffStorage = uploadMethod.useBufferStorage;
|
||||
if (useBuffStorage != bufferStorage) {
|
||||
destroy(false);
|
||||
create(useBuffStorage);
|
||||
}
|
||||
bind();
|
||||
ByteBuffer vboBuffer;
|
||||
|
||||
if (size < targetSize || size > targetSize * BUFFER_SHRINK_TRIGGER) {
|
||||
int newSize = (int) (targetSize * BUFFER_EXPANSION_MULTIPLIER);
|
||||
if (newSize > maxExpensionSize) newSize = maxExpensionSize;
|
||||
size = newSize;
|
||||
if (bufferStorage) {
|
||||
GL32.glDeleteBuffers(id);
|
||||
id = GL32.glGenBuffers();
|
||||
GL32.glBindBuffer(getBufferBindingTarget(), id);
|
||||
GL44.glBufferStorage(getBufferBindingTarget(), newSize, bufferHint);
|
||||
} else {
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, newSize, bufferHint);
|
||||
}
|
||||
}
|
||||
|
||||
vboBuffer = GL32.glMapBufferRange(GL32.GL_ARRAY_BUFFER, 0, targetSize, mapFlags);
|
||||
isMapped = true;
|
||||
return vboBuffer;
|
||||
}
|
||||
|
||||
// Requires already binded
|
||||
public void unmapBuffer()
|
||||
{
|
||||
if (!isMapped) throw new IllegalStateException("Unmap Buffer called but buffer is already not mapped!");
|
||||
bind();
|
||||
GL32.glUnmapBuffer(getBufferBindingTarget());
|
||||
isMapped = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
destroy(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (bufferStorage ? "" : "Static-")+ getClass().getSimpleName() +
|
||||
"[id:"+id+",size:"+size+(isMapped?",MAPPED" : "")+"]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU GPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.render.objects;
|
||||
|
||||
import com.seibel.lod.core.enums.config.GpuUploadMethod;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* This is a container for a OpenGL
|
||||
* VBO (Vertex Buffer Object).
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-20-2021
|
||||
*/
|
||||
public class GLElementBuffer extends GLBuffer
|
||||
{
|
||||
/**
|
||||
* When uploading to a buffer that is too small, recreate it this many times
|
||||
* bigger than the upload payload
|
||||
*/
|
||||
protected int indicesCount = 0;
|
||||
public int getIndicesCount() { return indicesCount; }
|
||||
protected int type = GL32.GL_UNSIGNED_INT;
|
||||
public int getType() { return type; }
|
||||
|
||||
public GLElementBuffer(boolean isBufferStorage)
|
||||
{
|
||||
super(isBufferStorage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy(boolean async) {
|
||||
super.destroy(async);
|
||||
indicesCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBufferBindingTarget() {
|
||||
return GL32.GL_ELEMENT_ARRAY_BUFFER;
|
||||
}
|
||||
}
|
||||
@@ -204,4 +204,24 @@ public class GLEnums {
|
||||
|
||||
return "GL_UNKNOWN(" + glEnum + ")";
|
||||
}
|
||||
|
||||
public static int getTypeSize(int glTypeEnum) {
|
||||
switch (glTypeEnum) {
|
||||
case GL_BYTE:
|
||||
case GL_UNSIGNED_BYTE:
|
||||
return 1;
|
||||
case GL_SHORT:
|
||||
case GL_UNSIGNED_SHORT:
|
||||
return 2;
|
||||
case GL_INT:
|
||||
case GL_UNSIGNED_INT:
|
||||
return 4;
|
||||
case GL_FLOAT:
|
||||
return 4;
|
||||
case GL_DOUBLE:
|
||||
return 8;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown type enum: " + getString(glTypeEnum));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ public class GLState {
|
||||
public int prog;
|
||||
public int vao;
|
||||
public int vbo;
|
||||
public int ebo;
|
||||
public int fbo;
|
||||
public int text;
|
||||
public int activeTex;
|
||||
@@ -48,6 +49,7 @@ public class GLState {
|
||||
prog = GL32.glGetInteger(GL32.GL_CURRENT_PROGRAM);
|
||||
vao = GL32.glGetInteger(GL32.GL_VERTEX_ARRAY_BINDING);
|
||||
vbo = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING);
|
||||
ebo = GL32.glGetInteger(GL32.GL_ELEMENT_ARRAY_BUFFER_BINDING);
|
||||
fbo = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING);
|
||||
text = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
|
||||
activeTex = GL32.glGetInteger(GL32.GL_ACTIVE_TEXTURE);
|
||||
@@ -72,7 +74,7 @@ public class GLState {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GLState{" + "prog=" + prog + ", vao=" + vao + ", vbo=" + vbo + ", fbo=" + fbo +
|
||||
return "GLState{" + "prog=" + prog + ", vao=" + vao + ", vbo=" + vbo + ", ebo=" + ebo + ", fbo=" + fbo +
|
||||
", text=" + GLEnums.getString(text) + "@"+activeTex+", text0=" + GLEnums.getString(text0) +
|
||||
", blend=" + blend + ", blendMode=" + GLEnums.getString(blendSrc) + "," + GLEnums.getString(blendDst) +
|
||||
", depth=" + depth +
|
||||
@@ -96,6 +98,7 @@ public class GLState {
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, text);
|
||||
GL32.glBindVertexArray(vao);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, vbo);
|
||||
GL32.glBindBuffer(GL32.GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||
|
||||
GL32.glBlendFunc(blendSrc, blendDst);
|
||||
if (depth) {
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU GPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.render.objects;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import com.seibel.lod.core.enums.config.GpuUploadMethod;
|
||||
|
||||
/**
|
||||
* This is a container for a OpenGL
|
||||
* VBO (Vertex Buffer Object).
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-20-2021
|
||||
*/
|
||||
public class GLVertexBuffer extends GLBuffer
|
||||
{
|
||||
/**
|
||||
* When uploading to a buffer that is too small, recreate it this many times
|
||||
* bigger than the upload payload
|
||||
*/
|
||||
protected int vertexCount = 0;
|
||||
public int getVertexCount() { return vertexCount; }
|
||||
// FIXME: This setter is needed for premapping buffer to manually set the vertexCount. Fix this.
|
||||
public void setVertexCount(int vertexCount) { this.vertexCount = vertexCount; }
|
||||
|
||||
public GLVertexBuffer(boolean isBufferStorage)
|
||||
{
|
||||
super(isBufferStorage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy(boolean async) {
|
||||
super.destroy(async);
|
||||
vertexCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBufferBindingTarget() {
|
||||
return GL32.GL_ARRAY_BUFFER;
|
||||
}
|
||||
|
||||
public void uploadBuffer(ByteBuffer bb, int vertCount, GpuUploadMethod uploadMethod, int maxExpensionSize) {
|
||||
if (vertCount < 0) throw new IllegalArgumentException("VertCount is negative!");
|
||||
// If size is zero, just ignore it.
|
||||
if (bb.limit()-bb.position() != 0) {
|
||||
boolean useBuffStorage = uploadMethod.useBufferStorage;
|
||||
super.uploadBuffer(bb, uploadMethod, maxExpensionSize, useBuffStorage ? 0 : GL32.GL_STATIC_DRAW);
|
||||
}
|
||||
vertexCount = vertCount;
|
||||
}
|
||||
|
||||
public ByteBuffer mapBuffer(int targetSize, GpuUploadMethod uploadMethod, int maxExpensionSize)
|
||||
{
|
||||
return super.mapBuffer(targetSize, uploadMethod, maxExpensionSize,
|
||||
uploadMethod.useBufferStorage ? GL32.GL_MAP_WRITE_BIT :
|
||||
uploadMethod.useEarlyMapping ? GL32.GL_DYNAMIC_DRAW : GL32.GL_STATIC_DRAW,
|
||||
GL32.GL_MAP_WRITE_BIT | GL32.GL_MAP_UNSYNCHRONIZED_BIT | GL32.GL_MAP_INVALIDATE_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.seibel.lod.core.render.objects;
|
||||
|
||||
import com.seibel.lod.core.api.ApiShared;
|
||||
import com.seibel.lod.core.enums.config.GpuUploadMethod;
|
||||
import com.seibel.lod.core.render.GLProxy;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class QuadElementBuffer extends GLElementBuffer {
|
||||
|
||||
public QuadElementBuffer() {
|
||||
super(GLProxy.getInstance().bufferStorageSupported);
|
||||
}
|
||||
|
||||
public int getCapacity() {
|
||||
return super.getSize() / GLEnums.getTypeSize(getType());
|
||||
}
|
||||
|
||||
private static void buildBufferByte(int quadCount, ByteBuffer buffer) {
|
||||
for (int i = 0; i < quadCount; i++) {
|
||||
int vIndex = i * 4;
|
||||
// First triangle
|
||||
buffer.put((byte) (vIndex));
|
||||
buffer.put((byte) (vIndex + 1));
|
||||
buffer.put((byte) (vIndex + 2));
|
||||
// Second triangle
|
||||
buffer.put((byte) (vIndex + 2));
|
||||
buffer.put((byte) (vIndex + 3));
|
||||
buffer.put((byte) (vIndex));
|
||||
}
|
||||
if (buffer.hasRemaining()) {
|
||||
throw new IllegalStateException("QuadElementBuffer is not full somehow after building");
|
||||
}
|
||||
buffer.rewind();
|
||||
}
|
||||
private static void buildBufferShort(int quadCount, ByteBuffer buffer) {
|
||||
for (int i = 0; i < quadCount; i++) {
|
||||
int vIndex = i * 4;
|
||||
// First triangle
|
||||
buffer.putShort((short) (vIndex));
|
||||
buffer.putShort((short) (vIndex + 1));
|
||||
buffer.putShort((short) (vIndex + 2));
|
||||
// Second triangle
|
||||
buffer.putShort((short) (vIndex + 2));
|
||||
buffer.putShort((short) (vIndex + 3));
|
||||
buffer.putShort((short) (vIndex));
|
||||
}
|
||||
if (buffer.hasRemaining()) {
|
||||
throw new IllegalStateException("QuadElementBuffer is not full somehow after building");
|
||||
}
|
||||
buffer.rewind();
|
||||
}
|
||||
private static void buildBufferInt(int quadCount, ByteBuffer buffer) {
|
||||
for (int i = 0; i < quadCount; i++) {
|
||||
int vIndex = i * 4;
|
||||
// First triangle
|
||||
buffer.putInt(vIndex);
|
||||
buffer.putInt(vIndex + 1);
|
||||
buffer.putInt(vIndex + 2);
|
||||
// Second triangle
|
||||
buffer.putInt(vIndex + 2);
|
||||
buffer.putInt(vIndex + 3);
|
||||
buffer.putInt(vIndex);
|
||||
}
|
||||
if (buffer.hasRemaining()) {
|
||||
throw new IllegalStateException("QuadElementBuffer is not full somehow after building");
|
||||
}
|
||||
buffer.rewind();
|
||||
}
|
||||
|
||||
private static void buildBuffer(int quadCount, ByteBuffer buffer, int type) {
|
||||
switch (type) {
|
||||
case GL32.GL_UNSIGNED_BYTE:
|
||||
buildBufferByte(quadCount, buffer);
|
||||
break;
|
||||
case GL32.GL_UNSIGNED_SHORT:
|
||||
buildBufferShort(quadCount, buffer);
|
||||
break;
|
||||
case GL32.GL_UNSIGNED_INT:
|
||||
buildBufferInt(quadCount, buffer);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public void reserve(int quadCount) {
|
||||
if (quadCount < 0) {
|
||||
throw new IllegalArgumentException("quadCount must be greater than 0");
|
||||
}
|
||||
indicesCount = quadCount * 6; // 2 triangles per quad
|
||||
if (indicesCount >= getCapacity() && indicesCount < getCapacity() * BUFFER_SHRINK_TRIGGER) {
|
||||
return;
|
||||
}
|
||||
int vertexCount = quadCount * 4; // 4 vertices per quad
|
||||
GLProxy gl = GLProxy.getInstance();
|
||||
|
||||
if (vertexCount < 255) { // Reserve 1 for the reset index
|
||||
type = GL32.GL_UNSIGNED_BYTE;
|
||||
} else if (vertexCount < 65535) { // Reserve 1 for the reset index
|
||||
type = GL32.GL_UNSIGNED_SHORT;
|
||||
} else {
|
||||
type = GL32.GL_UNSIGNED_INT;
|
||||
}
|
||||
ApiShared.LOGGER.info("Quad IBO Resizing from [" + getCapacity() + "] to [" + quadCount + "]" + " with type: " +
|
||||
GLEnums.getString(type));
|
||||
|
||||
ByteBuffer buffer;
|
||||
if (!gl.bufferStorageSupported) {
|
||||
bind();
|
||||
buffer = super.mapBuffer(indicesCount * GLEnums.getTypeSize(type), GpuUploadMethod.BUFFER_MAPPING,
|
||||
indicesCount * GLEnums.getTypeSize(type), GL32.GL_STATIC_DRAW,
|
||||
GL32.GL_MAP_WRITE_BIT | GL32.GL_MAP_INVALIDATE_BUFFER_BIT | GL32.GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
buildBuffer(quadCount, buffer, type);
|
||||
super.unmapBuffer();
|
||||
} else {
|
||||
buffer = ByteBuffer.allocateDirect(indicesCount * GLEnums.getTypeSize(type)).order(ByteOrder.nativeOrder());
|
||||
buildBuffer(quadCount, buffer, type);
|
||||
bind();
|
||||
super.uploadBuffer(buffer, GpuUploadMethod.BUFFER_STORAGE,
|
||||
indicesCount * GLEnums.getTypeSize(type), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,11 +31,16 @@ public abstract class VertexAttribute {
|
||||
public final int glType;
|
||||
public final boolean normalized;
|
||||
public final int byteSize;
|
||||
public VertexPointer(int elementCount, int glType, boolean normalized, int byteSize) {
|
||||
public final boolean useInteger;
|
||||
public VertexPointer(int elementCount, int glType, boolean normalized, int byteSize, boolean useInteger) {
|
||||
this.elementCount = elementCount;
|
||||
this.glType = glType;
|
||||
this.normalized = normalized;
|
||||
this.byteSize = byteSize;
|
||||
this.useInteger = useInteger;
|
||||
}
|
||||
public VertexPointer(int elementCount, int glType, boolean normalized, int byteSize) {
|
||||
this(elementCount, glType, normalized, byteSize, false);
|
||||
}
|
||||
private static int _align(int bytes) {
|
||||
return LodUtil.ceilDiv(bytes, 4)*4;
|
||||
@@ -53,26 +58,29 @@ public abstract class VertexAttribute {
|
||||
public static VertexPointer addVec4Pointer(boolean normalized) {
|
||||
return new VertexPointer(4, GL32.GL_FLOAT, normalized, 16);
|
||||
}
|
||||
public static VertexPointer addUnsignedBytePointer(boolean normalized) {
|
||||
return new VertexPointer(1, GL32.GL_UNSIGNED_BYTE, normalized, 4); // Always aligned to 4 bytes
|
||||
public static VertexPointer addUnsignedBytePointer(boolean normalized, boolean useInteger) {
|
||||
return new VertexPointer(1, GL32.GL_UNSIGNED_BYTE, normalized, 4, useInteger); // Always aligned to 4 bytes
|
||||
}
|
||||
public static VertexPointer addUnsignedBytesPointer(int elementCount, boolean normalized) {
|
||||
return new VertexPointer(elementCount, GL32.GL_UNSIGNED_BYTE, normalized, _align(elementCount)); // aligned to 4 bytes
|
||||
public static VertexPointer addUnsignedBytesPointer(int elementCount, boolean normalized, boolean useInteger) {
|
||||
return new VertexPointer(elementCount, GL32.GL_UNSIGNED_BYTE, normalized, _align(elementCount), useInteger); // aligned to 4 bytes
|
||||
}
|
||||
public static VertexPointer addUnsignedShortsPointer(int elementCount, boolean normalized) {
|
||||
return new VertexPointer(elementCount, GL32.GL_UNSIGNED_SHORT, normalized, _align(elementCount*2));
|
||||
public static VertexPointer addUnsignedShortsPointer(int elementCount, boolean normalized, boolean useInteger) {
|
||||
return new VertexPointer(elementCount, GL32.GL_UNSIGNED_SHORT, normalized, _align(elementCount*2), useInteger);
|
||||
}
|
||||
public static VertexPointer addIntPointer(boolean normalized) {
|
||||
return new VertexPointer(1, GL32.GL_INT, normalized, 4);
|
||||
public static VertexPointer addShortsPointer(int elementCount, boolean normalized, boolean useInteger) {
|
||||
return new VertexPointer(elementCount, GL32.GL_SHORT, normalized, _align(elementCount*2), useInteger);
|
||||
}
|
||||
public static VertexPointer addIvec2Pointer(boolean normalized) {
|
||||
return new VertexPointer(2, GL32.GL_INT, normalized, 8);
|
||||
public static VertexPointer addIntPointer(boolean normalized, boolean useInteger) {
|
||||
return new VertexPointer(1, GL32.GL_INT, normalized, 4, useInteger);
|
||||
}
|
||||
public static VertexPointer addIvec3Pointer(boolean normalized) {
|
||||
return new VertexPointer(3, GL32.GL_INT, normalized, 12);
|
||||
public static VertexPointer addIvec2Pointer(boolean normalized, boolean useInteger) {
|
||||
return new VertexPointer(2, GL32.GL_INT, normalized, 8, useInteger);
|
||||
}
|
||||
public static VertexPointer addIvec4Pointer(boolean normalized) {
|
||||
return new VertexPointer(4, GL32.GL_INT, normalized, 16);
|
||||
public static VertexPointer addIvec3Pointer(boolean normalized, boolean useInteger) {
|
||||
return new VertexPointer(3, GL32.GL_INT, normalized, 12, useInteger);
|
||||
}
|
||||
public static VertexPointer addIvec4Pointer(boolean normalized, boolean useInteger) {
|
||||
return new VertexPointer(4, GL32.GL_INT, normalized, 16, useInteger);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,10 @@ public final class VertexAttributePostGL43 extends VertexAttribute {
|
||||
@Override
|
||||
// Requires VertexAttribute binded
|
||||
public void setVertexAttribute(int bindingPoint, int attributeIndex, VertexPointer attribute) {
|
||||
GL43.glVertexAttribFormat(attributeIndex, attribute.elementCount, attribute.glType,
|
||||
if (attribute.useInteger)
|
||||
GL43.glVertexAttribIFormat(attributeIndex, attribute.elementCount, attribute.glType, strideSize);
|
||||
else
|
||||
GL43.glVertexAttribFormat(attributeIndex, attribute.elementCount, attribute.glType,
|
||||
attribute.normalized, strideSize); // Here strideSize is new attrib offset
|
||||
strideSize += attribute.byteSize;
|
||||
if (numberOfBindingPoints <= bindingPoint) numberOfBindingPoints = bindingPoint+1;
|
||||
|
||||
@@ -59,7 +59,10 @@ public final class VertexAttributePreGL43 extends VertexAttribute {
|
||||
for (int i=0; i< pointers.length; i++) {
|
||||
VertexPointer pointer = pointers[i];
|
||||
if (pointer==null) continue;
|
||||
GL32.glVertexAttribPointer(i, pointer.elementCount, pointer.glType,
|
||||
if (pointer.useInteger)
|
||||
GL32.glVertexAttribIPointer(i, pointer.elementCount, pointer.glType,
|
||||
strideSize, pointersOffset[i]);
|
||||
else GL32.glVertexAttribPointer(i, pointer.elementCount, pointer.glType,
|
||||
pointer.normalized, strideSize, pointersOffset[i]);
|
||||
}
|
||||
}
|
||||
@@ -77,7 +80,10 @@ public final class VertexAttributePreGL43 extends VertexAttribute {
|
||||
VertexPointer pointer = pointers[j];
|
||||
if (pointer == null)
|
||||
continue;
|
||||
GL32.glVertexAttribPointer(j, pointer.elementCount, pointer.glType,
|
||||
if (pointer.useInteger)
|
||||
GL32.glVertexAttribIPointer(j, pointer.elementCount, pointer.glType,
|
||||
strideSize, pointersOffset[j]);
|
||||
else GL32.glVertexAttribPointer(j, pointer.elementCount, pointer.glType,
|
||||
pointer.normalized, strideSize, pointersOffset[j]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#version 150 core
|
||||
|
||||
in vec4 vPosition;
|
||||
in uvec4 vPosition;
|
||||
in vec4 color;
|
||||
|
||||
out vec4 vertexColor;
|
||||
@@ -13,6 +13,7 @@ uniform float worldYOffset;
|
||||
|
||||
uniform int worldSkyLight;
|
||||
uniform sampler2D lightMap;
|
||||
uniform float mircoOffset;
|
||||
|
||||
|
||||
/**
|
||||
@@ -27,11 +28,28 @@ uniform sampler2D lightMap;
|
||||
void main()
|
||||
{
|
||||
vertexWorldPos = vPosition.xyz + modelOffset;
|
||||
|
||||
vertexYPos = vPosition.y + worldYOffset;
|
||||
|
||||
float light2 = (mod(vPosition.a, 16)+0.5) / 16.0;
|
||||
float light = (floor(vPosition.a/16)+0.5) / 16.0;
|
||||
uint meta = vPosition.a;
|
||||
|
||||
uint mirco = (meta & 0xFF00u) >> 8u; // mirco offset which is a xyz 2bit value
|
||||
// 0b00 = no offset
|
||||
// 0b01 = positive offset
|
||||
// 0b11 = negative offset
|
||||
// format is: 0b00zzyyxx
|
||||
float mx = (mirco & 1u)!=0u ? mircoOffset : 0.0;
|
||||
mx = (mirco & 2u)!=0u ? -mx : mx;
|
||||
float my = (mirco & 4u)!=0u ? mircoOffset : 0.0;
|
||||
my = (mirco & 8u)!=0u ? -my : my;
|
||||
float mz = (mirco & 16u)!=0u ? mircoOffset : 0.0;
|
||||
mz = (mirco & 32u)!=0u ? -mz : mz;
|
||||
|
||||
uint lights = meta & 0xFFu;
|
||||
|
||||
float light2 = (mod(float(lights), 16.0)+0.5) / 16.0;
|
||||
float light = (float(lights/16u)+0.5) / 16.0;
|
||||
vertexColor = color * vec4(texture(lightMap, vec2(light, light2)).xyz, 1.0);
|
||||
|
||||
gl_Position = combinedMatrix * vec4(vertexWorldPos, 1.0);
|
||||
gl_Position = combinedMatrix * vec4(vertexWorldPos + vec3(mx, my, mz), 1.0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user