175 lines
6.4 KiB
Java
175 lines
6.4 KiB
Java
package com.mojang.blaze3d.opengl;
|
|
|
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
|
import com.mojang.blaze3d.vertex.VertexFormatElement;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import org.jetbrains.annotations.Nullable;
|
|
import org.lwjgl.opengl.ARBVertexAttribBinding;
|
|
import org.lwjgl.opengl.GLCapabilities;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public abstract class VertexArrayCache {
|
|
public static VertexArrayCache create(GLCapabilities capabilities, GlDebugLabel debugLabel, Set<String> enabledExtensions) {
|
|
if (capabilities.GL_ARB_vertex_attrib_binding && GlDevice.USE_GL_ARB_vertex_attrib_binding) {
|
|
enabledExtensions.add("GL_ARB_vertex_attrib_binding");
|
|
return new VertexArrayCache.Separate(debugLabel);
|
|
} else {
|
|
return new VertexArrayCache.Emulated(debugLabel);
|
|
}
|
|
}
|
|
|
|
public abstract void bindVertexArray(VertexFormat format, GlBuffer buffer);
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
static class Emulated extends VertexArrayCache {
|
|
private final Map<VertexFormat, VertexArrayCache.VertexArray> cache = new HashMap();
|
|
private final GlDebugLabel debugLabels;
|
|
|
|
public Emulated(GlDebugLabel debugLabels) {
|
|
this.debugLabels = debugLabels;
|
|
}
|
|
|
|
@Override
|
|
public void bindVertexArray(VertexFormat format, GlBuffer buffer) {
|
|
VertexArrayCache.VertexArray vertexArray = (VertexArrayCache.VertexArray)this.cache.get(format);
|
|
if (vertexArray == null) {
|
|
int i = GlStateManager._glGenVertexArrays();
|
|
GlStateManager._glBindVertexArray(i);
|
|
GlStateManager._glBindBuffer(34962, buffer.handle);
|
|
setupCombinedAttributes(format, true);
|
|
VertexArrayCache.VertexArray vertexArray2 = new VertexArrayCache.VertexArray(i, format, buffer);
|
|
this.debugLabels.applyLabel(vertexArray2);
|
|
this.cache.put(format, vertexArray2);
|
|
} else {
|
|
GlStateManager._glBindVertexArray(vertexArray.id);
|
|
if (vertexArray.lastVertexBuffer != buffer) {
|
|
GlStateManager._glBindBuffer(34962, buffer.handle);
|
|
vertexArray.lastVertexBuffer = buffer;
|
|
setupCombinedAttributes(format, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void setupCombinedAttributes(VertexFormat vertexFormat, boolean enabled) {
|
|
int i = vertexFormat.getVertexSize();
|
|
List<VertexFormatElement> list = vertexFormat.getElements();
|
|
|
|
for (int j = 0; j < list.size(); j++) {
|
|
VertexFormatElement vertexFormatElement = (VertexFormatElement)list.get(j);
|
|
if (enabled) {
|
|
GlStateManager._enableVertexAttribArray(j);
|
|
}
|
|
|
|
switch (vertexFormatElement.usage()) {
|
|
case POSITION:
|
|
case GENERIC:
|
|
GlStateManager._vertexAttribPointer(
|
|
j, vertexFormatElement.count(), GlConst.toGl(vertexFormatElement.type()), false, i, vertexFormat.getOffset(vertexFormatElement)
|
|
);
|
|
break;
|
|
case NORMAL:
|
|
case COLOR:
|
|
GlStateManager._vertexAttribPointer(
|
|
j, vertexFormatElement.count(), GlConst.toGl(vertexFormatElement.type()), true, i, vertexFormat.getOffset(vertexFormatElement)
|
|
);
|
|
break;
|
|
case UV:
|
|
if (vertexFormatElement.type() == VertexFormatElement.Type.FLOAT) {
|
|
GlStateManager._vertexAttribPointer(
|
|
j, vertexFormatElement.count(), GlConst.toGl(vertexFormatElement.type()), false, i, vertexFormat.getOffset(vertexFormatElement)
|
|
);
|
|
} else {
|
|
GlStateManager._vertexAttribIPointer(
|
|
j, vertexFormatElement.count(), GlConst.toGl(vertexFormatElement.type()), i, vertexFormat.getOffset(vertexFormatElement)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
static class Separate extends VertexArrayCache {
|
|
private final Map<VertexFormat, VertexArrayCache.VertexArray> cache = new HashMap();
|
|
private final GlDebugLabel debugLabels;
|
|
|
|
public Separate(GlDebugLabel debugLabels) {
|
|
this.debugLabels = debugLabels;
|
|
}
|
|
|
|
@Override
|
|
public void bindVertexArray(VertexFormat format, GlBuffer buffer) {
|
|
VertexArrayCache.VertexArray vertexArray = (VertexArrayCache.VertexArray)this.cache.get(format);
|
|
if (vertexArray == null) {
|
|
int i = GlStateManager._glGenVertexArrays();
|
|
GlStateManager._glBindVertexArray(i);
|
|
ARBVertexAttribBinding.glBindVertexBuffer(0, buffer.handle, 0L, format.getVertexSize());
|
|
List<VertexFormatElement> list = format.getElements();
|
|
|
|
for (int j = 0; j < list.size(); j++) {
|
|
VertexFormatElement vertexFormatElement = (VertexFormatElement)list.get(j);
|
|
GlStateManager._enableVertexAttribArray(j);
|
|
switch (vertexFormatElement.usage()) {
|
|
case POSITION:
|
|
case GENERIC:
|
|
ARBVertexAttribBinding.glVertexAttribFormat(
|
|
j, vertexFormatElement.count(), GlConst.toGl(vertexFormatElement.type()), false, format.getOffset(vertexFormatElement)
|
|
);
|
|
break;
|
|
case NORMAL:
|
|
case COLOR:
|
|
ARBVertexAttribBinding.glVertexAttribFormat(
|
|
j, vertexFormatElement.count(), GlConst.toGl(vertexFormatElement.type()), true, format.getOffset(vertexFormatElement)
|
|
);
|
|
break;
|
|
case UV:
|
|
if (vertexFormatElement.type() == VertexFormatElement.Type.FLOAT) {
|
|
ARBVertexAttribBinding.glVertexAttribFormat(
|
|
j, vertexFormatElement.count(), GlConst.toGl(vertexFormatElement.type()), false, format.getOffset(vertexFormatElement)
|
|
);
|
|
} else {
|
|
ARBVertexAttribBinding.glVertexAttribIFormat(
|
|
j, vertexFormatElement.count(), GlConst.toGl(vertexFormatElement.type()), format.getOffset(vertexFormatElement)
|
|
);
|
|
}
|
|
}
|
|
|
|
ARBVertexAttribBinding.glVertexAttribBinding(j, 0);
|
|
}
|
|
|
|
VertexArrayCache.VertexArray vertexArray2 = new VertexArrayCache.VertexArray(i, format, buffer);
|
|
this.debugLabels.applyLabel(vertexArray2);
|
|
this.cache.put(format, vertexArray2);
|
|
} else {
|
|
GlStateManager._glBindVertexArray(vertexArray.id);
|
|
if (vertexArray.lastVertexBuffer != buffer) {
|
|
if (vertexArray.lastVertexBuffer != null && vertexArray.lastVertexBuffer.handle == buffer.handle) {
|
|
ARBVertexAttribBinding.glBindVertexBuffer(0, 0, 0L, 0);
|
|
}
|
|
|
|
ARBVertexAttribBinding.glBindVertexBuffer(0, buffer.handle, 0L, format.getVertexSize());
|
|
vertexArray.lastVertexBuffer = buffer;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public static class VertexArray {
|
|
final int id;
|
|
final VertexFormat format;
|
|
@Nullable
|
|
GlBuffer lastVertexBuffer;
|
|
|
|
VertexArray(int id, VertexFormat format, @Nullable GlBuffer lastVertexBuffer) {
|
|
this.id = id;
|
|
this.format = format;
|
|
this.lastVertexBuffer = lastVertexBuffer;
|
|
}
|
|
}
|
|
}
|