Android glitch effect or something

Fixes #116
This commit is contained in:
DBotThePony 2022-10-15 23:34:06 +07:00
parent a688f775b8
commit 3ead1c998d
Signed by: DBot
GPG Key ID: DCC23B5715498507
6 changed files with 552 additions and 146 deletions

View File

@ -360,9 +360,15 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
}
fun onHurt(event: LivingHurtEvent) {
if (isAndroid) {
for (feature in featureMap.values) {
feature.onHurt(event)
}
if (!event.isCanceled) {
sendNetwork(GlitchPacket((event.amount * 300).toLong().coerceAtLeast(200L).coerceAtMost(800L)))
}
}
}
fun <T : AndroidFeature> computeIfAbsent(feature: AndroidFeatureType<T>): T {

View File

@ -1,5 +1,8 @@
package ru.dbotthepony.mc.otm.client
import com.mojang.blaze3d.pipeline.MainTarget
import com.mojang.blaze3d.platform.GlConst.GL_COLOR_BUFFER_BIT
import com.mojang.blaze3d.platform.GlStateManager
import com.mojang.blaze3d.platform.InputConstants
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.BufferUploader
@ -7,6 +10,7 @@ import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexFormat
import com.mojang.math.Matrix4f
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.client.gui.screens.inventory.InventoryScreen
import net.minecraft.client.renderer.GameRenderer
@ -16,6 +20,7 @@ import net.minecraftforge.client.event.ScreenEvent
import ru.dbotthepony.mc.otm.android.feature.EnderTeleporterFeature
import ru.dbotthepony.mc.otm.android.feature.JumpBoostFeature
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.render.GlitchRenderer
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.render.tesselator
@ -27,6 +32,7 @@ import ru.dbotthepony.mc.otm.compat.cos.isCosmeticArmorScreen
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.identityFast
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import kotlin.math.min
fun onMovementInputUpdate(event: MovementInputUpdateEvent) {
val ply = event.entity
@ -111,11 +117,3 @@ fun onScreenOpen(event: ScreenEvent.Opening) {
event.newScreen = ExoSuitInventoryScreen(player.exoSuitMenu)
}
}
fun postLevelDrawHook(poseStack: PoseStack) {
}
fun lastLevelDrawHook(poseStack: PoseStack) {
}

View File

@ -0,0 +1,505 @@
package ru.dbotthepony.mc.otm.client.render
import com.google.common.collect.ImmutableList
import com.mojang.blaze3d.pipeline.MainTarget
import com.mojang.blaze3d.platform.GlConst
import com.mojang.blaze3d.platform.GlStateManager
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.BufferBuilder
import com.mojang.blaze3d.vertex.BufferUploader
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.VertexFormat
import com.mojang.math.Matrix4f
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.GameRenderer
import net.minecraft.core.Vec3i
import net.minecraft.world.level.levelgen.XoroshiroRandomSource
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.component1
import ru.dbotthepony.mc.otm.core.component2
import ru.dbotthepony.mc.otm.core.component3
import ru.dbotthepony.mc.otm.core.linearInterpolation
import java.util.stream.Collectors
import kotlin.math.absoluteValue
import kotlin.math.ceil
import kotlin.math.pow
@Suppress("SameParameterValue")
object GlitchRenderer {
private abstract class VideoGlitchType {
abstract fun upload(builder: BufferBuilder, x: Double, y: Double, width: Double, height: Double, u0: Float, v0: Float, u1: Float, v1: Float)
protected fun uploadVertices(faces: Int, builder: BufferBuilder, x: Double, y: Double, width: Double, height: Double, u0: Float, v0: Float, u1: Float, v1: Float, red: Int, green: Int, blue: Int, alpha: Int) {
if (faces and BOTTOM_LEFT != 0) {
builder.vertex(x, y + height, 0.0).uv(u0, v1).color(red, green, blue, alpha).endVertex()
}
if (faces and BOTTOM_RIGHT != 0) {
builder.vertex(x + width, y + height, 0.0).uv(u1, v1).color(red, green, blue, alpha).endVertex()
}
if (faces and TOP_RIGHT != 0) {
builder.vertex(x + width, y, 0.0).uv(u1, v0).color(red, green, blue, alpha).endVertex()
}
if (faces and TOP_LEFT != 0) {
builder.vertex(x, y, 0.0).uv(u0, v0).color(red, green, blue, alpha).endVertex()
}
}
protected fun uploadQuad(builder: BufferBuilder, x: Double, y: Double, width: Double, height: Double, u0: Float, v0: Float, u1: Float, v1: Float, red: Int, green: Int, blue: Int, alpha: Int) {
uploadVertices(TOP_LEFT or TOP_RIGHT or BOTTOM_RIGHT, builder, x, y, width, height, u0, v0, u1, v1, red, green, blue, alpha)
uploadVertices(TOP_LEFT or BOTTOM_RIGHT or BOTTOM_LEFT, builder, x, y, width, height, u0, v0, u1, v1, red, green, blue, alpha)
}
companion object {
const val TOP_LEFT = 1
const val TOP_RIGHT = 2
const val BOTTOM_LEFT = 4
const val BOTTOM_RIGHT = 8
val vertices = intArrayOf(
TOP_LEFT,
TOP_RIGHT,
BOTTOM_LEFT,
BOTTOM_RIGHT,
)
}
}
private val glitchesSorted: List<List<VideoGlitchType>>
private val glitchesTrisSorted: List<List<VideoGlitchType>>
private val glitchesQuadsSorted: List<List<VideoGlitchType>>
private fun selectGlitch(): List<VideoGlitchType> {
for (list in glitchesSorted) {
if (random.nextFloat() < 0.35f) {
return list
}
}
return glitchesSorted[glitchesSorted.size - 1]
}
private fun selectGlitchQuad(): List<VideoGlitchType> {
for (list in glitchesQuadsSorted) {
if (random.nextFloat() < 0.35f) {
return list
}
}
return glitchesQuadsSorted[glitchesQuadsSorted.size - 1]
}
private fun selectGlitchTriangle(): List<VideoGlitchType> {
for (list in glitchesTrisSorted) {
if (random.nextFloat() < 0.35f) {
return list
}
}
return glitchesTrisSorted[glitchesTrisSorted.size - 1]
}
init {
val glitchesMapQuads = Int2ObjectArrayMap<ArrayList<VideoGlitchType>>()
val glitchesMapTris = Int2ObjectArrayMap<ArrayList<VideoGlitchType>>()
val glitchesMap = Int2ObjectArrayMap<ArrayList<VideoGlitchType>>()
val colorVariants = ArrayList<Vec3i>()
val flippersFloppers = listOf(
{ u0: Float, v0: Float, u1: Float, v1: Float -> UVCoords(u0, v0, u1, v1) },
{ u0: Float, v0: Float, u1: Float, v1: Float -> UVCoords(1f - u0, v0, 1f - u1, v1) },
{ u0: Float, v0: Float, u1: Float, v1: Float -> UVCoords(u0, 1f - v0, u1, 1f - v1) },
{ u0: Float, v0: Float, u1: Float, v1: Float -> UVCoords(1f - u0, 1f - v0, 1f - u1, 1f - v1) },
)
val colors = intArrayOf(0, 10, 30, 50, 80, 100, 120, 150, 180, 220, 230, 235, 245, 249, 255)
for (red in colors)
for (green in colors)
for (blue in colors)
if (red != 255 || green != 255 || blue != 255)
colorVariants.add(Vec3i(red, green, blue))
for ((r, g, b) in colorVariants) {
for (winding in UVWindingOrder.distinct) {
for ((i, flipflop) in flippersFloppers.withIndex()) {
object : VideoGlitchType() {
@Suppress("name_shadowing")
override fun upload(builder: BufferBuilder, x: Double, y: Double, width: Double, height: Double, u0: Float, v0: Float, u1: Float, v1: Float) {
val (u0_, v0_, u1_, v1_) = winding.translate(u0, v0, u1, v1)
val (u0, v0, u1, v1) = flipflop.invoke(u0_, v0_, u1_, v1_)
uploadQuad(builder, x, y, width, height, u0, v0, u1, v1, r, g, b, 255)
}
}.also {
if (i == 0) {
glitchesMapQuads
.computeIfAbsent(255 - r + 255 - g + 255 - b, Int2ObjectFunction { ArrayList() })
.add(it)
}
glitchesMap
.computeIfAbsent(255 - r + 255 - g + 255 - b, Int2ObjectFunction { ArrayList() })
.add(it)
}
}
}
}
for (va in VideoGlitchType.vertices) {
for (vb in VideoGlitchType.vertices) {
if (va == vb) continue
for (cb in VideoGlitchType.vertices) {
if (cb == va || cb == vb) continue
for ((r, g, b) in colorVariants) {
for (winding in UVWindingOrder.distinct) {
for ((i, flipflop) in flippersFloppers.withIndex()) {
@Suppress("name_shadowing")
object : VideoGlitchType() {
val vertices = va or vb or cb
override fun upload(builder: BufferBuilder, x: Double, y: Double, width: Double, height: Double, u0: Float, v0: Float, u1: Float, v1: Float) {
val (u0_, v0_, u1_, v1_) = winding.translate(u0, v0, u1, v1)
val (u0, v0, u1, v1) = flipflop.invoke(u0_, v0_, u1_, v1_)
uploadVertices(vertices, builder, x, y, width, height, u0, v0, u1, v1, r, g, b, 255)
}
}.also {
if (i == 0) {
glitchesMapTris
.computeIfAbsent(255 - r + 255 - g + 255 - b, Int2ObjectFunction { ArrayList() })
.add(it)
}
glitchesMap
.computeIfAbsent(255 - r + 255 - g + 255 - b, Int2ObjectFunction { ArrayList() })
.add(it)
}
}
}
}
}
}
}
val toSort = glitchesMapQuads.entries.stream().collect(Collectors.toList())
toSort.sortBy { it.key }
glitchesQuadsSorted = toSort.stream().map { ImmutableList.copyOf(it.value) }.collect(ImmutableList.toImmutableList())
val toSort2 = glitchesMapTris.entries.stream().collect(Collectors.toList())
toSort2.sortBy { it.key }
glitchesTrisSorted = toSort2.stream().map { ImmutableList.copyOf(it.value) }.collect(ImmutableList.toImmutableList())
val toSort3 = glitchesMap.entries.stream().collect(Collectors.toList())
toSort3.sortBy { it.key }
glitchesSorted = toSort3.stream().map { ImmutableList.copyOf(it.value) }.collect(ImmutableList.toImmutableList())
}
private val random = XoroshiroRandomSource(System.nanoTime(), System.currentTimeMillis())
var redShiftX = 0.0
private set
var redShiftY = 0.0
private set
var greenShiftX = 0.0
private set
var greenShiftY = 0.0
private set
var blueShiftX = 0.0
private set
var blueShiftY = 0.0
private set
var lastGlitch = System.nanoTime()
private set
var nextGlitch = 0L
private set
var lastEncodingGlitch = System.nanoTime()
private set
var nextEncodingGlitch = 0L
private set
private val glitchBuffer by lazy(LazyThreadSafetyMode.NONE) {
MainTarget(minecraft.window.width, minecraft.window.height)
}
private fun upload(builder: BufferBuilder, offsetX: Double, offsetY: Double, u0: Float, v0: Float, u1: Float, v1: Float) {
builder.vertex(offsetX - 1.0, offsetY + 1.0, 0.0).uv(u0, v1).endVertex()
builder.vertex(offsetX + 1.0, offsetY + 1.0, 0.0).uv(u1, v1).endVertex()
builder.vertex(offsetX + 1.0, offsetY - 1.0, 0.0).uv(u1, v0).endVertex()
builder.vertex(offsetX - 1.0, offsetY - 1.0, 0.0).uv(u0, v0).endVertex()
}
private fun uploadEmpty(builder: BufferBuilder, offsetX: Double, offsetY: Double) {
builder.vertex(offsetX - 1.0, offsetY + 1.0, 0.0).endVertex()
builder.vertex(offsetX + 1.0, offsetY + 1.0, 0.0).endVertex()
builder.vertex(offsetX + 1.0, offsetY - 1.0, 0.0).endVertex()
builder.vertex(offsetX - 1.0, offsetY - 1.0, 0.0).endVertex()
}
private fun uploadLine(builder: BufferBuilder, offsetX: Double, offsetY: Double, height: Double, u0: Float, v0: Float, u1: Float, v1: Float) {
builder.vertex(offsetX - 1.0, offsetY - height, 0.0).uv(u0, v1).endVertex()
builder.vertex(offsetX + 1.0, offsetY - height, 0.0).uv(u1, v1).endVertex()
builder.vertex(offsetX + 1.0, offsetY, 0.0).uv(u1, v0).endVertex()
builder.vertex(offsetX - 1.0, offsetY, 0.0).uv(u0, v0).endVertex()
}
private inline fun makeMirrors(handler: (x: Double, y: Double, u0: Float, v0: Float, u1: Float, v1: Float) -> Unit) {
handler(0.0 - 2f, 0.0, 1f, 0f, 0f, 1f)
handler(0.0 + 2f, 0.0, 1f, 0f, 0f, 1f)
handler(0.0, 2.0, 0f, 1f, 1f, 0f)
handler(0.0, -2.0, 0f, 1f, 1f, 0f)
handler(0.0 - 2f, -2.0, 1f, 1f, 0f, 0f)
handler(0.0 + 2f, -2.0, 1f, 1f, 0f, 0f)
handler(0.0 - 2f, +2.0, 1f, 1f, 0f, 0f)
handler(0.0 + 2f, +2.0, 1f, 1f, 0f, 0f)
}
private fun draw(offsetX: Double, offsetY: Double) {
val builder = tesselator.builder
builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX)
upload(builder, offsetX, offsetY, 0f, 0f, 1f, 1f)
if (offsetX != 0.0 || offsetY != 0.0) {
makeMirrors { x: Double, y: Double, u0: Float, v0: Float, u1: Float, v1: Float ->
upload(builder, offsetX + x, offsetY + y, u0, v0, u1, v1)
}
}
BufferUploader.drawWithShader(builder.end())
}
private fun pixel2ViewX(value: Double) = linearInterpolation(value / glitchBuffer.width, 1.0, -1.0)
private fun pixel2ViewY(value: Double) = linearInterpolation(value / glitchBuffer.height, 1.0, -1.0)
private fun pixel2TextureX(value: Double) = (value / glitchBuffer.width).toFloat()
private fun pixel2TextureY(value: Double) = 1f - (value / glitchBuffer.height).toFloat()
private fun drawVHSLineGap(y: Double, height: Double) {
val builder = tesselator.builder
val v = pixel2TextureY(y)
builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX)
uploadLine(builder, 0.0, pixel2ViewY(y), (height / glitchBuffer.height) * 2.0, 0f, v, 1f, v)
BufferUploader.drawWithShader(builder.end())
}
private var colorGlitchBuff = arrayOfNulls<VideoGlitchType>(0)
private var colorGlitchWidth = 0
private var colorGlitchHeight = 0
private fun putMacroGlitch(x: Int, y: Int, width: Int, height: Int, value: VideoGlitchType?) {
for (offsetX in 0 until width) {
for (offsetY in 0 until height) {
val index = (x + offsetX) + (y + offsetY) * colorGlitchWidth
if (colorGlitchBuff.size > index) {
colorGlitchBuff[index] = value
}
}
}
}
private fun colorGlitchChanceMultiplier(x: Int, y: Int): Float {
return (1f - ((x.toDouble() - colorGlitchWidth.toDouble() / 2.0).pow(2.0) / colorGlitchWidth.toDouble().pow(2.0) +
(y.toDouble() - colorGlitchHeight.toDouble() / 2.0).pow(2.0) / colorGlitchHeight.toDouble().pow(2.0))
.toFloat()
.coerceAtLeast(0f)
.coerceAtMost(1f))
.pow(1f / 8f)
}
private fun makeColorGlitch() {
lastEncodingGlitch = System.nanoTime()
nextEncodingGlitch = random.nextIntBetweenInclusive(10_000_000, 40_000_000).toLong()
colorGlitchWidth = ceil(glitchBuffer.width / GLITCH_BLOCK_SIZE).toInt()
colorGlitchHeight = ceil(glitchBuffer.height / GLITCH_BLOCK_SIZE).toInt()
colorGlitchBuff = arrayOfNulls((colorGlitchWidth + 1) * (colorGlitchHeight + 1))
for (xBlock in 0 .. colorGlitchWidth)
for (yBlock in 0 .. colorGlitchHeight)
if (colorGlitchChanceMultiplier(xBlock, yBlock) < 0.99f && random.nextFloat() > colorGlitchChanceMultiplier(xBlock, yBlock) * 0.999f)
colorGlitchBuff[xBlock + yBlock * colorGlitchWidth] = selectGlitch().let { it[random.nextInt(0, it.size)] }
for (xBlock in 0 .. colorGlitchWidth)
for (yBlock in 0 .. colorGlitchHeight)
if (colorGlitchChanceMultiplier(xBlock, yBlock) < 0.99f && random.nextFloat() > colorGlitchChanceMultiplier(xBlock, yBlock) * 0.9999f)
putMacroGlitch(xBlock, yBlock, random.nextInt(1, 5), random.nextInt(1, 5), selectGlitchQuad().let { it[random.nextInt(0, it.size)] })
for (xBlock in 0 .. colorGlitchWidth)
for (yBlock in 0 .. colorGlitchHeight)
if (colorGlitchChanceMultiplier(xBlock, yBlock) < 0.99f && random.nextFloat() > colorGlitchChanceMultiplier(xBlock, yBlock) * 0.99999f)
putMacroGlitch(xBlock, yBlock, random.nextInt(1, 9), random.nextInt(1, 9), selectGlitchQuad().let { it[random.nextInt(0, it.size)] })
for (xBlock in 0 .. colorGlitchWidth)
for (yBlock in 0 .. colorGlitchHeight)
if (colorGlitchChanceMultiplier(xBlock, yBlock) < 0.99f && random.nextFloat() > colorGlitchChanceMultiplier(xBlock, yBlock) * 0.999999f)
putMacroGlitch(xBlock, yBlock, random.nextInt(1, 14), random.nextInt(1, 14), selectGlitchQuad().let { it[random.nextInt(0, it.size)] })
}
private fun makeGlitch() {
redShiftX = random.nextDouble() * 0.05 - 0.025
redShiftY = random.nextDouble() * 0.05 - 0.025
greenShiftX = random.nextDouble() * 0.05 - 0.025
greenShiftY = random.nextDouble() * 0.05 - 0.025
blueShiftX = random.nextDouble() * 0.05 - 0.025
blueShiftY = random.nextDouble() * 0.05 - 0.025
lastGlitch = System.nanoTime()
nextGlitch = random.nextIntBetweenInclusive(75_000_000, 400_000_000).toLong()
}
var glitchUntil = 0L
private set
var glitchSince = System.nanoTime()
private set
fun glitchFor(millis: Long) {
if (glitchUntil - (System.nanoTime() - glitchSince) < millis) {
glitchSince = System.nanoTime()
glitchUntil = millis * 1_000_000L
}
}
private const val GLITCH_BLOCK_SIZE = 8f
@JvmStatic
fun render() {
if (System.nanoTime() - glitchSince >= glitchUntil) {
return
}
if (System.nanoTime() - lastGlitch >= nextGlitch) {
makeGlitch()
}
if (System.nanoTime() - lastEncodingGlitch >= nextEncodingGlitch) {
makeColorGlitch()
}
val glitchBuffer = glitchBuffer
val projection = RenderSystem.getProjectionMatrix()
RenderSystem.setProjectionMatrix(Matrix4f().also { it.setIdentity() })
RenderSystem.getModelViewStack().also {
it.pushPose()
it.setIdentity()
}
RenderSystem.applyModelViewMatrix()
RenderSystem.disableCull()
RenderSystem.disableDepthTest()
RenderSystem.enableBlend()
RenderSystem.enableTexture()
RenderSystem.clearColor(0f, 0f, 0f, 1f)
if (glitchBuffer.width != minecraft.window.width || glitchBuffer.height != minecraft.window.height) {
glitchBuffer.resize(minecraft.window.width, minecraft.window.height, Minecraft.ON_OSX)
glitchBuffer.bindWrite(true)
} else {
glitchBuffer.bindWrite(true)
RenderSystem.clear(GlConst.GL_COLOR_BUFFER_BIT, Minecraft.ON_OSX)
}
// distort colors by sampling main frame buffer (raw stage)
RenderSystem.setShaderTexture(0, minecraft.mainRenderTarget.colorTextureId)
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_DST_ALPHA)
RenderSystem.setShader(GameRenderer::getPositionTexShader)
RenderSystem.setShaderColor(1f, 0.1f, 0f, 1f)
draw(redShiftX, redShiftY)
RenderSystem.setShaderColor(0f, 1f, 0f, 1f)
draw(greenShiftX, greenShiftY)
RenderSystem.setShaderColor(0f, 0f, 1f, 1f)
draw(blueShiftX, blueShiftY)
minecraft.mainRenderTarget.bindWrite(true)
// draw back to main frame buffer (prepare for post process)
RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO)
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
RenderSystem.setShaderTexture(0, glitchBuffer.colorTextureId)
draw(0.0, 0.0)
// return to our frame buffer (post process stage)
glitchBuffer.bindWrite(true)
RenderSystem.setShaderTexture(0, minecraft.mainRenderTarget.colorTextureId)
// color perception errors (eye-camera glitch)
drawVHSLineGap((System.currentTimeMillis() % glitchBuffer.height).toDouble(), glitchBuffer.height * 0.025)
drawVHSLineGap(((System.currentTimeMillis() + glitchBuffer.height / 2) % glitchBuffer.height).toDouble(), glitchBuffer.height * 0.075)
drawVHSLineGap(((System.currentTimeMillis() + glitchBuffer.height / 3) % glitchBuffer.height).toDouble(), glitchBuffer.height * 0.04)
drawVHSLineGap(((-System.currentTimeMillis() - glitchBuffer.height / 3) % glitchBuffer.height).toDouble().absoluteValue, glitchBuffer.height * 0.07)
// color encoding errors (encoder/transmission glitch)
val blocksWidth = ceil(glitchBuffer.width / GLITCH_BLOCK_SIZE).toInt()
val blocksHeight = ceil(glitchBuffer.height / GLITCH_BLOCK_SIZE).toInt()
if (colorGlitchWidth != blocksWidth || colorGlitchHeight != blocksHeight) {
makeColorGlitch()
}
val blockStepWidth = (GLITCH_BLOCK_SIZE / glitchBuffer.width) * 2.0
val blockStepHeight = (GLITCH_BLOCK_SIZE / glitchBuffer.height) * 2.0
val blockStepWidthUV = GLITCH_BLOCK_SIZE / glitchBuffer.width
val blockStepHeightUV = GLITCH_BLOCK_SIZE / glitchBuffer.height
val builder = tesselator.builder
builder.begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION_TEX_COLOR)
for (xBlock in 0 .. blocksWidth) {
for (yBlock in 0 .. blocksHeight) {
colorGlitchBuff[xBlock + yBlock * blocksWidth]?.upload(
builder = builder,
x = -1.0 + xBlock * blockStepWidth,
y = -1.0 + yBlock * blockStepHeight,
width = blockStepWidth,
height = blockStepHeight,
u0 = xBlock * blockStepWidthUV,
v0 = yBlock * blockStepHeightUV,
u1 = (xBlock + 1) * blockStepWidthUV,
v1 = (yBlock + 1) * blockStepHeightUV,
)
}
}
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
RenderSystem.setShader(GameRenderer::getPositionTexColorShader)
BufferUploader.drawWithShader(builder.end())
// upload final result to main frame buffer
minecraft.mainRenderTarget.bindWrite(true)
RenderSystem.setShader(GameRenderer::getPositionTexShader)
RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO)
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
RenderSystem.setShaderTexture(0, glitchBuffer.colorTextureId)
draw(0.0, 0.0)
RenderSystem.setProjectionMatrix(projection)
RenderSystem.getModelViewStack().popPose()
RenderSystem.applyModelViewMatrix()
}
}

View File

@ -1,5 +1,7 @@
package ru.dbotthepony.mc.otm.client.render
import com.google.common.collect.ImmutableList
sealed interface IUVCoords {
val u0: Float
val v0: Float
@ -80,6 +82,10 @@ enum class UVWindingOrder(
U1_V1_U0_V0(2, 3, 0, 1), // mirror both
FLIP_FLOP(2, 3, 0, 1); // mirror both
companion object {
val distinct: List<UVWindingOrder> = ImmutableList.of(NORMAL, FLIP, FLOP, FLIP_FLOP)
}
val isIdentity: Boolean = u0 == 0 && v0 == 1 && u1 == 2 && v1 == 3
operator fun component1() = u0

View File

@ -23,6 +23,7 @@ import ru.dbotthepony.mc.otm.android.feature.TriggerShockwavePacket
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.MatteryGUI
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.render.GlitchRenderer
import ru.dbotthepony.mc.otm.container.get
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.menu.AndroidStationMenu
@ -430,6 +431,23 @@ class PickItemFromInventoryPacket(
}
}
class GlitchPacket(val millis: Long) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {
buff.writeVarLong(millis)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true
GlitchRenderer.glitchFor(millis)
}
companion object {
fun read(buff: FriendlyByteBuf): GlitchPacket {
return GlitchPacket(buff.readVarLong())
}
}
}
object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
version = "1",
name = "player"
@ -457,5 +475,7 @@ object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
add(TriggerJumpBoostPacket::class, { TriggerJumpBoostPacket }, PLAY_TO_SERVER)
add(PickItemFromInventoryPacket::class, PickItemFromInventoryPacket.Companion::read, PLAY_TO_SERVER)
add(GlitchPacket::class, GlitchPacket.Companion::read, PLAY_TO_CLIENT)
}
}

View File

@ -890,33 +890,6 @@ function initializeCoreMod() {
}
},
'big GameRenderer#renderItemInHand fuck off':
method('net.minecraft.client.renderer.GameRenderer.m_109120_(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/Camera;F)V', function(node) {
putInstructions(node, undefined, [
new VarInsnNode(opcodesRemapped.aload, 1),
new MethodInsnNode(
opcodesRemapped.invokevirtual,
'com/mojang/blaze3d/vertex/PoseStack',
ASMAPI.mapMethod('m_85836_'), // pushPose
'()V',
false
)
])
injectInstructionsAtTail(node, [
new VarInsnNode(opcodesRemapped.aload, 1),
new MethodInsnNode(
opcodesRemapped.invokevirtual,
'com/mojang/blaze3d/vertex/PoseStack',
ASMAPI.mapMethod('m_85849_'), // popPose
'()V',
false
)
])
return node
}),
'GameRenderer#render hook': {
'target': {
'type': 'METHOD',
@ -934,137 +907,35 @@ function initializeCoreMod() {
false
))
// 233: new #26 // class com/mojang/blaze3d/vertex/PoseStack
// 236: dup
// 237: invokespecial #1425 // Method com/mojang/blaze3d/vertex/PoseStack."<init>":()V
// <-- our target for local variable
// 240: invokevirtual #3398 // Method renderLevel:(FJLcom/mojang/blaze3d/vertex/PoseStack;)V
// 243: aload_0
// 244: invokevirtual #3540 // Method tryTakeScreenshotIfNeeded:()V
// 247: aload_0
// 248: getfield #2773 // Field minecraft:Lnet/minecraft/client/Minecraft;
// 251: getfield #3207 // Field net/minecraft/client/Minecraft.levelRenderer:Lnet/minecraft/client/renderer/LevelRenderer;
// 254: invokevirtual #3543 // Method net/minecraft/client/renderer/LevelRenderer.doEntityOutline:()V
// <-- our target for post
// 257: aload_0
// 258: getfield #2788 // Field postEffect:Lnet/minecraft/client/renderer/PostChain;
// 261: ifnull 291
// 264: aload_0
// 265: getfield #2805 // Field effectActive:Z
// 268: ifeq 291
// 271: invokestatic #3546 // Method com/mojang/blaze3d/systems/RenderSystem.disableBlend:()V
// 274: invokestatic #3549 // Method com/mojang/blaze3d/systems/RenderSystem.disableDepthTest:()V
// 277: invokestatic #3552 // Method com/mojang/blaze3d/systems/RenderSystem.enableTexture:()V
// 280: invokestatic #3555 // Method com/mojang/blaze3d/systems/RenderSystem.resetTextureMatrix:()V
// 283: aload_0
// 284: getfield #2788 // Field postEffect:Lnet/minecraft/client/renderer/PostChain;
// 287: fload_1
// 288: invokevirtual #3558 // Method net/minecraft/client/renderer/PostChain.process:(F)V
// 291: aload_0
// 292: getfield #2773 // Field minecraft:Lnet/minecraft/client/Minecraft;
// 295: invokevirtual #2818 // Method net/minecraft/client/Minecraft.getMainRenderTarget:()Lcom/mojang/blaze3d/pipeline/RenderTarget;
// 298: iconst_1
// 299: invokevirtual #3561 // Method com/mojang/blaze3d/pipeline/RenderTarget.bindWrite:(Z)V
// <-- our target for last
// <-- our target
// 302: aload_0
// 303: getfield #2773 // Field minecraft:Lnet/minecraft/client/Minecraft;
// 306: invokevirtual #2821 // Method net/minecraft/client/Minecraft.getWindow:()Lcom/mojang/blaze3d/platform/Window;
// 309: astore 7
var ourmethod = ASMAPI.mapMethod('m_83947_')
var lastLabel = undefined
var beforeInvoke = undefined
var slot = undefined
var ourmethod = ASMAPI.mapMethod('m_83947_') // bindWrite
for (var i = 0; i < node.instructions.size(); i++) {
var instruction = node.instructions.get(i)
if (instruction.getOpcode() == opcodesRemapped.invokevirtual && instruction.name == ourmethod && instruction.desc == '(Z)V') {
beforeInvoke = instruction
var invoke = new MethodInsnNode(
node.instructions.insert(instruction, new MethodInsnNode(
opcodesRemapped.invokestatic,
'ru/dbotthepony/mc/otm/client/ClientEventHandlerKt',
'lastLevelDrawHook',
'(Lcom/mojang/blaze3d/vertex/PoseStack;)V',
false
)
node.instructions.insert(instruction, invoke)
lastLabel = new LabelNode(new Label())
node.instructions.insert(invoke, lastLabel)
break
}
}
if (lastLabel !== undefined && beforeInvoke !== undefined) {
var renderLevel = ASMAPI.mapMethod('m_109089_')
node.maxLocals++
for (var i = 0; i < node.instructions.size(); i++) {
var instruction = node.instructions.get(i)
if (instruction.getOpcode() == opcodesRemapped.invokevirtual && instruction.name == renderLevel && instruction.desc == '(FJLcom/mojang/blaze3d/vertex/PoseStack;)V') {
var startLabel = new Label()
var prev = node.instructions.get(i - 1)
var labelNode = new LabelNode(startLabel)
node.instructions.insert(prev, labelNode)
prev = labelNode
var slot = node.localVariables.size() + 1
var local = new LocalVariableNode(
'otm_capturePoseStack',
'Lcom/mojang/blaze3d/vertex/PoseStack;',
null,
labelNode,
lastLabel,
slot
)
node.localVariables.add(local)
var next = new InsnNode(opcodesRemapped.dup)
node.instructions.insert(prev, next)
prev = next
next = new VarInsnNode(opcodesRemapped.astore, slot)
node.instructions.insert(prev, next)
node.instructions.insert(beforeInvoke, new VarInsnNode(opcodesRemapped.aload, slot))
break
}
}
}
if (slot !== undefined) {
var doEntityOutline = ASMAPI.mapMethod('m_109769_')
for (var i = 0; i < node.instructions.size(); i++) {
var instruction = node.instructions.get(i)
if (instruction.getOpcode() == opcodesRemapped.invokevirtual && instruction.name == doEntityOutline && instruction.desc == '()V') {
var prev = instruction
var next = new VarInsnNode(opcodesRemapped.aload, slot)
node.instructions.insert(prev, next)
prev = next
node.instructions.insert(prev, new MethodInsnNode(
opcodesRemapped.invokestatic,
'ru/dbotthepony/mc/otm/client/ClientEventHandlerKt',
'postLevelDrawHook',
'(Lcom/mojang/blaze3d/vertex/PoseStack;)V',
'ru/dbotthepony/mc/otm/client/render/GlitchRenderer',
'render',
'()V',
false
))
break
}
}
}
return node
}