dynamic buffer source

This commit is contained in:
DBotThePony 2022-10-08 00:57:02 +07:00
parent cf12971861
commit 279e28095b
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -0,0 +1,324 @@
package ru.dbotthepony.mc.otm.client.render
import com.google.common.collect.ImmutableList
import com.mojang.blaze3d.vertex.BufferBuilder
import com.mojang.blaze3d.vertex.VertexConsumer
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.Sheets
private fun equals(existing: ImmutableList<RenderType>?, types: Array<out RenderType>): Boolean {
if (types.isEmpty()) {
return existing == null
}
if (existing == null) {
return false
}
if (existing.size != types.size) {
return false
}
for (i in types.indices) {
if (types[i] !== existing[i]) {
return false
}
}
return true
}
private fun equals(existing: ImmutableList<RenderType>?, types: ImmutableList<RenderType>): Boolean {
if (existing === types) {
return true
}
if (types.isEmpty()) {
return existing == null
}
if (existing == null) {
return false
}
if (existing.size != types.size) {
return false
}
for (i in types.indices) {
if (types[i] !== existing[i]) {
return false
}
}
return true
}
class DynamicBufferSource : MultiBufferSource {
private class State(
val type: RenderType,
var after: ImmutableList<RenderType>? = null,
val immutableAfter: Boolean = false
) {
var priority = -1
var dirty: Boolean = false
val builder by lazy {
BufferBuilder(type.bufferSize())
}
}
private val bufferList = ArrayList<State>().also {
var next = State(Sheets.solidBlockSheet(), null, true)
it.add(next)
next = State(Sheets.cutoutBlockSheet(), ImmutableList.of(next.type), true)
it.add(next)
next = State(Sheets.bannerSheet(), ImmutableList.of(next.type), true)
it.add(next)
next = State(Sheets.translucentCullBlockSheet(), ImmutableList.of(next.type), true)
it.add(next)
next = State(Sheets.shieldSheet(), ImmutableList.of(next.type), true)
it.add(next)
next = State(Sheets.bedSheet(), ImmutableList.of(next.type), true)
it.add(next)
next = State(Sheets.shulkerBoxSheet(), ImmutableList.of(next.type), true)
it.add(next)
next = State(Sheets.signSheet(), ImmutableList.of(next.type), true)
it.add(next)
next = State(Sheets.chestSheet(), ImmutableList.of(next.type), true)
it.add(next)
next = State(RenderType.translucentNoCrumbling(), ImmutableList.of(next.type), true)
it.add(next)
next = State(RenderType.armorGlint(), ImmutableList.of(next.type), true)
it.add(next)
next = State(RenderType.armorEntityGlint(), ImmutableList.of(next.type), true)
it.add(next)
next = State(RenderType.glint(), ImmutableList.of(next.type), true)
it.add(next)
next = State(RenderType.glintDirect(), ImmutableList.of(next.type), true)
it.add(next)
next = State(RenderType.glintTranslucent(), ImmutableList.of(next.type), true)
it.add(next)
next = State(RenderType.entityGlint(), ImmutableList.of(next.type), true)
it.add(next)
next = State(RenderType.entityGlintDirect(), ImmutableList.of(next.type), true)
it.add(next)
next = State(RenderType.waterMask(), ImmutableList.of(next.type), true)
it.add(next)
}
private fun determineHeight(input: State, seen: MutableSet<State>) {
if (!seen.add(input)) {
throw IllegalStateException("Recursive dependencies detected when going through ${input.type}: ${seen.joinToString(", ") { it.type.toString() + "[${it.after?.joinToString(", ")}]" }}")
}
if (input.after == null) {
input.priority = 0
} else {
for (type in input.after!!) {
for (input2 in bufferList) {
if (input2.type == type) {
if (input2.priority == -1) {
determineHeight(input2, seen)
}
input.priority = input.priority.coerceAtLeast(input2.priority + 1)
break
}
}
}
if (input.priority == -1) {
input.priority = 0
}
}
}
private fun sortBufferList() {
for (state in bufferList) {
state.priority = -1
}
for (state in bufferList) {
val seen = ReferenceArraySet<State>()
determineHeight(state, seen)
}
bufferList.sortWith { a, b ->
// most referenced buffers go first
b.priority.compareTo(a.priority)
}
}
private val buffers = Reference2ObjectOpenHashMap<RenderType, State>().also {
for (v in bufferList) it[v.type] = v
}
override fun getBuffer(renderType: RenderType): VertexConsumer {
var getState = buffers[renderType]
if (getState == null) {
getState = State(renderType)
buffers[renderType] = getState
bufferList.add(getState)
getState.dirty = true
return getState.builder.also {
it.begin(renderType.mode(), renderType.format())
}
}
if (!getState.dirty) {
getState.dirty = true
getState.builder.begin(renderType.mode(), renderType.format())
}
return getState.builder
}
fun getBuffer(renderType: RenderType, after: RenderType): VertexConsumer {
var getState = buffers[renderType]
if (getState == null) {
getState = State(renderType, ImmutableList.of(after))
buffers[renderType] = getState
bufferList.add(getState)
getState.dirty = true
sortBufferList()
return getState.builder.also {
it.begin(renderType.mode(), renderType.format())
}
}
if (!getState.immutableAfter && getState.after?.getOrNull(0) !== after) {
getState.after = ImmutableList.of(after)
sortBufferList()
}
if (!getState.dirty) {
getState.dirty = true
getState.builder.begin(renderType.mode(), renderType.format())
}
return getState.builder
}
fun getBuffer(renderType: RenderType, vararg after: RenderType): VertexConsumer {
var getState = buffers[renderType]
if (getState == null) {
getState = State(renderType, ImmutableList.copyOf(after))
buffers[renderType] = getState
bufferList.add(getState)
getState.dirty = true
sortBufferList()
return getState.builder.also {
it.begin(renderType.mode(), renderType.format())
}
}
if (!getState.immutableAfter && !equals(getState.after, after)) {
getState.after = ImmutableList.copyOf(after)
sortBufferList()
}
if (!getState.dirty) {
getState.dirty = true
getState.builder.begin(renderType.mode(), renderType.format())
}
return getState.builder
}
fun getBuffer(renderType: RenderType, after: ImmutableList<RenderType>): VertexConsumer {
var getState = buffers[renderType]
if (getState == null) {
getState = State(renderType, after)
buffers[renderType] = getState
bufferList.add(getState)
getState.dirty = true
sortBufferList()
return getState.builder.also {
it.begin(renderType.mode(), renderType.format())
}
}
if (!getState.immutableAfter && !equals(getState.after, after)) {
getState.after = after
sortBufferList()
}
if (!getState.dirty) {
getState.dirty = true
getState.builder.begin(renderType.mode(), renderType.format())
}
return getState.builder
}
fun registerType(renderType: RenderType, after: RenderType) {
var getState = buffers[renderType]
if (getState == null) {
getState = State(renderType, ImmutableList.of(after))
buffers[renderType] = getState
bufferList.add(getState)
sortBufferList()
} else if (!getState.immutableAfter && getState.after?.getOrNull(0) !== after) {
getState.after = ImmutableList.of(after)
sortBufferList()
}
}
fun registerType(renderType: RenderType, vararg after: RenderType) {
var getState = buffers[renderType]
if (getState == null) {
getState = State(renderType, ImmutableList.copyOf(after))
buffers[renderType] = getState
bufferList.add(getState)
sortBufferList()
} else if (!getState.immutableAfter && !equals(getState.after, after)) {
getState.after = ImmutableList.copyOf(after)
sortBufferList()
}
}
fun registerType(renderType: RenderType, after: ImmutableList<RenderType>) {
var getState = buffers[renderType]
if (getState == null) {
getState = State(renderType, after)
buffers[renderType] = getState
bufferList.add(getState)
sortBufferList()
} else if (!getState.immutableAfter && !equals(getState.after, after)) {
getState.after = after
sortBufferList()
}
}
fun endBatch() {
for (state in bufferList) {
if (state.dirty) {
state.dirty = false
state.type.end(state.builder, 0, 0, 0)
}
}
}
fun endBatch(type: RenderType) {
val state = buffers[type] ?: return
if (state.dirty) {
state.dirty = false
type.end(state.builder, 0, 0, 0)
}
}
companion object {
val GUI = DynamicBufferSource()
}
}