diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index 7d8e23579..80cb2facb 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; public class Backend { public static final Logger log = LogManager.getLogger(Backend.class); - private static final Backend INSTANCE = new Backend(); + public static Backend INSTANCE; public static Backend getInstance() { return INSTANCE; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java index 2a67adac9..02408eb68 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java @@ -83,6 +83,10 @@ public class InstancedRenderDispatcher { getTiles(te.getWorld()).queueUpdate(te); } + public static void enqueueUpdate(Entity entity) { + getEntities(entity.world).queueUpdate(entity); + } + @SubscribeEvent public static void onBeginFrame(BeginFrameEvent event) { Contexts.WORLD.getMaterialManager(event.getWorld()) diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstance.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstance.java index 80c438853..2500ac960 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstance.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstance.java @@ -54,6 +54,35 @@ public abstract class EntityInstance implements IInstance { */ public abstract void remove(); + /** + * Update instance data here. Good for when data doesn't change very often and when animations are GPU based. + * Don't query lighting data here, that's handled separately in {@link #updateLight()}. + * + *

If your animations are complex or more CPU driven, see {@link IDynamicInstance} or {@link ITickableInstance}. + */ + public void update() { + } + + /** + * Called after construction and when a light update occurs in the world. + * + *
If your model needs it, update light here. + */ + public void updateLight() { + } + + /** + * Just before {@link #update()} would be called, shouldReset() is checked. + * If this function returns true, then this instance will be {@link #remove removed}, + * and another instance will be constructed to replace it. This allows for more sane resource + * acquisition compared to trying to update everything within the lifetime of an instance. + * + * @return true if this instance should be discarded and refreshed. + */ + public boolean shouldReset() { + return false; + } + /** * In order to accommodate for floating point precision errors at high coordinates, * {@link TileInstanceManager}s are allowed to arbitrarily adjust the origin, and diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstanceManager.java index 6345053d9..59c68b1f4 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstanceManager.java @@ -3,6 +3,7 @@ package com.jozufozu.flywheel.backend.instancing.entity; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nullable; @@ -26,7 +27,7 @@ public class EntityInstanceManager implements MaterialManager.OriginShiftListene public final MaterialManager materialManager; protected final ArrayList queuedAdditions; - //protected final ConcurrentHashMap.KeySetView queuedUpdates; + protected final ConcurrentHashMap.KeySetView queuedUpdates; protected final Map> instances; protected final Object2ObjectOpenHashMap tickableInstances; @@ -37,7 +38,7 @@ public class EntityInstanceManager implements MaterialManager.OriginShiftListene public EntityInstanceManager(MaterialManager materialManager) { this.materialManager = materialManager; - //this.queuedUpdates = ConcurrentHashMap.newKeySet(64); + this.queuedUpdates = ConcurrentHashMap.newKeySet(64); this.queuedAdditions = new ArrayList<>(64); this.instances = new HashMap<>(); @@ -72,12 +73,12 @@ public class EntityInstanceManager implements MaterialManager.OriginShiftListene instance.tick(); } } -// -// queuedUpdates.forEach(te -> { -// queuedUpdates.remove(te); -// -// update(te); -// }); + + queuedUpdates.forEach(te -> { + queuedUpdates.remove(te); + + update(te); + }); } public void beginFrame(ActiveRenderInfo info) { @@ -126,16 +127,16 @@ public class EntityInstanceManager implements MaterialManager.OriginShiftListene } } -// public void onLightUpdate(T tile) { -// if (!Backend.getInstance().canUseInstancing()) return; -// -// if (tile instanceof IInstanceRendered) { -// EntityInstance instance = getInstance(tile, false); -// -// if (instance != null) -// instance.updateLight(); -// } -// } + public void onLightUpdate(T tile) { + if (!Backend.getInstance().canUseInstancing()) return; + + if (tile instanceof IInstanceRendered) { + EntityInstance instance = getInstance(tile, false); + + if (instance != null) + instance.updateLight(); + } + } public void add(T entity) { if (!Backend.getInstance().canUseInstancing()) return; @@ -145,24 +146,24 @@ public class EntityInstanceManager implements MaterialManager.OriginShiftListene } } -// public void update(T tile) { -// if (!Backend.getInstance().canUseInstancing()) return; -// -// if (tile instanceof IInstanceRendered) { -// EntityInstance instance = getInstance(tile, false); -// -// if (instance != null) { -// -// if (instance.shouldReset()) { -// removeInternal(tile, instance); -// -// createInternal(tile); -// } else { -// instance.update(); -// } -// } -// } -// } + public void update(T tile) { + if (!Backend.getInstance().canUseInstancing()) return; + + if (tile instanceof IInstanceRendered) { + EntityInstance instance = getInstance(tile, false); + + if (instance != null) { + + if (instance.shouldReset()) { + removeInternal(tile, instance); + + createInternal(tile); + } else { + instance.update(); + } + } + } + } public void remove(T entity) { if (!Backend.getInstance().canUseInstancing()) return; @@ -178,11 +179,11 @@ public class EntityInstanceManager implements MaterialManager.OriginShiftListene queuedAdditions.add(tile); } -// public synchronized void queueUpdate(T tile) { -// if (!Backend.getInstance().canUseInstancing()) return; -// -// queuedUpdates.add(tile); -// } + public synchronized void queueUpdate(T tile) { + if (!Backend.getInstance().canUseInstancing()) return; + + queuedUpdates.add(tile); + } protected synchronized void processQueuedAdditions() { if (queuedAdditions.size() > 0) { @@ -233,7 +234,7 @@ public class EntityInstanceManager implements MaterialManager.OriginShiftListene EntityInstance renderer = InstancedRenderRegistry.getInstance().create(materialManager, tile); if (renderer != null) { - //renderer.updateLight(); + renderer.updateLight(); instances.put(tile, renderer); if (renderer instanceof IDynamicInstance) diff --git a/src/main/java/com/jozufozu/flywheel/core/AtlasStitcher.java b/src/main/java/com/jozufozu/flywheel/core/AtlasStitcher.java new file mode 100644 index 000000000..bd22d54c9 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/AtlasStitcher.java @@ -0,0 +1,45 @@ +package com.jozufozu.flywheel.core; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.inventory.container.PlayerContainer; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.eventbus.api.IEventBus; + +/** + * This is primarily for hacking entity textures into the block atlas. + */ +public class AtlasStitcher { + public static AtlasStitcher INSTANCE; + + public static AtlasStitcher getInstance() { + return INSTANCE; + } + + public AtlasStitcher(IEventBus modEventBus) { + modEventBus.addListener(this::onTextureStitch); + } + + private final List sprites = new ArrayList<>(); + + public StitchedSprite get(ResourceLocation loc) { + StitchedSprite sprite = new StitchedSprite(loc); + + sprites.add(sprite); + + return sprite; + } + + public void onTextureStitch(TextureStitchEvent.Pre event) { + if (!event.getMap() + .getId() + .equals(PlayerContainer.BLOCK_ATLAS_TEXTURE)) + return; + + sprites.stream() + .map(StitchedSprite::getLoc) + .forEach(event::addSprite); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/StitchedSprite.java b/src/main/java/com/jozufozu/flywheel/core/StitchedSprite.java new file mode 100644 index 000000000..b9536b7ec --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/StitchedSprite.java @@ -0,0 +1,31 @@ +package com.jozufozu.flywheel.core; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.inventory.container.PlayerContainer; +import net.minecraft.util.ResourceLocation; + +public class StitchedSprite { + + private final ResourceLocation loc; + + TextureAtlasSprite sprite; + + public StitchedSprite(ResourceLocation loc) { + this.loc = loc; + } + + public ResourceLocation getLoc() { + return loc; + } + + public TextureAtlasSprite getSprite() { + if (sprite == null) { + sprite = Minecraft.getInstance() + .getSpriteAtlas(PlayerContainer.BLOCK_ATLAS_TEXTURE) + .apply(loc); + } + + return sprite; + } +} diff --git a/src/main/java/com/simibubi/create/AllStitchedTextures.java b/src/main/java/com/simibubi/create/AllStitchedTextures.java new file mode 100644 index 000000000..30482c457 --- /dev/null +++ b/src/main/java/com/simibubi/create/AllStitchedTextures.java @@ -0,0 +1,15 @@ +package com.simibubi.create; + +import com.jozufozu.flywheel.core.AtlasStitcher; +import com.jozufozu.flywheel.core.StitchedSprite; + +import net.minecraft.util.ResourceLocation; + +public class AllStitchedTextures { + + public static final StitchedSprite SUPER_GLUE = AtlasStitcher.getInstance().get(new ResourceLocation(Create.ID, "entity/super_glue/slime")); + + public static void init() { + + } +} diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index 95771076c..5d5ce5a4f 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -6,6 +6,7 @@ import java.util.Map; import java.util.function.Function; import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.AtlasStitcher; import com.jozufozu.flywheel.core.PartialModel; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; @@ -77,7 +78,8 @@ public class CreateClient { modEventBus.addListener(AllParticleTypes::registerFactories); modEventBus.addListener(ClientEvents::loadCompleted); - Backend.getInstance(); + Backend.INSTANCE = new Backend(); + AtlasStitcher.INSTANCE = new AtlasStitcher(modEventBus); } public static void clientInit(FMLClientSetupEvent event) { @@ -88,6 +90,7 @@ public class CreateClient { AllKeys.register(); // AllFluids.assignRenderLayers(); AllBlockPartials.clientInit(); + AllStitchedTextures.init(); PonderIndex.register(); PonderIndex.registerTags(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueInstance.java index f05438baa..cc171a904 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueInstance.java @@ -12,16 +12,20 @@ import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.instancing.ConditionalInstance; import com.jozufozu.flywheel.core.materials.OrientedData; import com.simibubi.create.AllItems; +import com.simibubi.create.AllStitchedTextures; import com.simibubi.create.Create; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Quaternion; import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.world.LightType; public class GlueInstance extends EntityInstance implements ITickableInstance { @@ -33,7 +37,7 @@ public class GlueInstance extends EntityInstance implements ITi public GlueInstance(MaterialManager materialManager, SuperGlueEntity entity) { super(materialManager, entity); - Instancer instancer = materialManager.getMaterial(Materials.ORIENTED, TEXTURE) + Instancer instancer = materialManager.getMaterial(Materials.ORIENTED) .get(entity.getType(), GlueInstance::supplyModel); Direction face = entity.getFacingDirection(); @@ -59,9 +63,20 @@ public class GlueInstance extends EntityInstance implements ITi model.setPosition(getInstancePosition()) .setPivot(0, 0, 0) - .setRotation(rotation) - .setSkyLight(15) - .setBlockLight(15); + .setRotation(rotation); + + updateLight(model); + } + + @Override + public void updateLight() { + model.get().ifPresent(this::updateLight); + } + + private void updateLight(OrientedData model) { + BlockPos pos = entity.getHangingPosition(); + model.setBlockLight(world.getLightLevel(LightType.BLOCK, pos)) + .setSkyLight(world.getLightLevel(LightType.SKY, pos)); } private boolean shouldShow() { @@ -99,17 +114,19 @@ public class GlueInstance extends EntityInstance implements ITi VecBuffer buffer = VecBuffer.allocate(Formats.UNLIT_MODEL.getStride() * 8); + TextureAtlasSprite sprite = AllStitchedTextures.SUPER_GLUE.getSprite(); + // pos normal uv // inside quad - buffer.putVec3((float) a1.x, (float) a1.y, (float) a1.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(1f, 0f); - buffer.putVec3((float) a2.x, (float) a2.y, (float) a2.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(1f, 1f); - buffer.putVec3((float) a3.x, (float) a3.y, (float) a3.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(0f, 1f); - buffer.putVec3((float) a4.x, (float) a4.y, (float) a4.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(0f, 0f); + buffer.putVec3((float) a1.x, (float) a1.y, (float) a1.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(sprite.getMaxU(), sprite.getMinV()); + buffer.putVec3((float) a2.x, (float) a2.y, (float) a2.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(sprite.getMaxU(), sprite.getMaxV()); + buffer.putVec3((float) a3.x, (float) a3.y, (float) a3.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(sprite.getMinU(), sprite.getMaxV()); + buffer.putVec3((float) a4.x, (float) a4.y, (float) a4.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(sprite.getMinU(), sprite.getMinV()); // outside quad - buffer.putVec3((float) b4.x, (float) b4.y, (float) b4.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(0f, 0f); - buffer.putVec3((float) b3.x, (float) b3.y, (float) b3.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(0f, 1f); - buffer.putVec3((float) b2.x, (float) b2.y, (float) b2.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(1f, 1f); - buffer.putVec3((float) b1.x, (float) b1.y, (float) b1.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(1f, 0f); + buffer.putVec3((float) b4.x, (float) b4.y, (float) b4.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(sprite.getMinU(), sprite.getMinV()); + buffer.putVec3((float) b3.x, (float) b3.y, (float) b3.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(sprite.getMinU(), sprite.getMaxV()); + buffer.putVec3((float) b2.x, (float) b2.y, (float) b2.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(sprite.getMaxU(), sprite.getMaxV()); + buffer.putVec3((float) b1.x, (float) b1.y, (float) b1.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(sprite.getMaxU(), sprite.getMinV()); buffer.rewind(); diff --git a/src/main/java/com/simibubi/create/foundation/mixin/flywheel/light/LightUpdateMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/flywheel/light/LightUpdateMixin.java index 1ee536982..27085583a 100644 --- a/src/main/java/com/simibubi/create/foundation/mixin/flywheel/light/LightUpdateMixin.java +++ b/src/main/java/com/simibubi/create/foundation/mixin/flywheel/light/LightUpdateMixin.java @@ -40,15 +40,16 @@ public abstract class LightUpdateMixin extends AbstractChunkProvider { if (chunk != null) { chunk.getTileEntityMap() - .entrySet() - .stream() - .filter(entry -> SectionPos.toChunk(entry.getKey() - .getY()) == sectionY) - .map(Map.Entry::getValue) - .forEach(tile -> { - InstancedRenderDispatcher.getTiles(world) - .onLightUpdate(tile); - }); + .entrySet() + .stream() + .filter(entry -> SectionPos.toChunk(entry.getKey() + .getY()) == sectionY) + .map(Map.Entry::getValue) + .forEach(InstancedRenderDispatcher.getTiles(world)::onLightUpdate); + + if (sectionY >= 0) // TODO: 1.17 + chunk.getEntityLists()[sectionY] + .forEach(InstancedRenderDispatcher.getEntities(world)::onLightUpdate); } LightUpdater.getInstance() diff --git a/src/main/java/com/simibubi/create/foundation/mixin/flywheel/light/NetworkLightUpdateMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/flywheel/light/NetworkLightUpdateMixin.java index fe706092a..15ebb2afc 100644 --- a/src/main/java/com/simibubi/create/foundation/mixin/flywheel/light/NetworkLightUpdateMixin.java +++ b/src/main/java/com/simibubi/create/foundation/mixin/flywheel/light/NetworkLightUpdateMixin.java @@ -1,5 +1,7 @@ package com.simibubi.create.foundation.mixin.flywheel.light; +import java.util.Arrays; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -13,6 +15,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.network.play.ClientPlayNetHandler; import net.minecraft.client.world.ClientWorld; import net.minecraft.network.play.server.SUpdateLightPacket; +import net.minecraft.util.ClassInheritanceMultiMap; import net.minecraft.world.chunk.Chunk; @Mixin(ClientPlayNetHandler.class) @@ -34,11 +37,12 @@ public class NetworkLightUpdateMixin { if (chunk != null) { chunk.getTileEntityMap() - .values() - .forEach(tile -> { - InstancedRenderDispatcher.getTiles(world) - .onLightUpdate(tile); - }); + .values() + .forEach(InstancedRenderDispatcher.getTiles(world)::onLightUpdate); + + Arrays.stream(chunk.getEntityLists()) + .flatMap(ClassInheritanceMultiMap::stream) + .forEach(InstancedRenderDispatcher.getEntities(world)::onLightUpdate); } LightUpdater.getInstance()