Skip to content

Commit

Permalink
Fluid render api (#14)
Browse files Browse the repository at this point in the history
* Fix YabnOps

* Fluid rendering api

* fog and overlay

* fix blunder

* add sprite cache to renderFluid

* add forgotten fabric overlay impl

* use state instead of fluid

* Update mc version
  • Loading branch information
ThatGravyBoat authored Jun 10, 2024
1 parent a82a862 commit 30fe26e
Show file tree
Hide file tree
Showing 21 changed files with 584 additions and 67 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package com.teamresourceful.resourcefullib.client.fluid.data;

import com.mojang.blaze3d.shaders.FogShape;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import com.mojang.datafixers.util.Function3;
import com.mojang.datafixers.util.Function6;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.joml.Vector3f;

import java.util.function.Function;

public interface ClientFluidProperties {

ResourceLocation still(@Nullable BlockAndTintGetter view, @Nullable BlockPos pos, FluidState state);

ResourceLocation flowing(@Nullable BlockAndTintGetter view, @Nullable BlockPos pos, FluidState state);

ResourceLocation overlay(@Nullable BlockAndTintGetter view, @Nullable BlockPos pos, FluidState state);

ResourceLocation screenOverlay();

default void renderOverlay(Minecraft minecraft, PoseStack stack) {
ResourceLocation texture = screenOverlay();
if (texture != null) {
Player player = minecraft.player;
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderTexture(0, texture);

BlockPos blockpos = BlockPos.containing(player.getX(), player.getEyeY(), player.getZ());
float brightness = LightTexture.getBrightness(player.level().dimensionType(), player.level().getMaxLocalRawBrightness(blockpos));

BufferBuilder bufferbuilder = Tesselator.getInstance().getBuilder();
RenderSystem.enableBlend();
RenderSystem.setShaderColor(brightness, brightness, brightness, 0.1F);
float f7 = -player.getYRot() / 64.0F;
float f8 = player.getXRot() / 64.0F;
Matrix4f matrix4f = stack.last().pose();
bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX);
bufferbuilder.vertex(matrix4f, -1.0F, -1.0F, -0.5F).uv(4.0F + f7, 4.0F + f8).endVertex();
bufferbuilder.vertex(matrix4f, 1.0F, -1.0F, -0.5F).uv(0.0F + f7, 4.0F + f8).endVertex();
bufferbuilder.vertex(matrix4f, 1.0F, 1.0F, -0.5F).uv(0.0F + f7, 0.0F + f8).endVertex();
bufferbuilder.vertex(matrix4f, -1.0F, 1.0F, -0.5F).uv(4.0F + f7, 0.0F + f8).endVertex();
BufferUploader.drawWithShader(bufferbuilder.end());
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.disableBlend();
}
}

int tintColor(@Nullable BlockAndTintGetter view, @Nullable BlockPos pos, FluidState state);

default boolean renderFluid(
BlockPos pos,
BlockAndTintGetter world, VertexConsumer vertexConsumer,
BlockState blockState, FluidState fluidState,
Function<ResourceLocation, TextureAtlasSprite> sprites
) {
return false;
}

default Vector3f modifyFogColor(Camera camera, float partialTick, ClientLevel level, int renderDistance, float darkenWorldAmount, Vector3f fluidFogColor) {
return fluidFogColor;
}

default void modifyFogRender(Camera camera, FogRenderer.FogMode mode, float renderDistance, float partialTick, float nearDistance, float farDistance, FogShape shape) {

}

static ClientFluidProperties.Builder builder() {
return new ClientFluidProperties.Builder();
}

class Builder {

private Function3<BlockAndTintGetter, BlockPos, FluidState, ResourceLocation> still = (a, b, c) -> null;
private Function3<BlockAndTintGetter, BlockPos, FluidState, ResourceLocation> flowing = (a, b, c) -> null;
private Function3<BlockAndTintGetter, BlockPos, FluidState, ResourceLocation> overlay = (a, b, c) -> null;
private ResourceLocation screenOverlay = null;
private Function3<BlockAndTintGetter, BlockPos, FluidState, Integer> tintColor = (a, b, c) -> -1;
private Function6<BlockPos, BlockAndTintGetter, VertexConsumer, BlockState, FluidState, Function<ResourceLocation, TextureAtlasSprite>, Boolean> renderFluid = (a, b, c, d, e, f) -> false;

public Builder still(ResourceLocation still) {
this.still = (a, b, c) -> still;
return this;
}

public Builder flowing(ResourceLocation flowing) {
this.flowing = (a, b, c) -> flowing;
return this;
}

public Builder overlay(ResourceLocation overlay) {
this.overlay = (a, b, c) -> overlay;
return this;
}

public Builder screenOverlay(ResourceLocation screenOverlay) {
this.screenOverlay = screenOverlay;
return this;
}

public Builder tintColor(Function3<BlockAndTintGetter, BlockPos, FluidState, Integer> tintColor) {
this.tintColor = tintColor;
return this;
}

public Builder tintColor(int tintColor) {
this.tintColor = (a, b, c) -> tintColor;
return this;
}

public Builder renderFluid(Function6<BlockPos, BlockAndTintGetter, VertexConsumer, BlockState, FluidState, Function<ResourceLocation, TextureAtlasSprite>, Boolean> renderFluid) {
this.renderFluid = renderFluid;
return this;
}

public ClientFluidProperties build() {
return new ClientFluidProperties() {

@Override
public ResourceLocation still(@Nullable BlockAndTintGetter view, @Nullable BlockPos pos, FluidState state) {
return still.apply(view, pos, state);
}

@Override
public ResourceLocation flowing(@Nullable BlockAndTintGetter view, @Nullable BlockPos pos, FluidState state) {
return flowing.apply(view, pos, state);
}

@Override
public ResourceLocation overlay(@Nullable BlockAndTintGetter view, @Nullable BlockPos pos, FluidState state) {
return overlay.apply(view, pos, state);
}

@Override
public ResourceLocation screenOverlay() {
return screenOverlay;
}

@Override
public int tintColor(@Nullable BlockAndTintGetter view, @Nullable BlockPos pos, FluidState state) {
return tintColor.apply(view, pos, state);
}

@Override
public boolean renderFluid(BlockPos pos, BlockAndTintGetter world, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState, Function<ResourceLocation, TextureAtlasSprite> sprites) {
return renderFluid.apply(pos, world, vertexConsumer, blockState, fluidState, sprites);
}
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.teamresourceful.resourcefullib.client.fluid.registry;

import com.teamresourceful.resourcefullib.client.fluid.data.ClientFluidProperties;
import com.teamresourceful.resourcefullib.common.registry.HolderRegistryEntry;
import com.teamresourceful.resourcefullib.common.registry.RegistryEntries;
import com.teamresourceful.resourcefullib.common.registry.RegistryEntry;
import com.teamresourceful.resourcefullib.common.registry.ResourcefulRegistry;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.ApiStatus;

import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

public class ResourcefulClientFluidRegistry implements ResourcefulRegistry<ClientFluidProperties> {

private static final Map<ResourceLocation, ClientFluidProperties> REGISTRY = new ConcurrentHashMap<>();

private final String modid;
private final RegistryEntries<ClientFluidProperties> entries = new RegistryEntries<>();

public ResourcefulClientFluidRegistry(String modid) {
this.modid = modid;
}

public RegistryEntry<ClientFluidProperties> register(String id, ClientFluidProperties.Builder builder) {
return register(id, builder::build);
}

@Override
public <I extends ClientFluidProperties> RegistryEntry<I> register(String id, Supplier<I> supplier) {
REGISTRY.put(new ResourceLocation(this.modid, id), supplier.get());
return entries.add(new Entry<>(new ResourceLocation(this.modid, id), supplier.get()));
}

/**
* @hidden use {@link #register(String, ClientFluidProperties.Builder)} instead
*/
@ApiStatus.Internal
@Deprecated
@Override
public HolderRegistryEntry<ClientFluidProperties> registerHolder(String id, Supplier<ClientFluidProperties> supplier) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Use register(String, ClientFluidProperties.Builder) instead.");
}

@Override
public Collection<RegistryEntry<ClientFluidProperties>> getEntries() {
return entries.getEntries();
}

@Override
public void init() {

}

@ApiStatus.Internal
public static ClientFluidProperties get(ResourceLocation id) {
return REGISTRY.get(id);
}

private record Entry<T extends ClientFluidProperties>(ResourceLocation id, T data) implements RegistryEntry<T> {

@Override
public T get() {
return this.data;
}

@Override
public ResourceLocation getId() {
return this.id;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.teamresourceful.resourcefullib.client.registry;

import com.teamresourceful.resourcefullib.client.fluid.registry.ResourcefulClientFluidRegistry;
import com.teamresourceful.resourcefullib.common.registry.ResourcefulRegistry;
import com.teamresourceful.resourcefullib.common.registry.ResourcefulRegistryChild;
import com.teamresourceful.resourcefullib.common.registry.ResourcefulRegistryType;
import dev.architectury.injectables.annotations.ExpectPlatform;
import net.minecraft.core.Registry;
import org.apache.commons.lang3.NotImplementedException;

public class ResourcefulClientRegistries {

@SuppressWarnings("unchecked")
public static <D, T extends ResourcefulRegistry<D>> T create(ResourcefulClientRegistryType<D, T> type, String id) {
if (type == ResourcefulClientRegistryType.FLUID) {
return (T) new ResourcefulClientFluidRegistry(id);
}
throw new NotImplementedException("Unknown registry type: " + type);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.teamresourceful.resourcefullib.client.registry;

import com.teamresourceful.resourcefullib.client.fluid.data.ClientFluidProperties;
import com.teamresourceful.resourcefullib.client.fluid.registry.ResourcefulClientFluidRegistry;
import com.teamresourceful.resourcefullib.common.registry.ResourcefulRegistry;
import org.jetbrains.annotations.ApiStatus;

public final class ResourcefulClientRegistryType<D, T extends ResourcefulRegistry<D>> {

@ApiStatus.Experimental
public static final ResourcefulClientRegistryType<ClientFluidProperties, ResourcefulClientFluidRegistry> FLUID = new ResourcefulClientRegistryType<>(
ResourcefulClientFluidRegistry.class
);

private final Class<T> type;

private ResourcefulClientRegistryType(Class<T> type) {
this.type = type;
}

@Override
public String toString() {
return "ResourcefulClientRegistryType{type=" + type + "}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ public YabnElement get(YabnElement key) {
@Nullable
@Override
public YabnElement get(String key) {
YabnElement element = object.elements().get(key);
return element == null ? null : element.getOrNull();
return object.elements().get(key);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ public DataResult<Stream<Pair<YabnElement, YabnElement>>> getMapValues(YabnEleme
Stream<Pair<YabnElement, YabnElement>> output = object.elements()
.entrySet()
.stream()
.map(entry -> Pair.of(createString(entry.getKey()), entry.getValue().getOrNull()));
.map(entry -> Pair.of(createString(entry.getKey()), entry.getValue()));
return DataResult.success(output);
}
return DataResult.error(() -> "Not a YABN Object: " + input);
Expand All @@ -179,7 +179,7 @@ public DataResult<Stream<Pair<YabnElement, YabnElement>>> getMapValues(YabnEleme
@Override
public DataResult<Consumer<BiConsumer<YabnElement, YabnElement>>> getMapEntries(YabnElement input) {
if (input instanceof YabnObject object) {
return DataResult.success(c -> object.elements().forEach((key, value) -> c.accept(createString(key), value.getOrNull())));
return DataResult.success(c -> object.elements().forEach((key, value) -> c.accept(createString(key), value)));
}
return DataResult.error(() -> "Not a YABN Object: " + input);
}
Expand All @@ -200,15 +200,15 @@ public YabnElement createMap(Stream<Pair<YabnElement, YabnElement>> map) {
@Override
public DataResult<Stream<YabnElement>> getStream(YabnElement input) {
if (input instanceof YabnArray array) {
return DataResult.success(array.elements().stream().map(YabnElement::getOrNull));
return DataResult.success(array.elements().stream());
}
return DataResult.error(() -> "Not a YABN Array: " + input);
}

@Override
public DataResult<Consumer<Consumer<YabnElement>>> getList(YabnElement input) {
if (input instanceof YabnArray array) {
return DataResult.success(c -> array.elements().forEach(e -> c.accept(e.getOrNull())));
return DataResult.success(c -> array.elements().forEach(c));
}
return DataResult.error(() -> "Not a YABN Array: " + input);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.teamresourceful.resourcefullib.common.fluid.data;

import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.material.FlowingFluid;
Expand All @@ -9,6 +10,8 @@

public interface FluidData {

ResourceLocation id();

FluidProperties properties();

Supplier<? extends FlowingFluid> still();
Expand Down
Loading

0 comments on commit 30fe26e

Please sign in to comment.