Ported Outline utility to 1.15

- Outliner can now be used in 1.15
- Ported Chassis range display to use new Outlines
This commit is contained in:
simibubi 2020-05-15 17:13:38 +02:00
parent afd6ec17e0
commit 071482bb26
16 changed files with 525 additions and 370 deletions

View file

@ -1,5 +1,7 @@
package com.simibubi.create; package com.simibubi.create;
import static com.simibubi.create.foundation.utility.data.BlockStateGen.oxidizedBlockstate;
import static com.simibubi.create.foundation.utility.data.ModelGen.oxidizedItemModel;
import static com.simibubi.create.modules.Sections.SCHEMATICS; import static com.simibubi.create.modules.Sections.SCHEMATICS;
import com.simibubi.create.foundation.registrate.CreateRegistrate; import com.simibubi.create.foundation.registrate.CreateRegistrate;
@ -21,8 +23,6 @@ import com.tterrag.registrate.builders.ItemBuilder;
import com.tterrag.registrate.util.DataIngredient; import com.tterrag.registrate.util.DataIngredient;
import com.tterrag.registrate.util.entry.BlockEntry; import com.tterrag.registrate.util.entry.BlockEntry;
import com.tterrag.registrate.util.nullness.NonNullFunction; import com.tterrag.registrate.util.nullness.NonNullFunction;
import com.tterrag.registrate.util.nullness.NonNullSupplier;
import com.tterrag.registrate.util.nullness.NonNullUnaryOperator;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
@ -33,15 +33,13 @@ import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags; import net.minecraft.tags.ItemTags;
import net.minecraft.tags.Tag; import net.minecraft.tags.Tag;
import net.minecraft.tags.TagCollection; import net.minecraft.tags.TagCollection;
import net.minecraft.util.IItemProvider;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.generators.ConfiguredModel;
import net.minecraftforge.common.ToolType; import net.minecraftforge.common.ToolType;
public class AllBlocksNew { public class AllBlocksNew {
private static final CreateRegistrate REGISTRATE = Create.registrate() private static final CreateRegistrate REGISTRATE = Create.registrate()
.itemGroup(() -> Create.baseCreativeTab); .itemGroup(() -> Create.baseCreativeTab);
static { static {
REGISTRATE.startSection(SCHEMATICS); REGISTRATE.startSection(SCHEMATICS);
@ -123,76 +121,68 @@ public class AllBlocksNew {
.model(AssetLookup::customItemModel) .model(AssetLookup::customItemModel)
.build() .build()
.register(); .register();
static { REGISTRATE.startSection(Sections.MATERIALS); } static {
REGISTRATE.startSection(Sections.MATERIALS);
public static final BlockEntry<OxidizingBlock> COPPER_ORE = REGISTRATE.block("copper_ore", p -> new OxidizingBlock(p, 1)) }
.initialProperties(() -> Blocks.IRON_ORE)
.transform(oxidizedBlockstate()) public static final BlockEntry<OxidizingBlock> COPPER_ORE =
.transform(tagBlockAndItem("ores/copper")) REGISTRATE.block("copper_ore", p -> new OxidizingBlock(p, 1))
.initialProperties(() -> Blocks.IRON_ORE)
.transform(oxidizedBlockstate())
.transform(tagBlockAndItem("ores/copper"))
.transform(oxidizedItemModel()) .transform(oxidizedItemModel())
.register(); .register();
public static final BlockEntry<Block> ZINC_ORE = REGISTRATE.block("zinc_ore", Block::new) public static final BlockEntry<Block> ZINC_ORE = REGISTRATE.block("zinc_ore", Block::new)
.initialProperties(() -> Blocks.GOLD_BLOCK) .initialProperties(() -> Blocks.GOLD_BLOCK)
.properties(p -> p.harvestLevel(2).harvestTool(ToolType.PICKAXE)) .properties(p -> p.harvestLevel(2)
.harvestTool(ToolType.PICKAXE))
.transform(tagBlockAndItem("ores/zinc")) .transform(tagBlockAndItem("ores/zinc"))
.build() .build()
.register(); .register();
public static final BlockEntry<OxidizingBlock> COPPER_BLOCK = REGISTRATE.block("copper_block", p -> new OxidizingBlock(p, 1 / 32f)) public static final BlockEntry<OxidizingBlock> COPPER_BLOCK =
.initialProperties(() -> Blocks.IRON_BLOCK) REGISTRATE.block("copper_block", p -> new OxidizingBlock(p, 1 / 32f))
.transform(tagBlockAndItem("storage_blocks/copper")) .initialProperties(() -> Blocks.IRON_BLOCK)
.transform(tagBlockAndItem("storage_blocks/copper"))
.transform(oxidizedItemModel()) .transform(oxidizedItemModel())
.recipe((ctx, prov) -> prov.square(DataIngredient.tag(forgeItemTag("ingots/copper")), ctx, false)) .recipe((ctx, prov) -> prov.square(DataIngredient.tag(forgeItemTag("ingots/copper")), ctx, false))
.transform(oxidizedBlockstate()) .transform(oxidizedBlockstate())
.register(); .register();
public static final BlockEntry<OxidizingBlock> COPPER_SHINGLES = REGISTRATE.block("copper_shingles", p -> new OxidizingBlock(p, 1 / 32f)) public static final BlockEntry<OxidizingBlock> COPPER_SHINGLES =
.initialProperties(() -> Blocks.IRON_BLOCK) REGISTRATE.block("copper_shingles", p -> new OxidizingBlock(p, 1 / 32f))
.item().transform(oxidizedItemModel()) .initialProperties(() -> Blocks.IRON_BLOCK)
.recipe((ctx, prov) -> prov.square(DataIngredient.tag(forgeItemTag("plates/copper")), ctx, true)) .item()
.transform(oxidizedBlockstate()) .transform(oxidizedItemModel())
.register(); .recipe((ctx, prov) -> prov.square(DataIngredient.tag(forgeItemTag("plates/copper")), ctx, true))
.transform(oxidizedBlockstate())
.register();
public static final BlockEntry<Block> ZINC_BLOCK = REGISTRATE.block("zinc_block", Block::new) public static final BlockEntry<Block> ZINC_BLOCK = REGISTRATE.block("zinc_block", Block::new)
.initialProperties(() -> Blocks.IRON_BLOCK) .initialProperties(() -> Blocks.IRON_BLOCK)
.transform(tagBlockAndItem("storage_blocks/zinc")) .transform(tagBlockAndItem("storage_blocks/zinc"))
.build() .build()
.recipe((ctx, prov) -> prov.square(DataIngredient.tag(forgeItemTag("ingots/zinc")), ctx, false)) .recipe((ctx, prov) -> prov.square(DataIngredient.tag(forgeItemTag("ingots/zinc")), ctx, false))
.register(); .register();
public static final BlockEntry<Block> BRASS_BLOCK = REGISTRATE.block("brass_block", Block::new) public static final BlockEntry<Block> BRASS_BLOCK = REGISTRATE.block("brass_block", Block::new)
.initialProperties(() -> Blocks.IRON_BLOCK) .initialProperties(() -> Blocks.IRON_BLOCK)
.transform(tagBlockAndItem("storage_blocks/brass")) .transform(tagBlockAndItem("storage_blocks/brass"))
.build() .build()
.recipe((ctx, prov) -> prov.square(DataIngredient.tag(forgeItemTag("ingots/brass")), ctx, false)) .recipe((ctx, prov) -> prov.square(DataIngredient.tag(forgeItemTag("ingots/brass")), ctx, false))
.register(); .register();
// Utility
private static String getOxidizedModel(String name, int level) { private static <T extends Block, P> NonNullFunction<BlockBuilder<T, P>, ItemBuilder<BlockItem, BlockBuilder<T, P>>> tagBlockAndItem(
return "block/oxidized/" + name + "_" + level; String tagName) {
} return b -> b.tag(forgeBlockTag(tagName))
.item()
private static <P> NonNullUnaryOperator<BlockBuilder<OxidizingBlock, P>> oxidizedBlockstate() { .tag(forgeItemTag(tagName));
return b -> b.blockstate((ctx, prov) -> prov.getVariantBuilder(ctx.getEntry())
.forAllStates(state -> {
String name = getOxidizedModel(ctx.getName(), state.get(OxidizingBlock.OXIDIZATION));
return ConfiguredModel.builder()
.modelFile(prov.models().cubeAll(name, prov.modLoc(name)))
.build();
}));
}
private static <P> NonNullFunction<ItemBuilder<BlockItem, P>, P> oxidizedItemModel() {
return b -> b.model((ctx, prov) -> prov.withExistingParent(ctx.getName(), prov.modLoc(getOxidizedModel(ctx.getName(), 0)))).build();
} }
private static <T extends Block, P> NonNullFunction<BlockBuilder<T, P>, ItemBuilder<BlockItem, BlockBuilder<T, P>>> tagBlockAndItem(String tagName) {
return b -> b.tag(forgeBlockTag(tagName))
.item()
.tag(forgeItemTag(tagName));
}
private static Tag<Block> forgeBlockTag(String name) { private static Tag<Block> forgeBlockTag(String name) {
return forgeTag(BlockTags.getCollection(), name); return forgeTag(BlockTags.getCollection(), name);
} }
@ -200,15 +190,15 @@ public class AllBlocksNew {
private static Tag<Item> forgeItemTag(String name) { private static Tag<Item> forgeItemTag(String name) {
return forgeTag(ItemTags.getCollection(), name); return forgeTag(ItemTags.getCollection(), name);
} }
private static <T> Tag<T> forgeTag(TagCollection<T> collection, String name) { private static <T> Tag<T> forgeTag(TagCollection<T> collection, String name) {
return tag(collection, "forge", name); return tag(collection, "forge", name);
} }
private static <T> Tag<T> tag(TagCollection<T> collection, String domain, String name) { private static <T> Tag<T> tag(TagCollection<T> collection, String domain, String name) {
return collection.getOrCreate(new ResourceLocation(domain, name)); return collection.getOrCreate(new ResourceLocation(domain, name));
} }
public static void register() {} public static void register() {}
} }

View file

@ -25,5 +25,9 @@ public enum AllSpecialTextures {
public void bind() { public void bind() {
Minecraft.getInstance().getTextureManager().bindTexture(location); Minecraft.getInstance().getTextureManager().bindTexture(location);
} }
public ResourceLocation getLocation() {
return location;
}
} }

View file

@ -12,7 +12,6 @@ import com.simibubi.create.foundation.item.TooltipHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.modules.contraptions.KineticDebugger; import com.simibubi.create.modules.contraptions.KineticDebugger;
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.modules.contraptions.components.contraptions.ChassisRangeDisplay;
import com.simibubi.create.modules.contraptions.components.turntable.TurntableHandler; import com.simibubi.create.modules.contraptions.components.turntable.TurntableHandler;
import com.simibubi.create.modules.contraptions.relays.belt.item.BeltConnectorHandler; import com.simibubi.create.modules.contraptions.relays.belt.item.BeltConnectorHandler;
import com.simibubi.create.modules.curiosities.zapper.terrainzapper.TerrainZapperRenderHandler; import com.simibubi.create.modules.curiosities.zapper.terrainzapper.TerrainZapperRenderHandler;
@ -74,18 +73,21 @@ public class ClientEvents {
MatrixStack ms = event.getMatrixStack(); MatrixStack ms = event.getMatrixStack();
ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo(); ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo();
Vec3d view = info.getProjectedView(); Vec3d view = info.getProjectedView();
ms.push(); ms.push();
ms.translate(-view.getX(), -view.getY(), -view.getZ()); ms.translate(-view.getX(), -view.getY(), -view.getZ());
IRenderTypeBuffer.Impl buffer = Minecraft.getInstance().getBufferBuilders().getEntityVertexConsumers(); IRenderTypeBuffer.Impl buffer = Minecraft.getInstance()
.getBufferBuilders()
.getEntityVertexConsumers();
CreateClient.schematicHandler.render(ms, buffer, 0xF000F0, OverlayTexture.DEFAULT_UV); CreateClient.schematicHandler.render(ms, buffer, 0xF000F0, OverlayTexture.DEFAULT_UV);
CreateClient.outliner.renderOutlines(ms, buffer);
KineticDebugger.renderSourceOutline(ms, buffer); KineticDebugger.renderSourceOutline(ms, buffer);
ChassisRangeDisplay.renderOutlines(event.getPartialTicks(), ms, buffer);
TerrainZapperRenderHandler.render(ms, buffer); TerrainZapperRenderHandler.render(ms, buffer);
ms.pop(); ms.pop();
buffer.draw(); buffer.draw();
} }
@ -94,8 +96,9 @@ public class ClientEvents {
if (event.getType() != ElementType.HOTBAR) if (event.getType() != ElementType.HOTBAR)
return; return;
onRenderHotbar(new MatrixStack(), Minecraft.getInstance().getBufferBuilders().getEntityVertexConsumers(), onRenderHotbar(new MatrixStack(), Minecraft.getInstance()
0xF000F0, OverlayTexture.DEFAULT_UV); .getBufferBuilders()
.getEntityVertexConsumers(), 0xF000F0, OverlayTexture.DEFAULT_UV);
} }
public static void onRenderHotbar(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { public static void onRenderHotbar(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) {
@ -121,9 +124,8 @@ public class ClientEvents {
double delta = event.getScrollDelta(); double delta = event.getScrollDelta();
boolean cancelled = CreateClient.schematicHandler.mouseScrolled(delta) boolean cancelled = CreateClient.schematicHandler.mouseScrolled(delta)
|| CreateClient.schematicAndQuillHandler.mouseScrolled(delta) || CreateClient.schematicAndQuillHandler.mouseScrolled(delta) || FilteringHandler.onScroll(delta)
|| FilteringHandler.onScroll(delta) || ScrollValueHandler.onScroll(delta);
|| ScrollValueHandler.onScroll(delta);
event.setCanceled(cancelled); event.setCanceled(cancelled);
} }
@ -147,7 +149,8 @@ public class ClientEvents {
return; return;
ItemStack stack = event.getItemStack(); ItemStack stack = event.getItemStack();
String translationKey = stack.getItem().getTranslationKey(stack); String translationKey = stack.getItem()
.getTranslationKey(stack);
if (!translationKey.startsWith(itemPrefix) && !translationKey.startsWith(blockPrefix)) if (!translationKey.startsWith(itemPrefix) && !translationKey.startsWith(blockPrefix))
return; return;
@ -155,7 +158,8 @@ public class ClientEvents {
List<ITextComponent> itemTooltip = event.getToolTip(); List<ITextComponent> itemTooltip = event.getToolTip();
List<ITextComponent> toolTip = new ArrayList<>(); List<ITextComponent> toolTip = new ArrayList<>();
toolTip.add(itemTooltip.remove(0)); toolTip.add(itemTooltip.remove(0));
TooltipHelper.getTooltip(stack).addInformation(toolTip); TooltipHelper.getTooltip(stack)
.addInformation(toolTip);
itemTooltip.addAll(0, toolTip); itemTooltip.addAll(0, toolTip);
} }

View file

@ -9,6 +9,7 @@ import com.simibubi.create.foundation.block.render.CustomBlockModels;
import com.simibubi.create.foundation.block.render.SpriteShifter; import com.simibubi.create.foundation.block.render.SpriteShifter;
import com.simibubi.create.foundation.item.IHaveCustomItemModel; import com.simibubi.create.foundation.item.IHaveCustomItemModel;
import com.simibubi.create.foundation.utility.SuperByteBufferCache; import com.simibubi.create.foundation.utility.SuperByteBufferCache;
import com.simibubi.create.foundation.utility.outliner.Outliner;
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.modules.contraptions.components.contraptions.ChassisRangeDisplay; import com.simibubi.create.modules.contraptions.components.contraptions.ChassisRangeDisplay;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionRenderer; import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionRenderer;
@ -41,6 +42,7 @@ public class CreateClient {
public static SchematicHandler schematicHandler; public static SchematicHandler schematicHandler;
public static SchematicAndQuillHandler schematicAndQuillHandler; public static SchematicAndQuillHandler schematicAndQuillHandler;
public static SuperByteBufferCache bufferCache; public static SuperByteBufferCache bufferCache;
public static Outliner outliner;
private static CustomBlockModels customBlockModels; private static CustomBlockModels customBlockModels;
public static void addListeners(IEventBus modEventBus) { public static void addListeners(IEventBus modEventBus) {
@ -57,6 +59,7 @@ public class CreateClient {
schematicSender = new ClientSchematicLoader(); schematicSender = new ClientSchematicLoader();
schematicHandler = new SchematicHandler(); schematicHandler = new SchematicHandler();
schematicAndQuillHandler = new SchematicAndQuillHandler(); schematicAndQuillHandler = new SchematicAndQuillHandler();
outliner = new Outliner();
bufferCache = new SuperByteBufferCache(); bufferCache = new SuperByteBufferCache();
bufferCache.registerCompartment(KineticTileEntityRenderer.KINETIC_TILE); bufferCache.registerCompartment(KineticTileEntityRenderer.KINETIC_TILE);
@ -74,11 +77,12 @@ public class CreateClient {
if (resourceManager instanceof IReloadableResourceManager) if (resourceManager instanceof IReloadableResourceManager)
((IReloadableResourceManager) resourceManager).addReloadListener(new ResourceReloadHandler()); ((IReloadableResourceManager) resourceManager).addReloadListener(new ResourceReloadHandler());
} }
public static void gameTick() { public static void gameTick() {
schematicSender.tick(); schematicSender.tick();
schematicAndQuillHandler.tick(); schematicAndQuillHandler.tick();
schematicHandler.tick(); schematicHandler.tick();
outliner.tickOutlines();
ChassisRangeDisplay.clientTick(); ChassisRangeDisplay.clientTick();
} }

View file

@ -3,10 +3,13 @@ package com.simibubi.create.foundation.utility.data;
import java.util.function.Function; import java.util.function.Function;
import com.simibubi.create.foundation.world.OxidizingBlock;
import com.simibubi.create.modules.palettes.PavedBlock; import com.simibubi.create.modules.palettes.PavedBlock;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.providers.DataGenContext; import com.tterrag.registrate.providers.DataGenContext;
import com.tterrag.registrate.providers.RegistrateBlockstateProvider; import com.tterrag.registrate.providers.RegistrateBlockstateProvider;
import com.tterrag.registrate.util.nullness.NonNullBiConsumer; import com.tterrag.registrate.util.nullness.NonNullBiConsumer;
import com.tterrag.registrate.util.nullness.NonNullUnaryOperator;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -56,4 +59,14 @@ public class BlockStateGen {
.build()); .build());
} }
public static <P> NonNullUnaryOperator<BlockBuilder<OxidizingBlock, P>> oxidizedBlockstate() {
return b -> b.blockstate((ctx, prov) -> prov.getVariantBuilder(ctx.getEntry())
.forAllStates(state -> {
String name = ModelGen.getOxidizedModel(ctx.getName(), state.get(OxidizingBlock.OXIDIZATION));
return ConfiguredModel.builder()
.modelFile(prov.models().cubeAll(name, prov.modLoc(name)))
.build();
}));
}
} }

View file

@ -1,9 +1,12 @@
package com.simibubi.create.foundation.utility.data; package com.simibubi.create.foundation.utility.data;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.tterrag.registrate.builders.ItemBuilder;
import com.tterrag.registrate.providers.DataGenContext; import com.tterrag.registrate.providers.DataGenContext;
import com.tterrag.registrate.util.nullness.NonNullFunction;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.item.BlockItem;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.generators.BlockStateProvider; import net.minecraftforge.client.model.generators.BlockStateProvider;
import net.minecraftforge.client.model.generators.ModelFile; import net.minecraftforge.client.model.generators.ModelFile;
@ -26,4 +29,12 @@ public class ModelGen {
.texture("overlay", overlay); .texture("overlay", overlay);
} }
public static <P> NonNullFunction<ItemBuilder<BlockItem, P>, P> oxidizedItemModel() {
return b -> b.model((ctx, prov) -> prov.withExistingParent(ctx.getName(), prov.modLoc(ModelGen.getOxidizedModel(ctx.getName(), 0)))).build();
}
public static String getOxidizedModel(String name, int level) {
return "block/oxidized/" + name + "_" + level;
}
} }

View file

@ -1,13 +1,16 @@
package com.simibubi.create.foundation.utility.outliner; package com.simibubi.create.foundation.utility.outliner;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder; import com.mojang.blaze3d.vertex.IVertexBuilder;
import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.ColorHelper;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -24,10 +27,10 @@ public class AABBOutline extends Outline {
} }
@Override @Override
public void render(BufferBuilder buffer) { public void render(MatrixStack ms, IRenderTypeBuffer buffer) {
Vec3d color = ColorHelper.getRGB(0xFFFFFF); Vec3d color = ColorHelper.getRGB(0xFFFFFF);
float alpha = 1f; float alpha = 1f;
renderBB(bb, buffer, color, alpha, !disableCull); renderBB(ms, buffer, bb, color, alpha, !disableCull);
} }
public void setTextures(AllSpecialTextures faceTexture, AllSpecialTextures highlightTexture) { public void setTextures(AllSpecialTextures faceTexture, AllSpecialTextures highlightTexture) {
@ -39,8 +42,10 @@ public class AABBOutline extends Outline {
this.highlightedFace = face; this.highlightedFace = face;
} }
public void renderBB(AxisAlignedBB bb, IVertexBuilder builder, Vec3d color, float alpha, boolean doCulling) { public void renderBB(MatrixStack ms, IRenderTypeBuffer buffer, AxisAlignedBB bb, Vec3d color, float alpha,
Vec3d projectedView = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView(); boolean doCulling) {
Vec3d projectedView = Minecraft.getInstance().gameRenderer.getActiveRenderInfo()
.getProjectedView();
boolean inside = bb.contains(projectedView); boolean inside = bb.contains(projectedView);
bb = bb.grow(inside ? -1 / 128d : 1 / 128d); bb = bb.grow(inside ? -1 / 128d : 1 / 128d);
@ -53,50 +58,54 @@ public class AABBOutline extends Outline {
Vec3d xYZ = new Vec3d(bb.minX, bb.maxY, bb.maxZ); Vec3d xYZ = new Vec3d(bb.minX, bb.maxY, bb.maxZ);
Vec3d XYZ = new Vec3d(bb.maxX, bb.maxY, bb.maxZ); Vec3d XYZ = new Vec3d(bb.maxX, bb.maxY, bb.maxZ);
renderFace(Direction.NORTH, xYz, XYz, Xyz, xyz, builder);
renderFace(Direction.SOUTH, XYZ, xYZ, xyZ, XyZ, builder);
renderFace(Direction.EAST, XYz, XYZ, XyZ, Xyz, builder);
renderFace(Direction.WEST, xYZ, xYz, xyz, xyZ, builder);
renderFace(Direction.UP, xYZ, XYZ, XYz, xYz, builder);
renderFace(Direction.DOWN, xyz, Xyz, XyZ, xyZ, builder);
Vec3d start = xyz; Vec3d start = xyz;
AllSpecialTextures.BLANK.bind(); renderAACuboidLine(ms, buffer, start, Xyz);
renderAACuboidLine(start, Xyz, color, alpha, builder); renderAACuboidLine(ms, buffer, start, xYz);
renderAACuboidLine(start, xYz, color, alpha, builder); renderAACuboidLine(ms, buffer, start, xyZ);
renderAACuboidLine(start, xyZ, color, alpha, builder);
start = XyZ; start = XyZ;
renderAACuboidLine(start, xyZ, color, alpha, builder); renderAACuboidLine(ms, buffer, start, xyZ);
renderAACuboidLine(start, XYZ, color, alpha, builder); renderAACuboidLine(ms, buffer, start, XYZ);
renderAACuboidLine(start, Xyz, color, alpha, builder); renderAACuboidLine(ms, buffer, start, Xyz);
start = XYz; start = XYz;
renderAACuboidLine(start, xYz, color, alpha, builder); renderAACuboidLine(ms, buffer, start, xYz);
renderAACuboidLine(start, Xyz, color, alpha, builder); renderAACuboidLine(ms, buffer, start, Xyz);
renderAACuboidLine(start, XYZ, color, alpha, builder); renderAACuboidLine(ms, buffer, start, XYZ);
start = xYZ; start = xYZ;
renderAACuboidLine(start, XYZ, color, alpha, builder); renderAACuboidLine(ms, buffer, start, XYZ);
renderAACuboidLine(start, xyZ, color, alpha, builder); renderAACuboidLine(ms, buffer, start, xyZ);
renderAACuboidLine(start, xYz, color, alpha, builder); renderAACuboidLine(ms, buffer, start, xYz);
renderFace(ms, buffer, Direction.NORTH, xYz, XYz, Xyz, xyz, inside);
renderFace(ms, buffer, Direction.SOUTH, XYZ, xYZ, xyZ, XyZ, inside);
renderFace(ms, buffer, Direction.EAST, XYz, XYZ, XyZ, Xyz, inside);
renderFace(ms, buffer, Direction.WEST, xYZ, xYz, xyz, xyZ, inside);
renderFace(ms, buffer, Direction.UP, xYZ, XYZ, XYz, xYz, inside);
renderFace(ms, buffer, Direction.DOWN, xyz, Xyz, XyZ, xyZ, inside);
} }
protected void renderFace(Direction direction, Vec3d p1, Vec3d p2, Vec3d p3, Vec3d p4, IVertexBuilder builder) { protected void renderFace(MatrixStack ms, IRenderTypeBuffer buffer, Direction direction, Vec3d p1, Vec3d p2,
Vec3d p3, Vec3d p4, boolean noCull) {
ResourceLocation faceTexture = this.faceTexture.getLocation();
if (direction == highlightedFace && highlightedTexture != null) if (direction == highlightedFace && highlightedTexture != null)
highlightedTexture.bind(); faceTexture = highlightedTexture.getLocation();
else if (faceTexture != null) else if (faceTexture == null)
faceTexture.bind();
else
return; return;
RenderType translucentType =
noCull ? RenderType.getEntityTranslucent(faceTexture) : RenderType.getEntityTranslucentCull(faceTexture);
IVertexBuilder builder = buffer.getBuffer(translucentType);
Axis axis = direction.getAxis();
Vec3d uDiff = p2.subtract(p1); Vec3d uDiff = p2.subtract(p1);
Vec3d vDiff = p4.subtract(p1); Vec3d vDiff = p4.subtract(p1);
Axis axis = direction.getAxis();
float maxU = (float) Math.abs(axis == Axis.X ? uDiff.z : uDiff.x); float maxU = (float) Math.abs(axis == Axis.X ? uDiff.z : uDiff.x);
float maxV = (float) Math.abs(axis == Axis.Y ? vDiff.z : vDiff.y); float maxV = (float) Math.abs(axis == Axis.Y ? vDiff.z : vDiff.y);
putQuadUV(p1, p2, p3, p4, 0, 0, maxU, maxV, new Vec3d(1, 1, 1), 1, builder); putQuadUV(ms, builder, p1, p2, p3, p4, 0, 0, maxU, maxV);
} }
} }

View file

@ -3,12 +3,16 @@ package com.simibubi.create.foundation.utility.outliner;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.Direction.AxisDirection;
@ -18,41 +22,59 @@ import net.minecraft.util.math.Vec3d;
public class BlockClusterOutline extends Outline { public class BlockClusterOutline extends Outline {
private Cluster cluster; private Cluster cluster;
private float alpha;
public BlockClusterOutline(Iterable<BlockPos> selection) { public BlockClusterOutline(Iterable<BlockPos> selection) {
cluster = new Cluster(); cluster = new Cluster();
selection.forEach(cluster::include); selection.forEach(cluster::include);
alpha = .5f;
} }
@Override @Override
public void render(BufferBuilder buffer) { public void render(MatrixStack ms, IRenderTypeBuffer buffer) {
Vec3d color = ColorHelper.getRGB(0xDDDDDD); for (MergeEntry edge : cluster.visibleEdges) {
AllSpecialTextures.SELECTION.bind(); Vec3d start = new Vec3d(edge.pos);
Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, edge.axis);
renderAACuboidLine(ms, buffer, start, new Vec3d(edge.pos.offset(direction)));
}
for (MergeEntry face : cluster.visibleFaces.keySet()) { for (MergeEntry face : cluster.visibleFaces.keySet()) {
AxisDirection axisDirection = cluster.visibleFaces.get(face); AxisDirection axisDirection = cluster.visibleFaces.get(face);
Direction direction = Direction.getFacingFromAxis(axisDirection, face.axis); Direction direction = Direction.getFacingFromAxis(axisDirection, face.axis);
BlockPos pos = face.pos; BlockPos pos = face.pos;
if (axisDirection == AxisDirection.POSITIVE) if (axisDirection == AxisDirection.POSITIVE)
pos = pos.offset(direction.getOpposite()); pos = pos.offset(direction.getOpposite());
renderFace(pos, direction, color, alpha * .25f, 1 / 64d, buffer); renderBlockFace(ms, buffer, pos, direction);
} }
AllSpecialTextures.BLANK.bind();
for (MergeEntry edge : cluster.visibleEdges) {
lineWidth = 1 / 16f * alpha;
Vec3d start = new Vec3d(edge.pos);
Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, edge.axis);
renderAACuboidLine(start, new Vec3d(edge.pos.offset(direction)), color, 1, buffer);
}
} }
public void setAlpha(float alpha) { protected void renderBlockFace(MatrixStack ms, IRenderTypeBuffer buffer, BlockPos pos, Direction face) {
this.alpha = alpha; Optional<AllSpecialTextures> faceTexture = params.faceTexture;
if (!faceTexture.isPresent())
return;
RenderType translucentType = RenderType.getEntityTranslucent(faceTexture.get()
.getLocation());
IVertexBuilder builder = buffer.getBuffer(translucentType);
Vec3d center = VecHelper.getCenterOf(pos);
Vec3d offset = new Vec3d(face.getDirectionVec());
Vec3d plane = VecHelper.planeByNormal(offset);
Axis axis = face.getAxis();
offset = offset.scale(1 / 2f + 1 / 64d);
plane = plane.scale(1 / 2f)
.add(offset);
int deg = face.getAxisDirection()
.getOffset() * 90;
Vec3d a1 = plane.add(center);
plane = VecHelper.rotate(plane, deg, axis);
Vec3d a2 = plane.add(center);
plane = VecHelper.rotate(plane, deg, axis);
Vec3d a3 = plane.add(center);
plane = VecHelper.rotate(plane, deg, axis);
Vec3d a4 = plane.add(center);
putQuad(ms, builder, a1, a2, a3, a4);
} }
private static class Cluster { private static class Cluster {

View file

@ -1,9 +1,10 @@
package com.simibubi.create.foundation.utility.outliner; package com.simibubi.create.foundation.utility.outliner;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.ColorHelper;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -23,24 +24,25 @@ public class ChasingAABBOutline extends AABBOutline {
targetBB = target; targetBB = target;
} }
@Override
public void tick() { public void tick() {
prevBB = bb; prevBB = bb;
bb = interpolateBBs(bb, targetBB, .5f); bb = interpolateBBs(bb, targetBB, .5f);
} }
@Override @Override
public void render(BufferBuilder buffer) { public void render(MatrixStack ms, IRenderTypeBuffer buffer) {
Vec3d color = ColorHelper.getRGB(0xFFFFFF); Vec3d color = ColorHelper.getRGB(0xFFFFFF);
float alpha = 1f; float alpha = 1f;
renderBB(interpolateBBs(prevBB, bb, Minecraft.getInstance().getRenderPartialTicks()), buffer, color, alpha, renderBB(ms, buffer, interpolateBBs(prevBB, bb, Minecraft.getInstance()
true); .getRenderPartialTicks()), color, alpha, true);
} }
private static AxisAlignedBB interpolateBBs(AxisAlignedBB current, AxisAlignedBB target, float pt) { private static AxisAlignedBB interpolateBBs(AxisAlignedBB current, AxisAlignedBB target, float pt) {
return new AxisAlignedBB(MathHelper.lerp(pt, current.minX, target.minX), return new AxisAlignedBB(MathHelper.lerp(pt, current.minX, target.minX),
MathHelper.lerp(pt, current.minY, target.minY), MathHelper.lerp(pt, current.minZ, target.minZ), MathHelper.lerp(pt, current.minY, target.minY), MathHelper.lerp(pt, current.minZ, target.minZ),
MathHelper.lerp(pt, current.maxX, target.maxX), MathHelper.lerp(pt, current.maxY, target.maxY), MathHelper.lerp(pt, current.maxX, target.maxX), MathHelper.lerp(pt, current.maxY, target.maxY),
MathHelper.lerp(pt, current.maxZ, target.maxZ)); MathHelper.lerp(pt, current.maxZ, target.maxZ));
} }
} }

View file

@ -1,21 +1,34 @@
package com.simibubi.create.foundation.utility.outliner; package com.simibubi.create.foundation.utility.outliner;
import java.util.Optional;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.matrix.MatrixStack.Entry;
import com.mojang.blaze3d.vertex.IVertexBuilder; import com.mojang.blaze3d.vertex.IVertexBuilder;
import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.foundation.utility.ColorHelper;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public abstract class Outline { public abstract class Outline {
protected float lineWidth = 1 / 32f; protected OutlineParams params;
public Outline() {
params = new OutlineParams();
}
public abstract void render(BufferBuilder buffer); public abstract void render(MatrixStack ms, IRenderTypeBuffer buffer);
public void renderAACuboidLine(MatrixStack ms, IRenderTypeBuffer buffer, Vec3d start, Vec3d end) {
IVertexBuilder builder = buffer.getBuffer(RenderType.getEntitySolid(AllSpecialTextures.BLANK.getLocation()));
public void renderAACuboidLine(Vec3d start, Vec3d end, Vec3d rgb, float alpha, IVertexBuilder builder) {
Vec3d diff = end.subtract(start); Vec3d diff = end.subtract(start);
if (diff.x + diff.y + diff.z < 0) { if (diff.x + diff.y + diff.z < 0) {
Vec3d temp = start; Vec3d temp = start;
@ -24,13 +37,17 @@ public abstract class Outline {
diff = diff.scale(-1); diff = diff.scale(-1);
} }
Vec3d extension = diff.normalize().scale(lineWidth / 2); float lineWidth = params.getLineWidth();
Vec3d extension = diff.normalize()
.scale(lineWidth / 2);
Vec3d plane = VecHelper.planeByNormal(diff); Vec3d plane = VecHelper.planeByNormal(diff);
Axis axis = Direction.getFacingFromVector(diff.x, diff.y, diff.z).getAxis(); Direction face = Direction.getFacingFromVector(diff.x, diff.y, diff.z);
Axis axis = face.getAxis();
start = start.subtract(extension); start = start.subtract(extension);
end = end.add(extension); end = end.add(extension);
plane = plane.scale(lineWidth / 2); plane = plane.scale(lineWidth / 2);
Vec3d a1 = plane.add(start); Vec3d a1 = plane.add(start);
Vec3d b1 = plane.add(end); Vec3d b1 = plane.add(end);
plane = VecHelper.rotate(plane, -90, axis); plane = VecHelper.rotate(plane, -90, axis);
@ -43,55 +60,92 @@ public abstract class Outline {
Vec3d a4 = plane.add(start); Vec3d a4 = plane.add(start);
Vec3d b4 = plane.add(end); Vec3d b4 = plane.add(end);
putQuad(b4, b3, b2, b1, rgb, alpha, builder); putQuad(ms, builder, b4, b3, b2, b1);
putQuad(a1, a2, a3, a4, rgb, alpha, builder); putQuad(ms, builder, a1, a2, a3, a4);
putQuad(ms, builder, a1, b1, b2, a2);
putQuad(a1, b1, b2, a2, rgb, alpha, builder); putQuad(ms, builder, a2, b2, b3, a3);
putQuad(a2, b2, b3, a3, rgb, alpha, builder); putQuad(ms, builder, a3, b3, b4, a4);
putQuad(a3, b3, b4, a4, rgb, alpha, builder); putQuad(ms, builder, a4, b4, b1, a1);
putQuad(a4, b4, b1, a1, rgb, alpha, builder);
} }
protected void renderFace(BlockPos pos, Direction face, Vec3d rgb, float alpha, double scaleOffset, public void putQuad(MatrixStack ms, IVertexBuilder builder, Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4) {
IVertexBuilder builder) { putQuadUV(ms, builder, v1, v2, v3, v4, 0, 0, 1, 1);
Vec3d center = VecHelper.getCenterOf(pos);
Vec3d offset = new Vec3d(face.getDirectionVec());
Vec3d plane = VecHelper.planeByNormal(offset);
Axis axis = face.getAxis();
offset = offset.scale(1 / 2f + scaleOffset);
plane = plane.scale(1 / 2f).add(offset);
int deg = face.getAxisDirection().getOffset() * 90;
Vec3d a1 = plane.add(center);
plane = VecHelper.rotate(plane, deg, axis);
Vec3d a2 = plane.add(center);
plane = VecHelper.rotate(plane, deg, axis);
Vec3d a3 = plane.add(center);
plane = VecHelper.rotate(plane, deg, axis);
Vec3d a4 = plane.add(center);
putQuad(a1, a2, a3, a4, rgb, alpha, builder);
} }
public void putQuad(Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4, Vec3d rgb, float alpha, IVertexBuilder builder) { public void putQuadUV(MatrixStack ms, IVertexBuilder builder, Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4, float minU,
putQuadUV(v1, v2, v3, v4, 0, 0, 1, 1, rgb, alpha, builder); float minV, float maxU, float maxV) {
putVertex(ms, builder, v1, minU, minV);
putVertex(ms, builder, v2, maxU, minV);
putVertex(ms, builder, v3, maxU, maxV);
putVertex(ms, builder, v4, minU, maxV);
} }
public void putQuadUV(Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4, float minU, float minV, float maxU, float maxV, protected void putVertex(MatrixStack ms, IVertexBuilder builder, Vec3d pos, float u, float v) {
Vec3d rgb, float alpha, IVertexBuilder builder) {
putVertex(v1, rgb, minU, minV, alpha, builder);
putVertex(v2, rgb, maxU, minV, alpha, builder);
putVertex(v3, rgb, maxU, maxV, alpha, builder);
putVertex(v4, rgb, minU, maxV, alpha, builder);
}
protected void putVertex(Vec3d pos, Vec3d rgb, float u, float v, float alpha, IVertexBuilder builder) {
int i = 15 << 20 | 15 << 4; int i = 15 << 20 | 15 << 4;
int j = i >> 16 & '\uffff'; int j = i >> 16 & '\uffff';
int k = i & '\uffff'; int k = i & '\uffff';
builder.vertex(pos.x, pos.y, pos.z).texture(u, v).color((float) rgb.x, (float) rgb.y, (float) rgb.z, alpha) Entry peek = ms.peek();
.light(j, k).endVertex(); Vec3d rgb = params.rgb;
builder.vertex(peek.getModel(), (float) pos.x, (float) pos.y, (float) pos.z)
.color((float) rgb.x, (float) rgb.y, (float) rgb.z, params.alpha)
.texture(u, v)
.overlay(OverlayTexture.DEFAULT_UV)
.light(j, k)
.normal(peek.getNormal(), 0, 1, 0)
.endVertex();
}
public void tick() {}
public OutlineParams getParams() {
return params;
}
public static class OutlineParams {
Optional<AllSpecialTextures> faceTexture;
Optional<AllSpecialTextures> hightlightedFaceTexture;
boolean fadeLineWidth;
float alpha;
private float lineWidth;
int lightMapU, lightMapV;
Vec3d rgb;
public OutlineParams() {
faceTexture = hightlightedFaceTexture = Optional.empty();
alpha = 1;
lineWidth = 1 / 32f;
fadeLineWidth = true;
rgb = ColorHelper.getRGB(0xFFFFFF);
int i = 15 << 20 | 15 << 4;
lightMapU = i >> 16 & '\uffff';
lightMapV = i & '\uffff';
}
// builder
public OutlineParams colored(int color) {
rgb = ColorHelper.getRGB(color);
return this;
}
public OutlineParams lineWidth(float width) {
this.lineWidth = width;
return this;
}
public OutlineParams withFaceTexture(AllSpecialTextures texture) {
this.faceTexture = Optional.of(texture);
return this;
}
// util
float getLineWidth() {
return fadeLineWidth ? alpha * lineWidth : lineWidth;
}
} }
} }

View file

@ -1,55 +0,0 @@
package com.simibubi.create.foundation.utility.outliner;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.player.ClientPlayerEntity;
import net.minecraft.client.particle.IParticleRenderType;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class OutlineParticle<O extends Outline> extends Particle {
protected O outline;
protected OutlineParticle(O outline, World worldIn, double xCoordIn, double yCoordIn, double zCoordIn) {
super(worldIn, xCoordIn, yCoordIn, zCoordIn);
this.outline = outline;
this.maxAge = 1024;
}
public static <O extends Outline> OutlineParticle<O> create(O outline) {
Minecraft mc = Minecraft.getInstance();
ClientPlayerEntity player = mc.player;
OutlineParticle<O> effect =
new OutlineParticle<>(outline, mc.world, player.getX(), player.getY(), player.getZ());
mc.particles.addEffect(effect);
return effect;
}
public void remove() {
isExpired = true;
}
@Override
public void buildGeometry(IVertexBuilder builder, ActiveRenderInfo renderInfo, float p_225606_3_) {
Vec3d view = renderInfo.getProjectedView();
// GlStateManager.translated(-view.x, -view.y, -view.z);
// TODO
// GlStateManager.enableBlend();
// getOutline().render(buffer);
// GlStateManager.disableBlend();
}
@Override
public IParticleRenderType getRenderType() {
return IParticleRenderType.CUSTOM;
}
public O getOutline() {
return outline;
}
}

View file

@ -0,0 +1,142 @@
package com.simibubi.create.foundation.utility.outliner;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
public class Outliner {
Map<Object, OutlineEntry> outlines;
// Facade
public OutlineParams showAABB(Object slot, AxisAlignedBB bb, ExpireType type) {
createAABBOutlineIfMissing(slot, bb, type);
ChasingAABBOutline outline = getAndRefreshAABB(slot);
outline.prevBB = outline.targetBB = bb;
return outline.getParams();
}
public OutlineParams chaseAABB(Object slot, AxisAlignedBB bb, ExpireType type) {
createAABBOutlineIfMissing(slot, bb, type);
ChasingAABBOutline outline = getAndRefreshAABB(slot);
outline.targetBB = bb;
return outline.getParams();
}
public OutlineParams showCluster(Object slot, Iterable<BlockPos> selection, ExpireType type) {
BlockClusterOutline outline = new BlockClusterOutline(selection);
OutlineEntry entry = new OutlineEntry(outline, type);
outlines.put(slot, entry);
return entry.getOutline()
.getParams();
}
public void keepCluster(Object slot) {
if (outlines.containsKey(slot))
outlines.get(slot).ticksTillRemoval = 1;
}
public void remove(Object slot) {
outlines.remove(slot);
}
// Utility
private void createAABBOutlineIfMissing(Object slot, AxisAlignedBB bb, ExpireType type) {
if (!outlines.containsKey(slot)) {
ChasingAABBOutline outline = new ChasingAABBOutline(bb);
outlines.put(slot, new OutlineEntry(outline, type));
}
}
private ChasingAABBOutline getAndRefreshAABB(Object slot) {
OutlineEntry entry = outlines.get(slot);
entry.ticksTillRemoval = 1;
return (ChasingAABBOutline) entry.getOutline();
}
// Maintenance
public Outliner() {
outlines = new HashMap<>();
}
public void tickOutlines() {
Set<Object> toClear = new HashSet<>();
outlines.forEach((key, entry) -> {
entry.ticksTillRemoval--;
entry.getOutline()
.tick();
if (entry.isAlive())
return;
toClear.add(key);
});
toClear.forEach(outlines::remove);
}
public void renderOutlines(MatrixStack ms, IRenderTypeBuffer buffer) {
outlines.forEach((key, entry) -> {
Outline outline = entry.getOutline();
outline.params.alpha = 1;
if (entry.type != ExpireType.IMMEDIATE && entry.ticksTillRemoval < 0) {
int prevTicks = entry.ticksTillRemoval + 1;
float lastAlpha = prevTicks >= 0 ? 1 : 1 + (prevTicks / (float) entry.type.fadeTicks);
float currentAlpha = 1 + (entry.ticksTillRemoval / (float) entry.type.fadeTicks);
float alpha = MathHelper.lerp(Minecraft.getInstance()
.getRenderPartialTicks(), lastAlpha, currentAlpha);
outline.params.alpha = alpha * alpha * alpha;
if (outline.params.alpha < 1 / 8f)
return;
}
outline.render(ms, buffer);
});
}
public enum ExpireType {
IMMEDIATE(0), FADE(8), FADE_EXPAND(10);
private int fadeTicks;
private ExpireType(int fadeTicks) {
this.fadeTicks = fadeTicks;
}
}
private class OutlineEntry {
private Outline outline;
private int ticksTillRemoval;
private ExpireType type;
public OutlineEntry(Outline outline, ExpireType type) {
this.outline = outline;
this.type = type;
ticksTillRemoval = 1;
}
public boolean isAlive() {
return ticksTillRemoval >= -type.fadeTicks;
}
public Outline getOutline() {
return outline;
}
}
}

View file

@ -9,19 +9,14 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.platform.GlStateManager.DestFactor;
import com.mojang.blaze3d.platform.GlStateManager.SourceFactor;
import com.mojang.blaze3d.systems.RenderSystem;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllKeys; import com.simibubi.create.AllKeys;
import com.simibubi.create.foundation.utility.outliner.BlockClusterOutline; import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.foundation.utility.outliner.Outline; import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.utility.outliner.OutlineParticle; import com.simibubi.create.foundation.utility.outliner.Outliner.ExpireType;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity; import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -35,16 +30,20 @@ public class ChassisRangeDisplay {
private static GroupEntry lastHoveredGroup = null; private static GroupEntry lastHoveredGroup = null;
private static class Entry { private static class Entry {
BlockClusterOutline outline;
OutlineParticle<Outline> particle;
ChassisTileEntity te; ChassisTileEntity te;
int timer; int timer;
public Entry(ChassisTileEntity te) { public Entry(ChassisTileEntity te) {
this.te = te; this.te = te;
outline = new BlockClusterOutline(createSelection(te));
particle = OutlineParticle.create(outline);
timer = DISPLAY_TIME; timer = DISPLAY_TIME;
CreateClient.outliner.showCluster(getOutlineKey(), createSelection(te), ExpireType.FADE)
.colored(0xFFFFBB)
.lineWidth(1 / 16f)
.withFaceTexture(AllSpecialTextures.CHECKERED);
}
protected Object getOutlineKey() {
return te.getPos();
} }
protected Set<BlockPos> createSelection(ChassisTileEntity chassis) { protected Set<BlockPos> createSelection(ChassisTileEntity chassis) {
@ -66,6 +65,11 @@ public class ChassisRangeDisplay {
super(te); super(te);
} }
@Override
protected Object getOutlineKey() {
return this;
}
@Override @Override
protected Set<BlockPos> createSelection(ChassisTileEntity chassis) { protected Set<BlockPos> createSelection(ChassisTileEntity chassis) {
Set<BlockPos> list = new HashSet<>(); Set<BlockPos> list = new HashSet<>();
@ -87,22 +91,23 @@ public class ChassisRangeDisplay {
World world = Minecraft.getInstance().world; World world = Minecraft.getInstance().world;
boolean hasWrench = AllItems.WRENCH.typeOf(player.getHeldItemMainhand()); boolean hasWrench = AllItems.WRENCH.typeOf(player.getHeldItemMainhand());
for (Iterator<BlockPos> iterator = entries.keySet().iterator(); iterator.hasNext();) { for (Iterator<BlockPos> iterator = entries.keySet()
Entry entry = entries.get(iterator.next()); .iterator(); iterator.hasNext();) {
if (tickEntry(entry, hasWrench)) { BlockPos pos = iterator.next();
entry.particle.remove(); Entry entry = entries.get(pos);
if (tickEntry(entry, hasWrench))
iterator.remove(); iterator.remove();
} CreateClient.outliner.keepCluster(entry.getOutlineKey());
} }
for (Iterator<GroupEntry> iterator = groupEntries.iterator(); iterator.hasNext();) { for (Iterator<GroupEntry> iterator = groupEntries.iterator(); iterator.hasNext();) {
GroupEntry group = iterator.next(); GroupEntry group = iterator.next();
if (tickEntry(group, hasWrench)) { if (tickEntry(group, hasWrench)) {
iterator.remove(); iterator.remove();
group.particle.remove();
if (group == lastHoveredGroup) if (group == lastHoveredGroup)
lastHoveredGroup = null; lastHoveredGroup = null;
} }
CreateClient.outliner.keepCluster(group.getOutlineKey());
} }
if (!hasWrench) if (!hasWrench)
@ -125,11 +130,8 @@ public class ChassisRangeDisplay {
if (ctrl) { if (ctrl) {
GroupEntry existingGroupForPos = getExistingGroupForPos(pos); GroupEntry existingGroupForPos = getExistingGroupForPos(pos);
if (existingGroupForPos != null) { if (existingGroupForPos != null) {
for (ChassisTileEntity included : existingGroupForPos.includedTEs) { for (ChassisTileEntity included : existingGroupForPos.includedTEs)
Entry removed = entries.remove(included.getPos()); entries.remove(included.getPos());
if (removed != null)
removed.particle.remove();
}
existingGroupForPos.timer = DISPLAY_TIME; existingGroupForPos.timer = DISPLAY_TIME;
return; return;
} }
@ -138,28 +140,18 @@ public class ChassisRangeDisplay {
if (!entries.containsKey(pos) || ctrl) if (!entries.containsKey(pos) || ctrl)
display(chassisTileEntity); display(chassisTileEntity);
else { else {
deselect();
if (!ctrl) if (!ctrl)
entries.get(pos).timer = DISPLAY_TIME; entries.get(pos).timer = DISPLAY_TIME;
} }
} }
private static void deselect() {
for (Entry entry : entries.values())
if (entry.timer > 10)
entry.timer = 10;
for (Entry entry : groupEntries)
if (entry.timer > 10)
entry.timer = 10;
}
private static boolean tickEntry(Entry entry, boolean hasWrench) { private static boolean tickEntry(Entry entry, boolean hasWrench) {
ChassisTileEntity chassisTileEntity = entry.te; ChassisTileEntity chassisTileEntity = entry.te;
World teWorld = chassisTileEntity.getWorld(); World teWorld = chassisTileEntity.getWorld();
World world = Minecraft.getInstance().world; World world = Minecraft.getInstance().world;
if (chassisTileEntity.isRemoved() || teWorld == null || teWorld != world if (chassisTileEntity.isRemoved() || teWorld == null || teWorld != world
|| !world.isBlockPresent(chassisTileEntity.getPos())) { || !world.isBlockPresent(chassisTileEntity.getPos())) {
return true; return true;
} }
@ -175,63 +167,31 @@ public class ChassisRangeDisplay {
} }
public static void display(ChassisTileEntity chassis) { public static void display(ChassisTileEntity chassis) {
deselect();
if (AllKeys.ctrlDown()) {
groupEntries.forEach(e -> e.particle.remove());
groupEntries.clear();
GroupEntry hoveredGroup = new GroupEntry(chassis);
for (ChassisTileEntity included : hoveredGroup.includedTEs) {
Entry remove = entries.remove(included.getPos());
if (remove != null)
remove.particle.remove();
}
groupEntries.add(hoveredGroup);
} else {
Entry old = entries.put(chassis.getPos(), new Entry(chassis));
if (old != null)
old.particle.remove();
}
}
public static void renderOutlines(float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer) { // Display a group and kill any selections of its contained chassis blocks
// TODO 1.15 buffered render if (AllKeys.ctrlDown()) {
if (entries.isEmpty() && groupEntries.isEmpty()) { GroupEntry hoveredGroup = new GroupEntry(chassis);
for (ChassisTileEntity included : hoveredGroup.includedTEs)
CreateClient.outliner.remove(included.getPos());
groupEntries.forEach(entry -> CreateClient.outliner.remove(entry.getOutlineKey()));
groupEntries.clear();
entries.clear();
groupEntries.add(hoveredGroup);
return; return;
} }
RenderSystem.lineWidth(2);
//TessellatorHelper.prepareForDrawing();
RenderSystem.disableTexture();
RenderSystem.enableAlphaTest();
for (Entry entry : entries.values()) // Display an individual chassis and kill any group selections that contained it
renderPositions(entry, partialTicks); BlockPos pos = chassis.getPos();
for (Entry groupEntry : groupEntries) GroupEntry entry = getExistingGroupForPos(pos);
renderPositions(groupEntry, partialTicks); if (entry != null)
CreateClient.outliner.remove(entry.getOutlineKey());
RenderSystem.enableTexture(); groupEntries.clear();
RenderSystem.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); entries.clear();
//TessellatorHelper.cleanUpAfterDrawing(); entries.put(pos, new Entry(chassis));
RenderSystem.lineWidth(1);
}
public static void renderPositions(Entry entry, float partialTicks) {
// GlStateManager.pushMatrix();
// RenderHelper.disableStandardItemLighting();
// GlStateManager.normal3f(0.0F, 1.0F, 0.0F);
// GlStateManager.color4f(1, 1, 1, 1);
// GlStateManager.enableTexture();
// GlStateManager.depthMask(false);
// GlStateManager.enableBlend();
// GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
//
float timer = entry.timer - partialTicks;
float alpha = timer > 20 ? 1 : timer / 20f;
entry.outline.setAlpha(alpha);
// entry.outline.render(Tessellator.getInstance().getBuffer());
//
// GlStateManager.disableBlend();
// GlStateManager.depthMask(true);
// GlStateManager.popMatrix();
} }
private static GroupEntry getExistingGroupForPos(BlockPos pos) { private static GroupEntry getExistingGroupForPos(BlockPos pos) {

View file

@ -10,16 +10,11 @@ import org.apache.commons.io.IOUtils;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllKeys; import com.simibubi.create.AllKeys;
import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.foundation.gui.ScreenOpener; import com.simibubi.create.foundation.gui.ScreenOpener;
import com.simibubi.create.foundation.gui.TextInputPromptScreen; import com.simibubi.create.foundation.gui.TextInputPromptScreen;
import com.simibubi.create.foundation.utility.FilesHelper; import com.simibubi.create.foundation.utility.FilesHelper;
import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.RaycastHelper; import com.simibubi.create.foundation.utility.RaycastHelper;
import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.foundation.utility.outliner.ChasingAABBOutline;
import com.simibubi.create.foundation.utility.outliner.OutlineParticle;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -49,7 +44,7 @@ public class SchematicAndQuillHandler {
private Direction selectedFace; private Direction selectedFace;
private int range = 10; private int range = 10;
private OutlineParticle<ChasingAABBOutline> particle; // private OutlineParticle<ChasingAABBOutline> particle;
public boolean mouseScrolled(double delta) { public boolean mouseScrolled(double delta) {
if (!isActive()) if (!isActive())
@ -129,10 +124,10 @@ public class SchematicAndQuillHandler {
public void tick() { public void tick() {
if (!isActive()) { if (!isActive()) {
if (particle != null) { // if (particle != null) {
particle.setExpired(); // particle.setExpired();
particle = null; // particle = null;
} // }
return; return;
} }
@ -157,49 +152,49 @@ public class SchematicAndQuillHandler {
setCursor(null); setCursor(null);
} }
if (particle == null) // if (particle == null)
return; // return;
//
// ChasingAABBOutline outline = particle.getOutline();
// if (particle.isAlive())
// outline.tick();
ChasingAABBOutline outline = particle.getOutline(); // if (secondPos == null) {
if (particle.isAlive()) // selectedFace = null;
outline.tick(); // outline.highlightFace(null);
// return;
if (secondPos == null) { // }
selectedFace = null; //
outline.highlightFace(null); // AxisAlignedBB bb = new AxisAlignedBB(firstPos, secondPos).expand(1, 1, 1).grow(.45f);
return; // Vec3d projectedView = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView();
} // boolean inside = bb.contains(projectedView);
//
AxisAlignedBB bb = new AxisAlignedBB(firstPos, secondPos).expand(1, 1, 1).grow(.45f); // PredicateTraceResult result =
Vec3d projectedView = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView(); // RaycastHelper.rayTraceUntil(player, 70, pos -> inside ^ bb.contains(VecHelper.getCenterOf(pos)));
boolean inside = bb.contains(projectedView); // selectedFace = result.missed() ? null : inside ? result.getFacing().getOpposite() : result.getFacing();
// outline.highlightFace(AllKeys.ACTIVATE_TOOL.isPressed() ? selectedFace : null);
PredicateTraceResult result =
RaycastHelper.rayTraceUntil(player, 70, pos -> inside ^ bb.contains(VecHelper.getCenterOf(pos)));
selectedFace = result.missed() ? null : inside ? result.getFacing().getOpposite() : result.getFacing();
outline.highlightFace(AllKeys.ACTIVATE_TOOL.isPressed() ? selectedFace : null);
} }
private void setCursor(BlockPos pos) { private void setCursor(BlockPos pos) {
selectedPos = pos; selectedPos = pos;
AxisAlignedBB bb = getCurrentSelectionBox(); AxisAlignedBB bb = getCurrentSelectionBox();
if (particle != null && !particle.isAlive()) // if (particle != null && !particle.isAlive())
particle = null; // particle = null;
if (bb == null) { // if (bb == null) {
if (particle != null) // if (particle != null)
particle.setExpired(); // particle.setExpired();
return; // return;
} // }
//
if (particle == null) { // if (particle == null) {
ChasingAABBOutline outline = new ChasingAABBOutline(bb); // ChasingAABBOutline outline = new ChasingAABBOutline(bb);
outline.setTextures(AllSpecialTextures.CHECKERED, AllSpecialTextures.HIGHLIGHT_CHECKERED); // outline.setTextures(AllSpecialTextures.CHECKERED, AllSpecialTextures.HIGHLIGHT_CHECKERED);
particle = OutlineParticle.create(outline); // particle = OutlineParticle.create(outline);
} // }
//
ChasingAABBOutline outline = particle.getOutline(); // ChasingAABBOutline outline = particle.getOutline();
outline.target(bb); // outline.target(bb);
} }
private AxisAlignedBB getCurrentSelectionBox() { private AxisAlignedBB getCurrentSelectionBox() {

View file

@ -65,9 +65,9 @@ public class DeployTool extends PlacementToolBase {
RenderSystem.translated(-rotationOffset.x, 0, -rotationOffset.z); RenderSystem.translated(-rotationOffset.x, 0, -rotationOffset.z);
RenderSystem.translated(-xOrigin, 0, -zOrigin); RenderSystem.translated(-xOrigin, 0, -zOrigin);
schematicHandler.getOutline().setTextures(AllSpecialTextures.CHECKERED, null); // schematicHandler.getOutline().setTextures(AllSpecialTextures.CHECKERED, null);
schematicHandler.getOutline().render(Tessellator.getInstance().getBuffer()); // schematicHandler.getOutline().render(Tessellator.getInstance().getBuffer());TODO
schematicHandler.getOutline().setTextures(null, null); // schematicHandler.getOutline().setTextures(null, null);
RenderSystem.popMatrix(); RenderSystem.popMatrix();
} }

View file

@ -129,7 +129,7 @@ public abstract class SchematicToolBase implements ISchematicTool {
RenderHelper.disableStandardItemLighting(); RenderHelper.disableStandardItemLighting();
RenderSystem.pushMatrix(); RenderSystem.pushMatrix();
RenderSystem.enableBlend(); RenderSystem.enableBlend();
outline.render(Tessellator.getInstance().getBuffer()); // outline.render(Tessellator.getInstance().getBuffer());TODO
RenderSystem.popMatrix(); RenderSystem.popMatrix();
outline.setTextures(null, null); outline.setTextures(null, null);