Instanced entities are lit

This commit is contained in:
JozsefA 2021-06-09 00:26:54 -07:00
parent 1ce141850b
commit b4a1fbf2c7
11 changed files with 220 additions and 70 deletions

View file

@ -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;

View file

@ -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())

View file

@ -54,6 +54,35 @@ public abstract class EntityInstance<E extends Entity> 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()}.
*
* <br><br> 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.
*
* <br> If your model needs it, update light here.
*/
public void updateLight() {
}
/**
* Just before {@link #update()} would be called, <code>shouldReset()</code> is checked.
* If this function returns <code>true</code>, 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 <code>true</code> 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

View file

@ -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<Entity> queuedAdditions;
//protected final ConcurrentHashMap.KeySetView<Entity, Boolean> queuedUpdates;
protected final ConcurrentHashMap.KeySetView<Entity, Boolean> queuedUpdates;
protected final Map<Entity, EntityInstance<?>> instances;
protected final Object2ObjectOpenHashMap<Entity, ITickableInstance> 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 <T extends Entity> void onLightUpdate(T tile) {
// if (!Backend.getInstance().canUseInstancing()) return;
//
// if (tile instanceof IInstanceRendered) {
// EntityInstance<? super T> instance = getInstance(tile, false);
//
// if (instance != null)
// instance.updateLight();
// }
// }
public <T extends Entity> void onLightUpdate(T tile) {
if (!Backend.getInstance().canUseInstancing()) return;
if (tile instanceof IInstanceRendered) {
EntityInstance<? super T> instance = getInstance(tile, false);
if (instance != null)
instance.updateLight();
}
}
public <T extends Entity> void add(T entity) {
if (!Backend.getInstance().canUseInstancing()) return;
@ -145,24 +146,24 @@ public class EntityInstanceManager implements MaterialManager.OriginShiftListene
}
}
// public <T extends Entity> void update(T tile) {
// if (!Backend.getInstance().canUseInstancing()) return;
//
// if (tile instanceof IInstanceRendered) {
// EntityInstance<? super T> instance = getInstance(tile, false);
//
// if (instance != null) {
//
// if (instance.shouldReset()) {
// removeInternal(tile, instance);
//
// createInternal(tile);
// } else {
// instance.update();
// }
// }
// }
// }
public <T extends Entity> void update(T tile) {
if (!Backend.getInstance().canUseInstancing()) return;
if (tile instanceof IInstanceRendered) {
EntityInstance<? super T> instance = getInstance(tile, false);
if (instance != null) {
if (instance.shouldReset()) {
removeInternal(tile, instance);
createInternal(tile);
} else {
instance.update();
}
}
}
}
public <T extends Entity> void remove(T entity) {
if (!Backend.getInstance().canUseInstancing()) return;
@ -178,11 +179,11 @@ public class EntityInstanceManager implements MaterialManager.OriginShiftListene
queuedAdditions.add(tile);
}
// public synchronized <T extends Entity> void queueUpdate(T tile) {
// if (!Backend.getInstance().canUseInstancing()) return;
//
// queuedUpdates.add(tile);
// }
public synchronized <T extends Entity> 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<? super T> renderer = InstancedRenderRegistry.getInstance().create(materialManager, tile);
if (renderer != null) {
//renderer.updateLight();
renderer.updateLight();
instances.put(tile, renderer);
if (renderer instanceof IDynamicInstance)

View file

@ -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<StitchedSprite> 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);
}
}

View file

@ -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;
}
}

View file

@ -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() {
}
}

View file

@ -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();

View file

@ -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<SuperGlueEntity> implements ITickableInstance {
@ -33,7 +37,7 @@ public class GlueInstance extends EntityInstance<SuperGlueEntity> implements ITi
public GlueInstance(MaterialManager<?> materialManager, SuperGlueEntity entity) {
super(materialManager, entity);
Instancer<OrientedData> instancer = materialManager.getMaterial(Materials.ORIENTED, TEXTURE)
Instancer<OrientedData> instancer = materialManager.getMaterial(Materials.ORIENTED)
.get(entity.getType(), GlueInstance::supplyModel);
Direction face = entity.getFacingDirection();
@ -59,9 +63,20 @@ public class GlueInstance extends EntityInstance<SuperGlueEntity> 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<SuperGlueEntity> 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();

View file

@ -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()

View file

@ -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()