dynamic buffer source
This commit is contained in:
parent
cf12971861
commit
279e28095b
@ -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()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user