Facade Recipe integration and cleanups
This commit is contained in:
@@ -19,9 +19,11 @@
|
||||
package appeng.core;
|
||||
|
||||
import appeng.items.parts.FacadeItem;
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
@@ -34,8 +36,11 @@ public final class FacadeCreativeTab {
|
||||
|
||||
private static List<ItemStack> subTypes = null;
|
||||
|
||||
private static ItemGroup group;
|
||||
|
||||
public static void init() {
|
||||
FabricItemGroupBuilder.create(AppEng.makeId("facades"))
|
||||
Preconditions.checkState(group == null);
|
||||
group = FabricItemGroupBuilder.create(AppEng.makeId("facades"))
|
||||
.icon(() -> {
|
||||
calculateSubTypes();
|
||||
if (subTypes.isEmpty()) {
|
||||
@@ -47,6 +52,13 @@ public final class FacadeCreativeTab {
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ItemGroup getGroup() {
|
||||
if (group == null) {
|
||||
init();
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
private static void fill(List<ItemStack> items) {
|
||||
calculateSubTypes();
|
||||
items.addAll(subTypes);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package appeng.integration.modules.jei;
|
||||
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.FacadeCreativeTab;
|
||||
import me.shedaniel.rei.api.EntryStack;
|
||||
import me.shedaniel.rei.plugin.crafting.DefaultCraftingCategory;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
/**
|
||||
* A simple copy of the crafting category to separate out the facade recipes.
|
||||
*/
|
||||
public class FacadeRecipeCategory extends DefaultCraftingCategory {
|
||||
|
||||
public static final Identifier ID = AppEng.makeId("facades");
|
||||
|
||||
@Override
|
||||
public Identifier getIdentifier() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntryStack getLogo() {
|
||||
return EntryStack.create(FacadeCreativeTab.getGroup().getIcon());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategoryName() {
|
||||
return I18n.translate(FacadeCreativeTab.getGroup().getTranslationKey());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.integration.modules.jei;
|
||||
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.FacadeCreativeTab;
|
||||
import appeng.items.parts.FacadeItem;
|
||||
import me.shedaniel.rei.api.ClientHelper;
|
||||
import me.shedaniel.rei.api.EntryStack;
|
||||
import me.shedaniel.rei.api.LiveRecipeGenerator;
|
||||
import me.shedaniel.rei.plugin.crafting.DefaultShapedDisplay;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.recipe.ShapedRecipe;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* This plugin will dynamically add facade recipes for any item that can be
|
||||
* turned into a facade.
|
||||
*/
|
||||
class FacadeRegistryGenerator implements LiveRecipeGenerator<DefaultShapedDisplay> {
|
||||
|
||||
private final FacadeItem itemFacade;
|
||||
|
||||
private final ItemStack cableAnchor;
|
||||
|
||||
FacadeRegistryGenerator(FacadeItem itemFacade, ItemStack cableAnchor) {
|
||||
this.itemFacade = itemFacade;
|
||||
this.cableAnchor = cableAnchor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getCategoryIdentifier() {
|
||||
return FacadeRecipeCategory.ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<List<DefaultShapedDisplay>> getRecipeFor(EntryStack entry) {
|
||||
// Looking up how a certain facade is crafted
|
||||
ItemStack itemStack = entry.getItemStack();
|
||||
if (itemStack.getItem() instanceof FacadeItem) {
|
||||
FacadeItem facadeItem = (FacadeItem) itemStack.getItem();
|
||||
ItemStack textureItem = facadeItem.getTextureItem(itemStack);
|
||||
return Optional.of(Collections.singletonList(make(textureItem, this.cableAnchor, itemStack)));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<List<DefaultShapedDisplay>> getUsageFor(EntryStack entry) {
|
||||
// Looking up if a certain block can be used to make a facade
|
||||
ItemStack itemStack = entry.getItemStack();
|
||||
ItemStack facade = this.itemFacade.createFacadeForItem(itemStack, false);
|
||||
|
||||
if (!facade.isEmpty()) {
|
||||
return Optional.of(Collections.singletonList(make(itemStack, this.cableAnchor, facade)));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<List<DefaultShapedDisplay>> getDisplaysGenerated(ClientHelper.ViewSearchBuilder builder) {
|
||||
// FABRIC FIXME Return a list of all facade recipes here
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private DefaultShapedDisplay make(ItemStack textureItem, ItemStack cableAnchor, ItemStack result) {
|
||||
// This id should only be used within JEI and not really matter
|
||||
Identifier id = AppEng.makeId("facade/" + Item.getRawId(textureItem.getItem()));
|
||||
|
||||
DefaultedList<Ingredient> ingredients = DefaultedList.ofSize(9, Ingredient.EMPTY);
|
||||
ingredients.set(1, Ingredient.ofStacks(cableAnchor));
|
||||
ingredients.set(3, Ingredient.ofStacks(cableAnchor));
|
||||
ingredients.set(5, Ingredient.ofStacks(cableAnchor));
|
||||
ingredients.set(7, Ingredient.ofStacks(cableAnchor));
|
||||
ingredients.set(4, Ingredient.ofStacks(textureItem));
|
||||
|
||||
return new DefaultShapedDisplay(new ShapedRecipe(id, "", 3, 3, ingredients, result));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,16 +30,14 @@ import appeng.core.AEConfig;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.localization.GuiText;
|
||||
import appeng.integration.abstraction.ReiFacade;
|
||||
import appeng.items.parts.FacadeItem;
|
||||
import appeng.recipes.handlers.GrinderRecipe;
|
||||
import appeng.recipes.handlers.InscriberRecipe;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import me.shedaniel.rei.api.EntryStack;
|
||||
import me.shedaniel.rei.api.RecipeHelper;
|
||||
import me.shedaniel.rei.api.plugins.REIPluginV0;
|
||||
import me.shedaniel.rei.plugin.information.DefaultInformationDisplay;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.RecipeManager;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
@@ -66,6 +64,7 @@ public class ReiPlugin implements REIPluginV0 {
|
||||
recipeHelper.registerCategory(new GrinderRecipeCategory());
|
||||
recipeHelper.registerCategory(new CondenserCategory());
|
||||
recipeHelper.registerCategory(new InscriberRecipeCategory());
|
||||
recipeHelper.registerCategory(new FacadeRecipeCategory());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,6 +87,12 @@ public class ReiPlugin implements REIPluginV0 {
|
||||
recipeHelper.removeAutoCraftButton(CondenserCategory.UID);
|
||||
|
||||
registerWorkingStations(recipeHelper);
|
||||
|
||||
IDefinitions definitions = Api.instance().definitions();
|
||||
recipeHelper.registerLiveRecipeGenerator(new FacadeRegistryGenerator(
|
||||
(FacadeItem) definitions.items().facade().item(),
|
||||
definitions.parts().cableAnchor().stack(1)
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.core.crash;
|
||||
|
||||
import net.minecraftforge.fml.common.ICrashCallable;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
|
||||
import appeng.core.AEConfig;
|
||||
|
||||
public class ModCrashEnhancement implements ICrashCallable {
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return "AE2 Version";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
return AEConfig.CHANNEL + ' ' + AEConfig.VERSION + " for Forge " + ForgeVersion.getVersion();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.integration.modules.jei;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.recipe.ShapedRecipe;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
|
||||
import mezz.jei.api.constants.VanillaRecipeCategoryUid;
|
||||
import mezz.jei.api.recipe.IFocus;
|
||||
import mezz.jei.api.recipe.advanced.IRecipeManagerPlugin;
|
||||
import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||
|
||||
import appeng.core.AppEng;
|
||||
import appeng.items.parts.FacadeItem;
|
||||
|
||||
/**
|
||||
* This plugin will dynamically add facade recipes for any item that can be
|
||||
* turned into a facade.
|
||||
*/
|
||||
class FacadeRegistryPlugin implements IRecipeManagerPlugin {
|
||||
|
||||
private final FacadeItem itemFacade;
|
||||
|
||||
private final ItemStack cableAnchor;
|
||||
|
||||
FacadeRegistryPlugin(FacadeItem itemFacade, ItemStack cableAnchor) {
|
||||
this.itemFacade = itemFacade;
|
||||
this.cableAnchor = cableAnchor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> List<Identifier> getRecipeCategoryUids(IFocus<V> focus) {
|
||||
if (focus.getMode() == IFocus.Mode.OUTPUT && focus.getValue() instanceof ItemStack) {
|
||||
// Looking up how a certain facade is crafted
|
||||
ItemStack itemStack = (ItemStack) focus.getValue();
|
||||
if (itemStack.getItem() instanceof FacadeItem) {
|
||||
return Collections.singletonList(VanillaRecipeCategoryUid.CRAFTING);
|
||||
}
|
||||
} else if (focus.getMode() == IFocus.Mode.INPUT && focus.getValue() instanceof ItemStack) {
|
||||
// Looking up if a certain block can be used to make a facade
|
||||
ItemStack itemStack = (ItemStack) focus.getValue();
|
||||
|
||||
if (!this.itemFacade.createFacadeForItem(itemStack, true).isEmpty()) {
|
||||
return Collections.singletonList(VanillaRecipeCategoryUid.CRAFTING);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T, V> List<T> getRecipes(IRecipeCategory<T> recipeCategory, IFocus<V> focus) {
|
||||
if (!VanillaRecipeCategoryUid.CRAFTING.equals(recipeCategory.getUid())) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (focus.getMode() == IFocus.Mode.OUTPUT && focus.getValue() instanceof ItemStack) {
|
||||
// Looking up how a certain facade is crafted
|
||||
ItemStack itemStack = (ItemStack) focus.getValue();
|
||||
if (itemStack.getItem() instanceof FacadeItem) {
|
||||
FacadeItem facadeItem = (FacadeItem) itemStack.getItem();
|
||||
ItemStack textureItem = facadeItem.getTextureItem(itemStack);
|
||||
return Collections.singletonList((T) make(textureItem, this.cableAnchor, itemStack));
|
||||
}
|
||||
} else if (focus.getMode() == IFocus.Mode.INPUT && focus.getValue() instanceof ItemStack) {
|
||||
// Looking up if a certain block can be used to make a facade
|
||||
|
||||
ItemStack itemStack = (ItemStack) focus.getValue();
|
||||
ItemStack facade = this.itemFacade.createFacadeForItem(itemStack, false);
|
||||
|
||||
if (!facade.isEmpty()) {
|
||||
return Collections.singletonList((T) make(itemStack, this.cableAnchor, facade));
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private ShapedRecipe make(ItemStack textureItem, ItemStack cableAnchor, ItemStack result) {
|
||||
// This id should only be used within JEI and not really matter
|
||||
Identifier id = new Identifier(AppEng.MOD_ID,
|
||||
"facade/" + textureItem.getItem().getRegistryName().toString().replace(':', '/'));
|
||||
|
||||
DefaultedList<Ingredient> ingredients = DefaultedList.withSize(9, Ingredient.EMPTY);
|
||||
ingredients.set(1, Ingredient.ofStacks(cableAnchor));
|
||||
ingredients.set(3, Ingredient.ofStacks(cableAnchor));
|
||||
ingredients.set(5, Ingredient.ofStacks(cableAnchor));
|
||||
ingredients.set(7, Ingredient.ofStacks(cableAnchor));
|
||||
ingredients.set(4, Ingredient.ofStacks(textureItem));
|
||||
|
||||
return new ShapedRecipe(id, "", 3, 3, ingredients, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getRecipes(IRecipeCategory<T> recipeCategory) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* This file is part of CodeChickenLib.
|
||||
* Copyright (c) 2018, covers1624, All rights reserved.
|
||||
*
|
||||
* CodeChickenLib is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CodeChickenLib is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.thirdparty.codechicken.lib.model;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.minecraft.client.render.VertexFormat;
|
||||
import net.minecraft.client.render.VertexFormatElement;
|
||||
|
||||
/**
|
||||
* A simple VertexFormat cache. This caches the existence of attributes and
|
||||
* their indexes.
|
||||
*
|
||||
* @author covers1624
|
||||
*/
|
||||
public class CachedFormat {
|
||||
|
||||
public static final Map<VertexFormat, CachedFormat> formatCache = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Lookup or create the CachedFormat for a given VertexFormat.
|
||||
*
|
||||
* @param format The format to lookup.
|
||||
*
|
||||
* @return The CachedFormat.
|
||||
*/
|
||||
public static CachedFormat lookup(VertexFormat format) {
|
||||
return formatCache.computeIfAbsent(format, CachedFormat::new);
|
||||
}
|
||||
|
||||
public VertexFormat format;
|
||||
|
||||
public boolean hasPosition;
|
||||
public boolean hasNormal;
|
||||
public boolean hasColor;
|
||||
public boolean hasUV;
|
||||
public boolean hasOverlay;
|
||||
public boolean hasLightMap;
|
||||
|
||||
public int positionIndex = -1;
|
||||
public int normalIndex = -1;
|
||||
public int colorIndex = -1;
|
||||
public int uvIndex = -1;
|
||||
public int overlayIndex = -1;
|
||||
public int lightMapIndex = -1;
|
||||
|
||||
public int elementCount;
|
||||
|
||||
/**
|
||||
* Caches the vertex format element indexes for efficiency.
|
||||
*
|
||||
* @param format The format.
|
||||
*/
|
||||
public CachedFormat(VertexFormat format) {
|
||||
this.format = format;
|
||||
this.elementCount = format.getElements().size();
|
||||
for (int i = 0; i < this.elementCount; i++) {
|
||||
VertexFormatElement element = format.getElements().get(i);
|
||||
switch (element.getType()) {
|
||||
case POSITION:
|
||||
if (this.hasPosition) {
|
||||
throw new IllegalStateException("Found 2 position elements..");
|
||||
}
|
||||
this.hasPosition = true;
|
||||
this.positionIndex = i;
|
||||
break;
|
||||
case NORMAL:
|
||||
if (this.hasNormal) {
|
||||
throw new IllegalStateException("Found 2 normal elements..");
|
||||
}
|
||||
this.hasNormal = true;
|
||||
this.normalIndex = i;
|
||||
break;
|
||||
case COLOR:
|
||||
if (this.hasColor) {
|
||||
throw new IllegalStateException("Found 2 color elements..");
|
||||
}
|
||||
this.hasColor = true;
|
||||
this.colorIndex = i;
|
||||
break;
|
||||
case UV:
|
||||
switch (element.getIndex()) {
|
||||
case 0:
|
||||
if (hasUV) {
|
||||
throw new IllegalStateException("Found 2 UV elements..");
|
||||
}
|
||||
hasUV = true;
|
||||
uvIndex = i;
|
||||
break;
|
||||
case 1:
|
||||
if (hasOverlay) {
|
||||
throw new IllegalStateException("Found 2 Overlay elements..");
|
||||
}
|
||||
hasOverlay = true;
|
||||
overlayIndex = i;
|
||||
break;
|
||||
case 2:
|
||||
if (hasLightMap) {
|
||||
throw new IllegalStateException("Found 2 LightMap elements..");
|
||||
}
|
||||
hasLightMap = true;
|
||||
lightMapIndex = i;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof CachedFormat)) {
|
||||
return false;
|
||||
}
|
||||
CachedFormat other = (CachedFormat) obj;
|
||||
return other.elementCount == this.elementCount && //
|
||||
other.positionIndex == this.positionIndex && //
|
||||
other.normalIndex == this.normalIndex && //
|
||||
other.colorIndex == this.colorIndex && //
|
||||
other.uvIndex == this.uvIndex && //
|
||||
other.lightMapIndex == this.lightMapIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 1;
|
||||
result = 31 * result + this.elementCount;
|
||||
result = 31 * result + this.positionIndex;
|
||||
result = 31 * result + this.normalIndex;
|
||||
result = 31 * result + this.colorIndex;
|
||||
result = 31 * result + this.uvIndex;
|
||||
result = 31 * result + this.lightMapIndex;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* This file is part of CodeChickenLib.
|
||||
* Copyright (c) 2018, covers1624, All rights reserved.
|
||||
*
|
||||
* CodeChickenLib is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CodeChickenLib is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.thirdparty.codechicken.lib.model;
|
||||
|
||||
import appeng.thirdparty.codechicken.lib.model.pipeline.VertexConsumer;
|
||||
|
||||
/**
|
||||
* Marks a standard IVertexConsumer as compatible with {@link Quad}.
|
||||
*
|
||||
* @author covers1624
|
||||
*/
|
||||
public interface ISmartVertexConsumer extends VertexConsumer {
|
||||
|
||||
/**
|
||||
* Assumes the data is already completely unpacked. You must always copy the
|
||||
* data from the quad provided to an internal cache. basically:
|
||||
* this.quad.put(quad);
|
||||
*
|
||||
* @param quad The quad to copy data from.
|
||||
*/
|
||||
void put(Quad quad);
|
||||
}
|
||||
@@ -1,494 +0,0 @@
|
||||
/*
|
||||
* This file is part of CodeChickenLib.
|
||||
* Copyright (c) 2018, covers1624, All rights reserved.
|
||||
*
|
||||
* CodeChickenLib is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CodeChickenLib is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.thirdparty.codechicken.lib.model;
|
||||
|
||||
import appeng.thirdparty.codechicken.lib.model.pipeline.VertexConsumer;
|
||||
import appeng.thirdparty.codechicken.lib.model.pipeline.VertexProducer;
|
||||
import net.minecraft.client.render.VertexFormats;
|
||||
import net.minecraft.client.util.math.Vector3f;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.render.VertexFormat;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
import appeng.thirdparty.codechicken.lib.math.InterpHelper;
|
||||
|
||||
/**
|
||||
* A simple easy to manipulate quad format. Can be reset and then used on a
|
||||
* different format.
|
||||
*
|
||||
* @author covers1624
|
||||
*/
|
||||
public class Quad implements VertexProducer, ISmartVertexConsumer {
|
||||
|
||||
public CachedFormat format;
|
||||
|
||||
public int tintIndex = -1;
|
||||
public Direction orientation;
|
||||
public boolean diffuseLighting = true;
|
||||
public Sprite sprite;
|
||||
|
||||
public Vertex[] vertices = new Vertex[4];
|
||||
public boolean full;
|
||||
|
||||
// Not copied.
|
||||
private int vertexIndex = 0;
|
||||
// Cache for normal computation.
|
||||
private Vector3f v1 = new Vector3f();
|
||||
private Vector3f v2 = new Vector3f();
|
||||
private Vector3f t = new Vector3f();
|
||||
private Vector3f normal = new Vector3f();
|
||||
|
||||
/**
|
||||
* Use this if you reset the quad each time you use it.
|
||||
*/
|
||||
public Quad() {
|
||||
}
|
||||
|
||||
/**
|
||||
* use this if you want to initialize the quad with a format.
|
||||
*
|
||||
* @param format The format.
|
||||
*/
|
||||
public Quad(CachedFormat format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexFormat getVertexFormat() {
|
||||
return this.format.format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQuadTint(int tint) {
|
||||
this.tintIndex = tint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQuadOrientation(Direction orientation) {
|
||||
this.orientation = orientation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplyDiffuseLighting(boolean diffuse) {
|
||||
this.diffuseLighting = diffuse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTexture(Sprite texture) {
|
||||
this.sprite = texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(int element, float... data) {
|
||||
if (this.full) {
|
||||
throw new RuntimeException("Unable to add data when full.");
|
||||
}
|
||||
Vertex v = this.vertices[this.vertexIndex];
|
||||
if (v == null) {
|
||||
v = new Vertex(this.format);
|
||||
this.vertices[this.vertexIndex] = v;
|
||||
}
|
||||
System.arraycopy(data, 0, v.raw[element], 0, data.length);
|
||||
if (element == (this.format.elementCount - 1)) {
|
||||
this.vertexIndex++;
|
||||
if (this.vertexIndex == 4) {
|
||||
this.vertexIndex = 0;
|
||||
this.full = true;
|
||||
if (this.orientation == null) {
|
||||
this.calculateOrientation(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Quad quad) {
|
||||
this.copyFrom(quad);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pipe(VertexConsumer consumer) {
|
||||
if (consumer instanceof ISmartVertexConsumer) {
|
||||
((ISmartVertexConsumer) consumer).put(this);
|
||||
} else {
|
||||
consumer.setQuadTint(this.tintIndex);
|
||||
consumer.setQuadOrientation(this.orientation);
|
||||
consumer.setApplyDiffuseLighting(this.diffuseLighting);
|
||||
consumer.setTexture(this.sprite);
|
||||
for (Vertex v : this.vertices) {
|
||||
for (int e = 0; e < this.format.elementCount; e++) {
|
||||
consumer.put(e, v.raw[e]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to reset the interpolation values inside the provided helper.
|
||||
*
|
||||
* @param helper The helper.
|
||||
* @param s The axis. side >> 1;
|
||||
*
|
||||
* @return The same helper.
|
||||
*/
|
||||
public InterpHelper resetInterp(InterpHelper helper, int s) {
|
||||
helper.reset( //
|
||||
this.vertices[0].dx(s), this.vertices[0].dy(s), //
|
||||
this.vertices[1].dx(s), this.vertices[1].dy(s), //
|
||||
this.vertices[2].dx(s), this.vertices[2].dy(s), //
|
||||
this.vertices[3].dx(s), this.vertices[3].dy(s));
|
||||
return helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the Quad inside the box.
|
||||
*
|
||||
* @param bb The box.
|
||||
*/
|
||||
public void clamp(Box bb) {
|
||||
for (Vertex vertex : this.vertices) {
|
||||
float[] vec = vertex.vec;
|
||||
vec[0] = (float) MathHelper.clamp(vec[0], bb.minX, bb.maxX);
|
||||
vec[1] = (float) MathHelper.clamp(vec[1], bb.minY, bb.maxY);
|
||||
vec[2] = (float) MathHelper.clamp(vec[2], bb.minZ, bb.maxZ);
|
||||
}
|
||||
this.calculateOrientation(true);
|
||||
}
|
||||
|
||||
private static void setVector(Vector3f to, float[] from) {
|
||||
to.set(from[0], from[1], from[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-calculates the Orientation of this quad, optionally the normal vector.
|
||||
*
|
||||
* @param setNormal If the normal vector should be updated.
|
||||
*/
|
||||
public void calculateOrientation(boolean setNormal) {
|
||||
setVector(this.v1, this.vertices[3].vec);
|
||||
setVector(this.t, this.vertices[1].vec);
|
||||
this.v1.subtract(this.t);
|
||||
|
||||
setVector(this.v2, this.vertices[2].vec);
|
||||
setVector(this.t, this.vertices[0].vec);
|
||||
this.v2.subtract(this.t);
|
||||
|
||||
this.normal.set(this.v2.getX(), this.v2.getY(), this.v2.getZ());
|
||||
this.normal.cross(this.v1);
|
||||
this.normal.normalize();
|
||||
|
||||
if (this.format.hasNormal && setNormal) {
|
||||
for (Vertex vertex : this.vertices) {
|
||||
vertex.normal[0] = this.normal.getX();
|
||||
vertex.normal[1] = this.normal.getY();
|
||||
vertex.normal[2] = this.normal.getZ();
|
||||
vertex.normal[3] = 0;
|
||||
}
|
||||
}
|
||||
this.orientation = Direction.getFacing(this.normal.getX(), this.normal.getY(), this.normal.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create a new quad complete copy of this one.
|
||||
*
|
||||
* @return The new quad.
|
||||
*/
|
||||
public Quad copy() {
|
||||
if (!this.full) {
|
||||
throw new RuntimeException("Only copying full quads is supported.");
|
||||
}
|
||||
Quad quad = new Quad(this.format);
|
||||
quad.tintIndex = this.tintIndex;
|
||||
quad.orientation = this.orientation;
|
||||
quad.diffuseLighting = this.diffuseLighting;
|
||||
quad.sprite = this.sprite;
|
||||
quad.full = true;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
quad.vertices[i] = this.vertices[i].copy();
|
||||
}
|
||||
return quad;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the data inside the given quad to this one. This ignores VertexFormat,
|
||||
* please make sure your quads are in the same format.
|
||||
*
|
||||
* @param quad The Quad to copy from.
|
||||
*
|
||||
* @return This quad.
|
||||
*/
|
||||
public Quad copyFrom(Quad quad) {
|
||||
this.tintIndex = quad.tintIndex;
|
||||
this.orientation = quad.orientation;
|
||||
this.diffuseLighting = quad.diffuseLighting;
|
||||
this.sprite = quad.sprite;
|
||||
this.full = quad.full;
|
||||
for (int v = 0; v < 4; v++) {
|
||||
for (int e = 0; e < this.format.elementCount; e++) {
|
||||
System.arraycopy(quad.vertices[v].raw[e], 0, this.vertices[v].raw[e], 0, 4);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the quad to the new format.
|
||||
*
|
||||
* @param format The new format.
|
||||
*/
|
||||
public void reset(CachedFormat format) {
|
||||
this.format = format;
|
||||
this.tintIndex = -1;
|
||||
this.orientation = null;
|
||||
this.diffuseLighting = true;
|
||||
this.sprite = null;
|
||||
for (int i = 0; i < this.vertices.length; i++) {
|
||||
Vertex v = this.vertices[i];
|
||||
if (v == null) {
|
||||
this.vertices[i] = v = new Vertex(format);
|
||||
}
|
||||
v.reset(format);
|
||||
}
|
||||
this.vertexIndex = 0;
|
||||
this.full = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bakes this Quad to a BakedQuad.
|
||||
*
|
||||
* @return The BakedQuad.
|
||||
*/
|
||||
public BakedQuad bake() {
|
||||
if (format.format != VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL) {
|
||||
throw new IllegalStateException("Unable to bake this quad to the specified format. " + format.format);
|
||||
}
|
||||
int[] packedData = new int[this.format.format.getVertexSizeInteger()];
|
||||
for (int v = 0; v < 4; v++) {
|
||||
for (int e = 0; e < this.format.elementCount; e++) {
|
||||
// FIXME FABRIC LightUtil.pack(this.vertices[v].raw[e], packedData, this.format.format, v, e);
|
||||
}
|
||||
}
|
||||
return new BakedQuad(packedData, this.tintIndex, this.orientation, this.sprite, this.diffuseLighting);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple vertex format.
|
||||
*/
|
||||
public static class Vertex {
|
||||
|
||||
public CachedFormat format;
|
||||
|
||||
/**
|
||||
* The raw data.
|
||||
*/
|
||||
public float[][] raw;
|
||||
|
||||
// References to the arrays inside raw.
|
||||
public float[] vec;
|
||||
public float[] normal;
|
||||
public float[] color;
|
||||
public float[] uv;
|
||||
public float[] overlay;
|
||||
public float[] lightmap;
|
||||
|
||||
/**
|
||||
* Create a new Vertex.
|
||||
*
|
||||
* @param format The format for the vertex.
|
||||
*/
|
||||
public Vertex(CachedFormat format) {
|
||||
this.format = format;
|
||||
this.raw = new float[format.elementCount][4];
|
||||
this.preProcess();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Vertex using the data inside the other. A copy!
|
||||
*
|
||||
* @param other The other.
|
||||
*/
|
||||
public Vertex(Vertex other) {
|
||||
this.format = other.format;
|
||||
this.raw = other.raw.clone();
|
||||
for (int v = 0; v < this.format.elementCount; v++) {
|
||||
this.raw[v] = other.raw[v].clone();
|
||||
}
|
||||
this.preProcess();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls references to the individual element's arrays inside raw. Modifying the
|
||||
* individual element arrays will update raw.
|
||||
*/
|
||||
public void preProcess() {
|
||||
if (this.format.hasPosition) {
|
||||
this.vec = this.raw[this.format.positionIndex];
|
||||
}
|
||||
if (this.format.hasNormal) {
|
||||
this.normal = this.raw[this.format.normalIndex];
|
||||
}
|
||||
if (this.format.hasColor) {
|
||||
this.color = this.raw[this.format.colorIndex];
|
||||
}
|
||||
if (this.format.hasUV) {
|
||||
this.uv = this.raw[this.format.uvIndex];
|
||||
}
|
||||
if (format.hasOverlay) {
|
||||
overlay = raw[format.overlayIndex];
|
||||
}
|
||||
if (this.format.hasLightMap) {
|
||||
this.lightmap = this.raw[this.format.lightMapIndex];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 2d X coord for the given axis.
|
||||
*
|
||||
* @param s The axis. side >> 1
|
||||
*
|
||||
* @return The x coord.
|
||||
*/
|
||||
public float dx(int s) {
|
||||
if (s <= 1) {
|
||||
return this.vec[0];
|
||||
} else {
|
||||
return this.vec[2];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 2d Y coord for the given axis.
|
||||
*
|
||||
* @param s The axis. side >> 1
|
||||
*
|
||||
* @return The y coord.
|
||||
*/
|
||||
public float dy(int s) {
|
||||
if (s > 0) {
|
||||
return this.vec[1];
|
||||
} else {
|
||||
return this.vec[2];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates the new color values for this Vertex using the others as a
|
||||
* reference.
|
||||
*
|
||||
* @param interpHelper The InterpHelper to use.
|
||||
* @param others The other Vertices to use as a template.
|
||||
*
|
||||
* @return The same Vertex.
|
||||
*/
|
||||
public Vertex interpColorFrom(InterpHelper interpHelper, Vertex[] others) {
|
||||
for (int e = 0; e < 4; e++) {
|
||||
float p1 = others[0].color[e];
|
||||
float p2 = others[1].color[e];
|
||||
float p3 = others[2].color[e];
|
||||
float p4 = others[3].color[e];
|
||||
// Only interpolate if colors are different.
|
||||
if (p1 != p2 || p2 != p3 || p3 != p4) {
|
||||
this.color[e] = interpHelper.interpolate(p1, p2, p3, p4);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates the new UV values for this Vertex using the others as a
|
||||
* reference.
|
||||
*
|
||||
* @param interpHelper The InterpHelper to use.
|
||||
* @param others The other Vertices to use as a template.
|
||||
*
|
||||
* @return The same Vertex.
|
||||
*/
|
||||
public Vertex interpUVFrom(InterpHelper interpHelper, Vertex[] others) {
|
||||
for (int e = 0; e < 2; e++) {
|
||||
float p1 = others[0].uv[e];
|
||||
float p2 = others[1].uv[e];
|
||||
float p3 = others[2].uv[e];
|
||||
float p4 = others[3].uv[e];
|
||||
if (p1 != p2 || p2 != p3 || p3 != p4) {
|
||||
this.uv[e] = interpHelper.interpolate(p1, p2, p3, p4);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates the new LightMap values for this Vertex using the others as a
|
||||
* reference.
|
||||
*
|
||||
* @param interpHelper The InterpHelper to use.
|
||||
* @param others The other Vertices to use as a template.
|
||||
*
|
||||
* @return The same Vertex.
|
||||
*/
|
||||
public Vertex interpLightMapFrom(InterpHelper interpHelper, Vertex[] others) {
|
||||
for (int e = 0; e < 2; e++) {
|
||||
float p1 = others[0].lightmap[e];
|
||||
float p2 = others[1].lightmap[e];
|
||||
float p3 = others[2].lightmap[e];
|
||||
float p4 = others[3].lightmap[e];
|
||||
if (p1 != p2 || p2 != p3 || p3 != p4) {
|
||||
this.lightmap[e] = interpHelper.interpolate(p1, p2, p3, p4);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies this Vertex to a new one.
|
||||
*
|
||||
* @return The new Vertex.
|
||||
*/
|
||||
public Vertex copy() {
|
||||
return new Vertex(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the Vertex to a new format. Expands the raw array if needed.
|
||||
*
|
||||
* @param format The format to reset to.
|
||||
*/
|
||||
public void reset(CachedFormat format) {
|
||||
// If the format is different and our raw array is smaller, then expand it.
|
||||
if (!this.format.equals(format) && format.elementCount > this.raw.length) {
|
||||
this.raw = new float[format.elementCount][4];
|
||||
}
|
||||
this.format = format;
|
||||
|
||||
this.vec = null;
|
||||
this.normal = null;
|
||||
this.color = null;
|
||||
this.uv = null;
|
||||
this.lightmap = null;
|
||||
|
||||
// for (float[] f : raw) {
|
||||
// Arrays.fill(f, 0F);
|
||||
// }
|
||||
|
||||
this.preProcess();
|
||||
}
|
||||
}
|
||||
}
|
||||
-400
@@ -1,400 +0,0 @@
|
||||
/*
|
||||
* This file is part of CodeChickenLib.
|
||||
* Copyright (c) 2018, covers1624, All rights reserved.
|
||||
*
|
||||
* CodeChickenLib is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CodeChickenLib is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.thirdparty.codechicken.lib.model.pipeline;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.render.VertexFormat;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import appeng.thirdparty.codechicken.lib.model.CachedFormat;
|
||||
import appeng.thirdparty.codechicken.lib.model.ISmartVertexConsumer;
|
||||
import appeng.thirdparty.codechicken.lib.model.Quad;
|
||||
|
||||
/**
|
||||
* The BakedPipeline! Basically this allows us to efficiently transform a
|
||||
* BakedQuad, the Pipeline has Elements, each element has a name, state and a
|
||||
* transformer, you can enable and disable elements easily, you can also grab
|
||||
* the underlying transformer for the element if you need to set its state
|
||||
* before rendering.
|
||||
*
|
||||
* The BakedPipeline is final once created, you cannot add or remove elements,
|
||||
* you should not need to add or remove them runtime, enable and disable exist.
|
||||
*
|
||||
* You must use the Builder class to construct a BakedPipeline, see
|
||||
* {@link #builder}
|
||||
*
|
||||
* Transformers run on a mutable state inside each transformer, allowing for
|
||||
* easy reuse. It is recommended to store your pipeline inside a ThreadLocal
|
||||
* because 'minecraft'.
|
||||
*
|
||||
* Each Transformer should be smart enough to expand itself for each newly sized
|
||||
* VertexFormat it comes across, meaning that the internal states for the
|
||||
* transformers can be safely shared across VertexFormats, this reduces array
|
||||
* creations, and generally makes the system as efficient as it is.
|
||||
*
|
||||
* To use the system: Grab any elements you need to set state data on first,
|
||||
* using {@link #getElement(String, Class)} transformers should NOT clear their
|
||||
* state on pipeline Reset's so set any global data on elements now. Assuming
|
||||
* you are looping over a set of quads to transform, next you need to
|
||||
* {@link #reset} the pipeline, Now you should disable / enable any optional
|
||||
* elements that are needed, NOTE: Element states are reset when resetting the
|
||||
* pipeline. Now you will need to call {@link #prepare(IVertexConsumer)} on the
|
||||
* pipeline, here you will pass your collector, usually this is some form of
|
||||
* (Unpacked)BakedQuadBuilder, See {@link QuadBuilder} for a simple and fast
|
||||
* implementation for standard BakedQuads, and {@link UnpackedBakedQuad.Builder}
|
||||
* for UnpackedBakedQuads. Now final step, simply pipe the quad you want to
|
||||
* transform INTO the pipeline 'quad.pipe(pipeline)' And that's it! hell, Pipe a
|
||||
* pipeline into each other for all i care, the system is efficient enough that
|
||||
* there would be no performance penalty for doing so.
|
||||
*
|
||||
* @author covers1624
|
||||
*/
|
||||
public class BakedPipeline implements ISmartVertexConsumer {
|
||||
|
||||
private PipelineElement[] elements;
|
||||
private Map<String, PipelineElement> nameLookup;
|
||||
private IPipelineConsumer first;
|
||||
|
||||
private Quad unpacker = new Quad();
|
||||
|
||||
private BakedPipeline(PipelineElement[] elements) {
|
||||
this.elements = elements;
|
||||
this.nameLookup = Arrays.stream(elements).collect(Collectors.toMap(e -> e.name, e -> e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create a BakedPipeline.
|
||||
*
|
||||
* @return The builder.
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to reset the pipeline for the next quad. MUST be called between quads.
|
||||
*
|
||||
* @param format The format.
|
||||
*/
|
||||
public void reset(VertexFormat format) {
|
||||
this.reset(CachedFormat.lookup(format));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to reset the pipeline for the next quad. MUST be called between quads.
|
||||
*
|
||||
* @param format The format.
|
||||
*/
|
||||
public void reset(CachedFormat format) {
|
||||
this.unpacker.reset(format);
|
||||
for (PipelineElement element : this.elements) {
|
||||
element.reset(format);
|
||||
}
|
||||
this.first = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an element from the pipeline.
|
||||
*
|
||||
* @param name The name of the element.
|
||||
* @param clazz The Class of the element, used to safe cast.
|
||||
*
|
||||
* @return The element.
|
||||
*/
|
||||
public <T extends IPipelineConsumer> T getElement(String name, Class<T> clazz) {
|
||||
PipelineElement element = this.nameLookup.get(name);
|
||||
if (element != null) {
|
||||
if (!clazz.isAssignableFrom(element.consumer.getClass())) {
|
||||
throw new IllegalArgumentException(
|
||||
"Element with name " + name + " is not assignable from reference class.");
|
||||
}
|
||||
return clazz.cast(element.consumer);
|
||||
}
|
||||
throw new IllegalArgumentException("Element with name " + name + " does not exist.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to enable an element on the pipeline with the specified name.
|
||||
*
|
||||
* @param name The elements name.
|
||||
*/
|
||||
public void enableElement(String name) {
|
||||
this.setElementState(name, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to disable an element on the pipeline with the specified name.
|
||||
*
|
||||
* @param name The elements name.
|
||||
*/
|
||||
public void disableElement(String name) {
|
||||
this.setElementState(name, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to set the state of an element on the pipeline.
|
||||
*
|
||||
* @param name The name of the element.
|
||||
* @param enabled The state to set it to.
|
||||
*/
|
||||
public void setElementState(String name, boolean enabled) {
|
||||
PipelineElement element = this.nameLookup.get(name);
|
||||
if (element != null) {
|
||||
element.isEnabled = enabled;
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException("Element with name " + name + " does not exist.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Call when you are ready to use the pipeline. This builds the internal state
|
||||
* of the Elements getting things ready to transform.
|
||||
*
|
||||
* @param collector The IVertexConsumer that should collect the transformed
|
||||
* quad.
|
||||
*/
|
||||
public void prepare(IVertexConsumer collector) {
|
||||
IPipelineConsumer next = null;
|
||||
for (PipelineElement element : this.elements) {
|
||||
if (element.isEnabled) {
|
||||
if (this.first == null) {
|
||||
this.first = element.consumer;
|
||||
} else {
|
||||
next.setParent(element.consumer);
|
||||
}
|
||||
next = element.consumer;
|
||||
}
|
||||
}
|
||||
next.setParent(collector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexFormat getVertexFormat() {
|
||||
this.check();
|
||||
return this.first.getVertexFormat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQuadTint(int tint) {
|
||||
this.check();
|
||||
this.unpacker.setQuadTint(tint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQuadOrientation(Direction orientation) {
|
||||
this.check();
|
||||
this.unpacker.setQuadOrientation(orientation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplyDiffuseLighting(boolean diffuse) {
|
||||
this.check();
|
||||
this.unpacker.setApplyDiffuseLighting(diffuse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTexture(Sprite texture) {
|
||||
this.check();
|
||||
this.unpacker.setTexture(texture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(int element, float... data) {
|
||||
this.check();
|
||||
this.unpacker.put(element, data);
|
||||
if (this.unpacker.full) {
|
||||
this.onFull();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Quad quad) {
|
||||
this.check();
|
||||
this.unpacker.put(quad);
|
||||
}
|
||||
|
||||
private void check() {
|
||||
if (this.first == null) {
|
||||
throw new IllegalStateException("Pipeline used before prepare was called.");
|
||||
}
|
||||
}
|
||||
|
||||
private void onFull() {
|
||||
this.first.setInputQuad(this.unpacker);
|
||||
this.first.put(this.unpacker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class, used to hold a PipelineElement's state.
|
||||
*/
|
||||
public static class PipelineElement<T extends IPipelineConsumer> {
|
||||
|
||||
public String name;
|
||||
public boolean defaultState;
|
||||
public T consumer;
|
||||
public boolean isEnabled;
|
||||
|
||||
public void reset(CachedFormat format) {
|
||||
this.isEnabled = this.defaultState;
|
||||
this.consumer.setParent(null);
|
||||
this.consumer.reset(format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The builder associated with the BakedPipeline. You must create a
|
||||
* BakedPipeline with this, once created a pipeline cannot be modified,
|
||||
* modifying should not be needed as you can enable and disable elements with
|
||||
* ease.
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
private LinkedList<PipelineElement> elements = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Inserts an element to the front of the list, Useful if you have a more
|
||||
* complex system and each system need to be independent from each other, but
|
||||
* this element must be first.
|
||||
*
|
||||
* @param name The name to identify this element, used as an identifier when
|
||||
* setting state, and retrieving the element.
|
||||
* @param factory The factory used to create the Transformer.
|
||||
*
|
||||
* @return The same builder.
|
||||
*/
|
||||
public Builder addFirst(String name, IPipelineElementFactory<?> factory) {
|
||||
return this.addFirst(name, factory, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an element to the front of the list, Useful if you have a more
|
||||
* complex system and each system need to be independent from each other, but
|
||||
* this element must be first.
|
||||
*
|
||||
* @param name The name to identify this element, used as an identifier
|
||||
* when setting state, and retrieving the element.
|
||||
* @param factory The factory used to create the Transformer.
|
||||
* @param defaultState The default state for this element.
|
||||
*
|
||||
* @return The same builder.
|
||||
*/
|
||||
public Builder addFirst(String name, IPipelineElementFactory<?> factory, boolean defaultState) {
|
||||
return this.addFirst(name, factory, defaultState, e -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an element to the front of the list, Useful if you have a more
|
||||
* complex system and each system need to be independent from each other, but
|
||||
* this element must be first.
|
||||
*
|
||||
* @param name The name to identify this element, used as an
|
||||
* identifier when setting state, and retrieving the
|
||||
* element.
|
||||
* @param factory The factory used to create the Transformer.
|
||||
* @param defaultState The default state for this element.
|
||||
* @param defaultsSetter A callback used to set any defaults on the transformer.
|
||||
*
|
||||
* @return The same builder.
|
||||
*/
|
||||
public <T extends IPipelineConsumer> Builder addFirst(String name, IPipelineElementFactory<T> factory,
|
||||
boolean defaultState, Consumer<T> defaultsSetter) {
|
||||
PipelineElement<T> element = this.makeElement(name, factory, defaultState);
|
||||
defaultsSetter.accept(element.consumer);
|
||||
this.elements.addFirst(element);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element at the end of the transform list, Suitable for 99% of cases.
|
||||
*
|
||||
* @param name The name to identify this element, used as an identifier when
|
||||
* setting state, and retrieving the element.
|
||||
* @param factory The factory used to create the Transformer.
|
||||
*
|
||||
* @return The same builder.
|
||||
*/
|
||||
public Builder addElement(String name, IPipelineElementFactory<?> factory) {
|
||||
return this.addElement(name, factory, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element at the end of the transform list, Suitable for 99% of cases.
|
||||
*
|
||||
* @param name The name to identify this element, used as an identifier
|
||||
* when setting state, and retrieving the element.
|
||||
* @param factory The factory used to create the Transformer.
|
||||
* @param defaultState The default state for this element.
|
||||
*
|
||||
* @return The same builder.
|
||||
*/
|
||||
public Builder addElement(String name, IPipelineElementFactory<?> factory, boolean defaultState) {
|
||||
return this.addElement(name, factory, defaultState, e -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element at the end of the transform list, Suitable for 99% of cases.
|
||||
*
|
||||
* @param name The name to identify this element, used as an
|
||||
* identifier when setting state, and retrieving the
|
||||
* element.
|
||||
* @param factory The factory used to create the Transformer.
|
||||
* @param defaultState The default state for this element.
|
||||
* @param defaultsSetter A callback used to set any defaults on the transformer.
|
||||
*
|
||||
* @return The same builder.
|
||||
*/
|
||||
public <T extends IPipelineConsumer> Builder addElement(String name, IPipelineElementFactory<T> factory,
|
||||
boolean defaultState, Consumer<T> defaultsSetter) {
|
||||
PipelineElement<T> element = this.makeElement(name, factory, defaultState);
|
||||
defaultsSetter.accept(element.consumer);
|
||||
this.elements.add(element);
|
||||
return this;
|
||||
}
|
||||
|
||||
// Internal method, used to construct the PipelineElement class.
|
||||
private <T extends IPipelineConsumer> PipelineElement<T> makeElement(String name,
|
||||
IPipelineElementFactory<T> factory, boolean defaultState) {
|
||||
if (this.elements.stream().anyMatch(p -> p.name.equals(name))) {
|
||||
throw new IllegalArgumentException("Unable to add element with duplicate name: " + name);
|
||||
}
|
||||
PipelineElement<T> element = new PipelineElement<>();
|
||||
element.name = name;
|
||||
element.consumer = factory.create();
|
||||
element.defaultState = defaultState;
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this once you are finished to build your BakedPipeline!
|
||||
*
|
||||
* @return The new Pipeline.
|
||||
*/
|
||||
public BakedPipeline build() {
|
||||
return new BakedPipeline(this.elements.toArray(new PipelineElement[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* This file is part of CodeChickenLib.
|
||||
* Copyright (c) 2018, covers1624, All rights reserved.
|
||||
*
|
||||
* CodeChickenLib is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CodeChickenLib is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.thirdparty.codechicken.lib.model.pipeline;
|
||||
|
||||
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
|
||||
|
||||
import appeng.thirdparty.codechicken.lib.model.CachedFormat;
|
||||
import appeng.thirdparty.codechicken.lib.model.ISmartVertexConsumer;
|
||||
import appeng.thirdparty.codechicken.lib.model.Quad;
|
||||
import appeng.thirdparty.codechicken.lib.model.pipeline.transformers.QuadReInterpolator;
|
||||
|
||||
/**
|
||||
* Anything implementing this may be used in the BakedPipeline.
|
||||
*
|
||||
* @author covers1624
|
||||
*/
|
||||
public interface IPipelineConsumer extends ISmartVertexConsumer {
|
||||
|
||||
/**
|
||||
* The quad at the start of the transformation. This is useful for obtaining the
|
||||
* vertex data before any transformations have been applied, such as
|
||||
* interpolation, See {@link QuadReInterpolator}. When overriding this make sure
|
||||
* you call setInputQuad on your parent consumer too.
|
||||
*
|
||||
* @param quad The quad.
|
||||
*/
|
||||
void setInputQuad(Quad quad);
|
||||
|
||||
/**
|
||||
* Resets the Consumer to the new format. This should resize any internal arrays
|
||||
* if needed, ready for the new vertex data.
|
||||
*
|
||||
* @param format The format to reset to.
|
||||
*/
|
||||
void reset(CachedFormat format);
|
||||
|
||||
/**
|
||||
* Sets the parent consumer. This consumer may choose to not pipe any data,
|
||||
* that's fine, but if it does, it MUST pipe the data to the one provided here.
|
||||
*
|
||||
* @param parent The parent.
|
||||
*/
|
||||
void setParent(IVertexConsumer parent);
|
||||
}
|
||||
Vendored
-28
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* This file is part of CodeChickenLib.
|
||||
* Copyright (c) 2018, covers1624, All rights reserved.
|
||||
*
|
||||
* CodeChickenLib is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CodeChickenLib is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.thirdparty.codechicken.lib.model.pipeline;
|
||||
|
||||
/**
|
||||
* @author covers1624
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface IPipelineElementFactory<T extends IPipelineConsumer> {
|
||||
|
||||
T create();
|
||||
}
|
||||
-149
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* This file is part of CodeChickenLib.
|
||||
* Copyright (c) 2018, covers1624, All rights reserved.
|
||||
*
|
||||
* CodeChickenLib is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CodeChickenLib is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.thirdparty.codechicken.lib.model.pipeline;
|
||||
|
||||
import javax.annotation.OverridingMethodsMustInvokeSuper;
|
||||
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.render.VertexFormat;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
|
||||
|
||||
import appeng.thirdparty.codechicken.lib.model.CachedFormat;
|
||||
import appeng.thirdparty.codechicken.lib.model.ISmartVertexConsumer;
|
||||
import appeng.thirdparty.codechicken.lib.model.Quad;
|
||||
|
||||
/**
|
||||
* Base class for a simple QuadTransformer. Operates on BakedQuads.
|
||||
* QuadTransformers can be piped into each other at no performance penalty.
|
||||
*
|
||||
* @author covers1624
|
||||
*/
|
||||
public abstract class QuadTransformer implements IVertexConsumer, ISmartVertexConsumer, IPipelineConsumer {
|
||||
|
||||
protected CachedFormat format;
|
||||
protected IVertexConsumer consumer;
|
||||
protected Quad quad;
|
||||
|
||||
/**
|
||||
* Used for the BakedPipeline.
|
||||
*/
|
||||
protected QuadTransformer() {
|
||||
this.quad = new Quad();
|
||||
}
|
||||
|
||||
public QuadTransformer(IVertexConsumer consumer) {
|
||||
this(consumer.getVertexFormat(), consumer);
|
||||
}
|
||||
|
||||
public QuadTransformer(VertexFormat format, IVertexConsumer consumer) {
|
||||
this(CachedFormat.lookup(format), consumer);
|
||||
}
|
||||
|
||||
public QuadTransformer(CachedFormat format, IVertexConsumer consumer) {
|
||||
this.format = format;
|
||||
this.consumer = consumer;
|
||||
this.quad = new Quad(format);
|
||||
}
|
||||
|
||||
@Override
|
||||
@OverridingMethodsMustInvokeSuper
|
||||
public void reset(CachedFormat format) {
|
||||
this.format = format;
|
||||
this.quad.reset(format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(IVertexConsumer parent) {
|
||||
this.consumer = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
@OverridingMethodsMustInvokeSuper
|
||||
public void setInputQuad(Quad quad) {
|
||||
if (this.consumer instanceof IPipelineConsumer) {
|
||||
((IPipelineConsumer) this.consumer).setInputQuad(quad);
|
||||
}
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
@Override
|
||||
public VertexFormat getVertexFormat() {
|
||||
return this.format.format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQuadTint(int tint) {
|
||||
this.quad.setQuadTint(tint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQuadOrientation(Direction orientation) {
|
||||
this.quad.setQuadOrientation(orientation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplyDiffuseLighting(boolean diffuse) {
|
||||
this.quad.setApplyDiffuseLighting(diffuse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTexture(Sprite texture) {
|
||||
this.quad.setTexture(texture);
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
@Override
|
||||
public void put(int element, float... data) {
|
||||
this.quad.put(element, data);
|
||||
if (this.quad.full) {
|
||||
this.onFull();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Quad quad) {
|
||||
this.quad.put(quad);
|
||||
this.onFull();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to transform the vertices.
|
||||
*
|
||||
* @return If the transformer should pipe the quad.
|
||||
*/
|
||||
public abstract boolean transform();
|
||||
|
||||
public void onFull() {
|
||||
if (this.transform()) {
|
||||
this.quad.pipe(this.consumer);
|
||||
}
|
||||
}
|
||||
|
||||
// Should be small enough.
|
||||
private final static double EPSILON = 0.00001;
|
||||
|
||||
public static boolean epsComp(float a, float b) {
|
||||
if (a == b) {
|
||||
return true;
|
||||
} else {
|
||||
return Math.abs(a - b) < EPSILON;
|
||||
}
|
||||
}
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package appeng.thirdparty.codechicken.lib.model.pipeline;
|
||||
|
||||
import net.minecraft.client.render.VertexFormat;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
public interface VertexConsumer {
|
||||
VertexFormat getVertexFormat();
|
||||
void setQuadTint(int tint);
|
||||
void setQuadOrientation(Direction orientation);
|
||||
void setApplyDiffuseLighting(boolean diffuse);
|
||||
void setTexture(Sprite texture);
|
||||
void put(int element, float... data);
|
||||
}
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
package appeng.thirdparty.codechicken.lib.model.pipeline;
|
||||
|
||||
public interface VertexProducer {
|
||||
void pipe(VertexConsumer consumer);
|
||||
}
|
||||
Reference in New Issue
Block a user