mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-20 14:16:26 -04:00
add glow halo around terastal
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
|
||||
import com.cobblemon.mod.common.client.render.shader.TeraHalo;
|
||||
import com.cobblemon.mod.common.integration.IrisCompatibility;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
@@ -59,6 +60,7 @@ public class GameRendererMixin {
|
||||
)
|
||||
private void cobblemon$drawAfterShaderPack(DeltaTracker deltaTracker, CallbackInfo ci) {
|
||||
IrisCompatibility.INSTANCE.drawDeferred();
|
||||
TeraHalo.INSTANCE.draw();
|
||||
}
|
||||
|
||||
@ModifyArg(
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.shader.TeraHalo;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(LevelRenderer.class)
|
||||
public class LevelRendererMixin {
|
||||
@Inject(method = "initOutline", at = @At("TAIL"))
|
||||
private void cobblemon$loadTeraHalo(CallbackInfo ci) {
|
||||
TeraHalo.INSTANCE.load();
|
||||
}
|
||||
|
||||
@Inject(method = "resize", at = @At("TAIL"))
|
||||
private void cobblemon$resizeTeraHalo(int width, int height, CallbackInfo ci) {
|
||||
TeraHalo.INSTANCE.resize(width, height);
|
||||
}
|
||||
|
||||
@Inject(method = "close", at = @At("TAIL"))
|
||||
private void cobblemon$closeTeraHalo(CallbackInfo ci) {
|
||||
TeraHalo.INSTANCE.close();
|
||||
}
|
||||
}
|
||||
+7
-4
@@ -54,6 +54,8 @@ import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import com.cobblemon.mod.common.integration.IrisCompatibility
|
||||
import com.cobblemon.mod.common.client.render.shader.TeraHalo
|
||||
import com.cobblemon.mod.common.client.render.shader.TeraRender
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@@ -177,7 +179,7 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
var currentState: PosableState? = null
|
||||
|
||||
@Transient
|
||||
var teraOverlay: Pair<RenderType, Int>? = null
|
||||
var tera: TeraRender? = null
|
||||
|
||||
@Transient
|
||||
val functions = QueryStruct(this.animationFunctions())
|
||||
@@ -268,7 +270,7 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
currentLayers = emptyList()
|
||||
bufferProvider = null
|
||||
currentState = null
|
||||
teraOverlay = null
|
||||
tera = null
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -495,8 +497,9 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
)
|
||||
stack.popPose()
|
||||
}
|
||||
teraOverlay?.let { (renderType, tint) ->
|
||||
IrisCompatibility.renderAfterShaderPack(provider, renderType) { rootPart.render(context, stack, it, packedLight, packedOverlay, tint) }
|
||||
tera?.let { tera ->
|
||||
IrisCompatibility.renderAfterShaderPack(provider, tera.overlay) { rootPart.render(context, stack, it, packedLight, packedOverlay, tera.tint) }
|
||||
TeraHalo.record(tera.halo) { rootPart.render(context, stack, it, packedLight, packedOverlay, tera.tint) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@ class PokemonRenderer(
|
||||
}
|
||||
|
||||
modelNow.setLayerContext(buffer, clientDelegate, VaryingModelRepository.getLayers(entity.pokemon.species.resourceIdentifier, clientDelegate))
|
||||
modelNow.teraOverlay = TeraOverlay.forAspects(entity.aspects, getTextureLocation(entity))
|
||||
modelNow.tera = TeraOverlay.forAspects(entity.aspects, getTextureLocation(entity))
|
||||
|
||||
|
||||
if (entity.passengers.isNotEmpty()) {
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.shader
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.integration.DeferredMeshes
|
||||
import com.cobblemon.mod.common.integration.IrisCompatibility
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.mojang.blaze3d.platform.GlStateManager
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import net.minecraft.Util
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.GameRenderer
|
||||
import net.minecraft.client.renderer.PostChain
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
object TeraHalo {
|
||||
private val CHAIN_LOCATION = cobblemonResource("shaders/post/tera_halo.json")
|
||||
|
||||
private val deferred = DeferredMeshes()
|
||||
private var chain: PostChain? = null
|
||||
|
||||
private val MASK_TARGET = RenderStateShard.OutputStateShard(
|
||||
"cobblemon_tera_halo_mask",
|
||||
{ chain?.getTempTarget("mask")?.bindWrite(false) },
|
||||
{ Minecraft.getInstance().mainRenderTarget.bindWrite(false) }
|
||||
)
|
||||
|
||||
private val renderType = Util.memoize { texture: ResourceLocation ->
|
||||
RenderType.create(
|
||||
"cobblemon_tera_halo",
|
||||
DefaultVertexFormat.POSITION_TEX_COLOR,
|
||||
VertexFormat.Mode.QUADS,
|
||||
256,
|
||||
false,
|
||||
false,
|
||||
RenderType.CompositeState.builder()
|
||||
.setShaderState(RenderStateShard.ShaderStateShard(GameRenderer::getRendertypeOutlineShader))
|
||||
.setTextureState(RenderStateShard.TextureStateShard(texture, false, false))
|
||||
.setDepthTestState(RenderStateShard.LEQUAL_DEPTH_TEST)
|
||||
.setCullState(RenderStateShard.CULL)
|
||||
.setWriteMaskState(RenderStateShard.COLOR_WRITE)
|
||||
.setOutputState(MASK_TARGET)
|
||||
.createCompositeState(false)
|
||||
)
|
||||
}
|
||||
|
||||
fun renderType(texture: ResourceLocation): RenderType = renderType.apply(texture)
|
||||
|
||||
fun record(renderType: RenderType, draw: (VertexConsumer) -> Unit) {
|
||||
if (IrisCompatibility.isRenderingShadowPass()) return
|
||||
deferred.record(renderType, draw)
|
||||
}
|
||||
|
||||
fun draw() {
|
||||
if (deferred.isEmpty()) return
|
||||
val chain = chain ?: return deferred.discard()
|
||||
val main = Minecraft.getInstance().mainRenderTarget
|
||||
|
||||
val mask = chain.getTempTarget("mask")
|
||||
mask.setClearColor(0F, 0F, 0F, 0F)
|
||||
mask.clear(Minecraft.ON_OSX)
|
||||
mask.copyDepthFrom(main)
|
||||
deferred.drawAll()
|
||||
|
||||
chain.process(0F)
|
||||
main.bindWrite(false)
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_COLOR)
|
||||
chain.getTempTarget("swap").blitToScreen(main.width, main.height, false)
|
||||
RenderSystem.disableBlend()
|
||||
RenderSystem.defaultBlendFunc()
|
||||
}
|
||||
|
||||
|
||||
fun load() {
|
||||
close()
|
||||
val minecraft = Minecraft.getInstance()
|
||||
chain = try {
|
||||
PostChain(minecraft.textureManager, minecraft.resourceManager, minecraft.mainRenderTarget, CHAIN_LOCATION).also {
|
||||
it.resize(minecraft.mainRenderTarget.width, minecraft.mainRenderTarget.height)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Failed to load tera halo post chain $CHAIN_LOCATION", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun resize(width: Int, height: Int) {
|
||||
chain?.resize(width, height)
|
||||
}
|
||||
|
||||
fun close() {
|
||||
chain?.close()
|
||||
chain = null
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
data class TeraRender(val overlay: RenderType, val halo: RenderType, val tint: Int)
|
||||
|
||||
object TeraOverlay {
|
||||
private const val ASPECT = "terastal"
|
||||
|
||||
@@ -60,9 +62,9 @@ object TeraOverlay {
|
||||
)
|
||||
}
|
||||
|
||||
fun forAspects(aspects: Set<String>, texture: ResourceLocation): Pair<RenderType, Int>? {
|
||||
fun forAspects(aspects: Set<String>, texture: ResourceLocation): TeraRender? {
|
||||
val aspect = aspects.firstOrNull { it == ASPECT || it.startsWith("$ASPECT-") } ?: return null
|
||||
val hue = ElementalTypes.get(aspect.removePrefix(ASPECT).removePrefix("-"))?.hue
|
||||
return renderType.apply(texture) to (0xFF000000.toInt() or (hue ?: 0xFFFFFF))
|
||||
return TeraRender(renderType.apply(texture), TeraHalo.renderType(texture), 0xFF000000.toInt() or (hue ?: 0xFFFFFF))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,7 @@ object IrisCompatibility {
|
||||
private val shaderPackInUse = api?.getMethod("isShaderPackInUse")
|
||||
private val renderingShadowPass = api?.getMethod("isRenderingShadowPass")
|
||||
|
||||
private val bytes = ByteBufferBuilder(1 shl 18)
|
||||
private val deferred = mutableListOf<Pair<RenderType, MeshData>>()
|
||||
private val modelView = Matrix4f()
|
||||
private val projection = Matrix4f()
|
||||
private val deferred = DeferredMeshes()
|
||||
|
||||
fun isShaderPackInUse() = shaderPackInUse?.invoke(instance) == true
|
||||
|
||||
@@ -38,18 +35,36 @@ object IrisCompatibility {
|
||||
if (!isShaderPackInUse()) return draw(provider.getBuffer(renderType))
|
||||
if (isRenderingShadowPass()) return
|
||||
|
||||
if (deferred.isEmpty()) {
|
||||
modelView.set(RenderSystem.getModelViewMatrix())
|
||||
projection.set(RenderSystem.getProjectionMatrix())
|
||||
}
|
||||
val builder = BufferBuilder(bytes, renderType.mode(), renderType.format())
|
||||
draw(builder)
|
||||
builder.build()?.let { deferred += renderType to it }
|
||||
deferred.record(renderType, draw)
|
||||
}
|
||||
|
||||
fun drawDeferred() {
|
||||
if (deferred.isEmpty()) return
|
||||
Minecraft.getInstance().mainRenderTarget.bindWrite(false)
|
||||
deferred.drawAll()
|
||||
}
|
||||
}
|
||||
|
||||
/** Meshes recorded during level rendering, drawn later with the camera matrices they were recorded under. */
|
||||
class DeferredMeshes {
|
||||
private val bytes = ByteBufferBuilder(1 shl 18)
|
||||
private val meshes = mutableListOf<Pair<RenderType, MeshData>>()
|
||||
private val modelView = Matrix4f()
|
||||
private val projection = Matrix4f()
|
||||
|
||||
fun isEmpty() = meshes.isEmpty()
|
||||
|
||||
fun record(renderType: RenderType, draw: (VertexConsumer) -> Unit) {
|
||||
if (meshes.isEmpty()) {
|
||||
modelView.set(RenderSystem.getModelViewMatrix())
|
||||
projection.set(RenderSystem.getProjectionMatrix())
|
||||
}
|
||||
val builder = BufferBuilder(bytes, renderType.mode(), renderType.format())
|
||||
draw(builder)
|
||||
builder.build()?.let { meshes += renderType to it }
|
||||
}
|
||||
|
||||
fun drawAll() {
|
||||
RenderSystem.backupProjectionMatrix()
|
||||
RenderSystem.setProjectionMatrix(projection, VertexSorting.DISTANCE_TO_ORIGIN)
|
||||
val stack = RenderSystem.getModelViewStack()
|
||||
@@ -57,11 +72,16 @@ object IrisCompatibility {
|
||||
stack.set(modelView)
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
|
||||
deferred.forEach { (renderType, mesh) -> renderType.draw(mesh) }
|
||||
deferred.clear()
|
||||
meshes.forEach { (renderType, mesh) -> renderType.draw(mesh) }
|
||||
meshes.clear()
|
||||
|
||||
stack.popMatrix()
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
RenderSystem.restoreProjectionMatrix()
|
||||
}
|
||||
|
||||
fun discard() {
|
||||
meshes.forEach { it.second.close() }
|
||||
meshes.clear()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"targets": [
|
||||
"mask",
|
||||
"swap",
|
||||
"glow"
|
||||
],
|
||||
"passes": [
|
||||
{
|
||||
"name": "cobblemon_tera_halo_blur",
|
||||
"intarget": "mask",
|
||||
"outtarget": "swap",
|
||||
"use_linear_filter": true,
|
||||
"uniforms": [
|
||||
{ "name": "BlurDir", "values": [ 1.0, 0.0 ] },
|
||||
{ "name": "Radius", "values": [ 16.0 ] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cobblemon_tera_halo_blur",
|
||||
"intarget": "swap",
|
||||
"outtarget": "glow",
|
||||
"use_linear_filter": true,
|
||||
"uniforms": [
|
||||
{ "name": "BlurDir", "values": [ 0.0, 1.0 ] },
|
||||
{ "name": "Radius", "values": [ 16.0 ] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cobblemon_tera_halo_blur",
|
||||
"intarget": "glow",
|
||||
"outtarget": "swap",
|
||||
"use_linear_filter": true,
|
||||
"uniforms": [
|
||||
{ "name": "BlurDir", "values": [ 1.0, 0.0 ] },
|
||||
{ "name": "Radius", "values": [ 32.0 ] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cobblemon_tera_halo_blur",
|
||||
"intarget": "swap",
|
||||
"outtarget": "glow",
|
||||
"use_linear_filter": true,
|
||||
"uniforms": [
|
||||
{ "name": "BlurDir", "values": [ 0.0, 1.0 ] },
|
||||
{ "name": "Radius", "values": [ 32.0 ] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cobblemon_tera_halo_composite",
|
||||
"intarget": "glow",
|
||||
"outtarget": "swap",
|
||||
"auxtargets": [
|
||||
{ "name": "MaskSampler", "id": "mask" }
|
||||
],
|
||||
"uniforms": [
|
||||
{ "name": "Strength", "values": [ 1.0 ] }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D DiffuseSampler;
|
||||
uniform vec2 InSize;
|
||||
// How far the blur reaches, in pixels on a 1080p screen
|
||||
uniform float Radius;
|
||||
|
||||
in vec2 texCoord;
|
||||
in vec2 sampleStep;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
const float WEIGHTS[5] = float[](0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
|
||||
|
||||
void main() {
|
||||
vec2 tap = sampleStep * Radius * (InSize.y / 1080.0) / 4.0;
|
||||
vec4 color = texture(DiffuseSampler, texCoord) * WEIGHTS[0];
|
||||
for (int i = 1; i < 5; i++) {
|
||||
color += texture(DiffuseSampler, texCoord + tap * float(i)) * WEIGHTS[i];
|
||||
color += texture(DiffuseSampler, texCoord - tap * float(i)) * WEIGHTS[i];
|
||||
}
|
||||
fragColor = color;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"blend": {
|
||||
"func": "add",
|
||||
"srcrgb": "one",
|
||||
"dstrgb": "zero"
|
||||
},
|
||||
"vertex": "blur",
|
||||
"fragment": "cobblemon_tera_halo_blur",
|
||||
"attributes": [ "Position" ],
|
||||
"samplers": [
|
||||
{ "name": "DiffuseSampler" }
|
||||
],
|
||||
"uniforms": [
|
||||
{ "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
|
||||
{ "name": "InSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
|
||||
{ "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
|
||||
{ "name": "BlurDir", "type": "float", "count": 2, "values": [ 1.0, 0.0 ] },
|
||||
{ "name": "Radius", "type": "float", "count": 1, "values": [ 20.0 ] }
|
||||
]
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D DiffuseSampler;
|
||||
uniform sampler2D MaskSampler;
|
||||
uniform float Strength;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// How much the glow is dimmed over the mon itself, so the crystal overlay stays readable
|
||||
const float INNER_DIM = 0.9;
|
||||
|
||||
void main() {
|
||||
vec3 glow = texture(DiffuseSampler, texCoord).rgb;
|
||||
float inside = texture(MaskSampler, texCoord).a;
|
||||
fragColor = vec4(min(glow * Strength, vec3(1.0)) * (1.0 - INNER_DIM * inside), 1.0);
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"blend": {
|
||||
"func": "add",
|
||||
"srcrgb": "one",
|
||||
"dstrgb": "zero"
|
||||
},
|
||||
"vertex": "sobel",
|
||||
"fragment": "cobblemon_tera_halo_composite",
|
||||
"attributes": [ "Position" ],
|
||||
"samplers": [
|
||||
{ "name": "DiffuseSampler" },
|
||||
{ "name": "MaskSampler" }
|
||||
],
|
||||
"uniforms": [
|
||||
{ "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
|
||||
{ "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
|
||||
{ "name": "Strength", "type": "float", "count": 1, "values": [ 2.2 ] }
|
||||
]
|
||||
}
|
||||
@@ -71,6 +71,7 @@ transitive-accessible field net/minecraft/client/renderer/RenderStateShard NO_CU
|
||||
transitive-accessible field net/minecraft/client/renderer/RenderStateShard COLOR_WRITE Lnet/minecraft/client/renderer/RenderStateShard$WriteMaskStateShard;
|
||||
transitive-accessible field net/minecraft/client/renderer/RenderStateShard NO_DEPTH_TEST Lnet/minecraft/client/renderer/RenderStateShard$DepthTestStateShard;
|
||||
transitive-accessible class net/minecraft/client/renderer/RenderStateShard$DepthTestStateShard
|
||||
transitive-accessible class net/minecraft/client/renderer/RenderStateShard$OutputStateShard
|
||||
transitive-accessible field net/minecraft/client/renderer/RenderStateShard LEQUAL_DEPTH_TEST Lnet/minecraft/client/renderer/RenderStateShard$DepthTestStateShard;
|
||||
transitive-accessible field net/minecraft/client/renderer/RenderStateShard GLINT_TRANSPARENCY Lnet/minecraft/client/renderer/RenderStateShard$TransparencyStateShard;
|
||||
transitive-accessible field net/minecraft/client/renderer/RenderStateShard ADDITIVE_TRANSPARENCY Lnet/minecraft/client/renderer/RenderStateShard$TransparencyStateShard;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"client.ItemInHandLayerMixin",
|
||||
"client.ItemInHandRendererMixin",
|
||||
"client.ItemRendererMixin",
|
||||
"client.LevelRendererMixin",
|
||||
"client.LivingEntityRendererMixin",
|
||||
"client.LocalPlayerMixin",
|
||||
"client.ModelLoaderMixin",
|
||||
|
||||
Reference in New Issue
Block a user