first code commit
9
.classpath
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src/main/java"/>
|
||||
<classpathentry kind="src" path="src/main/resources"/>
|
||||
<classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry exported="true" kind="con" path="org.springsource.ide.eclipse.gradle.classpathcontainer"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/MinecraftForge-1.7.2"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.gradle/
|
||||
.settings/
|
||||
bin/
|
||||
build/
|
||||
libs/
|
||||
18
.project
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>BetterFoliage</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.springsource.ide.eclipse.gradle.core.nature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
45
build.gradle
Normal file
@@ -0,0 +1,45 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
name = "forge"
|
||||
url = "http://files.minecraftforge.net/maven"
|
||||
}
|
||||
maven {
|
||||
name = "sonatype"
|
||||
url = "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT'
|
||||
}
|
||||
}
|
||||
apply plugin: 'forge'
|
||||
|
||||
minecraft {
|
||||
version = '1.7.2-10.12.1.1098'
|
||||
}
|
||||
|
||||
jar.baseName = 'BetterFoliage-1.7.2'
|
||||
group = 'com.github.octarine-noise'
|
||||
version='0.9b'
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
inputs.property "mcversion", project.minecraft.version
|
||||
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include 'mcmod.info'
|
||||
expand 'version':project.version, 'mcversion':project.minecraft.version
|
||||
}
|
||||
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
exclude 'mcmod.info'
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes("FMLCorePlugin": "mods.betterfoliage.loader.BetterFoliageLoader", "FMLCorePluginContainsFMLMod": "mods.betterfoliage.BetterFoliage")
|
||||
}
|
||||
}
|
||||
51
src/main/java/mods/betterfoliage/BetterFoliage.java
Normal file
@@ -0,0 +1,51 @@
|
||||
package mods.betterfoliage;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import mods.betterfoliage.client.BetterFoliageClient;
|
||||
import mods.betterfoliage.common.config.Config;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import cpw.mods.fml.common.Mod;
|
||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.network.NetworkCheckHandler;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
|
||||
@Mod(name=BetterFoliage.MOD_NAME, modid=BetterFoliage.MOD_ID, acceptedMinecraftVersions="[1.7.2]", guiFactory="mods.betterfoliage.client.gui.ConfigGuiFactory")
|
||||
public class BetterFoliage {
|
||||
|
||||
public static final String MOD_ID = "BetterFoliage";
|
||||
public static final String MOD_NAME = "Better Foliage";
|
||||
|
||||
@Mod.Instance
|
||||
public static BetterFoliage instance;
|
||||
|
||||
public static Logger log;
|
||||
|
||||
public static File configDir;
|
||||
|
||||
@Mod.EventHandler
|
||||
public void preInit(FMLPreInitializationEvent event) {
|
||||
log = event.getModLog();
|
||||
if (event.getSide() == Side.CLIENT) {
|
||||
configDir = new File(event.getModConfigurationDirectory(), "betterfoliage");
|
||||
configDir.mkdir();
|
||||
Config.load();
|
||||
BetterFoliageClient.preInit();
|
||||
}
|
||||
}
|
||||
|
||||
@Mod.EventHandler
|
||||
public void postInit(FMLPostInitializationEvent event) {
|
||||
if (event.getSide() == Side.CLIENT) {
|
||||
}
|
||||
}
|
||||
|
||||
@NetworkCheckHandler
|
||||
public boolean checkVersion(Map<String, String> mods, Side side) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package mods.betterfoliage;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
|
||||
/** Allows overriding block rendertype.
|
||||
* @author octarine-noise
|
||||
*/
|
||||
public class BlockRenderTypeOverride {
|
||||
|
||||
public static IRenderTypeProvider provider = null;
|
||||
|
||||
public static interface IRenderTypeProvider {
|
||||
public int getRenderType(Block block);
|
||||
}
|
||||
|
||||
/** Entry point from transformed RenderBlocks class. If no provider is given,
|
||||
* replicates default behaviour
|
||||
* @param block block instance
|
||||
* @return block render type
|
||||
*/
|
||||
public static int getRenderType(Block block) {
|
||||
return provider == null ? block.getRenderType() : provider.getRenderType(block);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package mods.betterfoliage.client;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
import mods.betterfoliage.BetterFoliage;
|
||||
import mods.betterfoliage.BlockRenderTypeOverride;
|
||||
import mods.betterfoliage.BlockRenderTypeOverride.IRenderTypeProvider;
|
||||
import mods.betterfoliage.client.render.RenderBlockBetterGrass;
|
||||
import mods.betterfoliage.client.render.RenderBlockBetterLeaves;
|
||||
import mods.betterfoliage.client.resource.ILeafTextureRecognizer;
|
||||
import mods.betterfoliage.client.resource.LeafTextureGenerator;
|
||||
import mods.betterfoliage.common.config.Config;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockGrass;
|
||||
import net.minecraft.block.BlockLeavesBase;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class BetterFoliageClient implements IRenderTypeProvider, ILeafTextureRecognizer {
|
||||
|
||||
public static int leavesRenderId;
|
||||
public static int grassRenderId;
|
||||
public static LeafTextureGenerator leafGenerator;
|
||||
public static Set<Class<?>> blockLeavesClasses = Sets.newHashSet();
|
||||
|
||||
public static void preInit() {
|
||||
FMLCommonHandler.instance().bus().register(new KeyHandler());
|
||||
|
||||
BetterFoliage.log.info("Registering renderers");
|
||||
leavesRenderId = RenderBlockBetterLeaves.register();
|
||||
grassRenderId = RenderBlockBetterGrass.register();
|
||||
BlockRenderTypeOverride.provider = new BetterFoliageClient();
|
||||
|
||||
blockLeavesClasses.add(BlockLeavesBase.class);
|
||||
addLeafBlockClass("forestry.arboriculture.gadgets.BlockLeaves");
|
||||
addLeafBlockClass("thaumcraft.common.blocks.BlockMagicalLeaves");
|
||||
|
||||
BetterFoliage.log.info("Registering leaf texture generator");
|
||||
leafGenerator = new LeafTextureGenerator();
|
||||
MinecraftForge.EVENT_BUS.register(leafGenerator);
|
||||
leafGenerator.recognizers.add(new BetterFoliageClient());
|
||||
leafGenerator.loadLeafMappings(new File(BetterFoliage.configDir, "leafMask.properties"));
|
||||
}
|
||||
|
||||
protected static void addLeafBlockClass(String className) {
|
||||
try {
|
||||
blockLeavesClasses.add(Class.forName(className));
|
||||
} catch(ClassNotFoundException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public int getRenderType(Block block) {
|
||||
if (Config.grassEnabled && block instanceof BlockGrass) return grassRenderId;
|
||||
|
||||
if (Config.leavesEnabled)
|
||||
for (Class<?> clazz : blockLeavesClasses)
|
||||
if (clazz.isAssignableFrom(block.getClass()))
|
||||
return leavesRenderId;
|
||||
|
||||
return block.getRenderType();
|
||||
}
|
||||
|
||||
public boolean isLeafTexture(TextureAtlasSprite icon) {
|
||||
String resourceLocation = icon.getIconName();
|
||||
if (resourceLocation.startsWith("forestry:leaves/")) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
27
src/main/java/mods/betterfoliage/client/KeyHandler.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package mods.betterfoliage.client;
|
||||
|
||||
import cpw.mods.fml.client.FMLClientHandler;
|
||||
import cpw.mods.fml.client.registry.ClientRegistry;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.common.gameevent.InputEvent;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import mods.betterfoliage.BetterFoliage;
|
||||
import mods.betterfoliage.client.gui.ConfigGuiScreen;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class KeyHandler {
|
||||
|
||||
public static KeyBinding guiBinding;
|
||||
|
||||
public KeyHandler() {
|
||||
guiBinding = new KeyBinding("key.betterfoliage.gui", 66, BetterFoliage.MOD_NAME);
|
||||
ClientRegistry.registerKeyBinding(guiBinding);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void handleKeyPress(InputEvent.KeyInputEvent event) {
|
||||
if (guiBinding.isPressed()) FMLClientHandler.instance().showGuiScreen(new ConfigGuiScreen(null));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package mods.betterfoliage.client.gui;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import cpw.mods.fml.client.IModGuiFactory;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class ConfigGuiFactory implements IModGuiFactory {
|
||||
|
||||
public void initialize(Minecraft minecraftInstance) {
|
||||
|
||||
}
|
||||
|
||||
public Class<? extends GuiScreen> mainConfigGuiClass() {
|
||||
return ConfigGuiScreen.class;
|
||||
}
|
||||
|
||||
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories() {
|
||||
return ImmutableSet.<RuntimeOptionCategoryElement>of();
|
||||
}
|
||||
|
||||
public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package mods.betterfoliage.client.gui;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import mods.betterfoliage.common.config.Config;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import cpw.mods.fml.client.FMLClientHandler;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class ConfigGuiScreen extends GuiScreen {
|
||||
|
||||
public enum Button {CLOSE, TOGGLE_LEAVES, TOGGLE_GRASS}
|
||||
|
||||
private GuiScreen parent;
|
||||
protected List<OptionDoubleWidget> widgets = Lists.newLinkedList();
|
||||
|
||||
public ConfigGuiScreen(GuiScreen parent) {
|
||||
this.parent = parent;
|
||||
int id = 3;
|
||||
widgets.add(new OptionDoubleWidget(Config.leavesSize, -160, -65, 150, 40, id++, id++, "message.betterfoliage.size", "%.2f"));
|
||||
widgets.add(new OptionDoubleWidget(Config.leavesHOffset, -160, -35, 150, 40, id++, id++, "message.betterfoliage.hOffset", "%.3f"));
|
||||
widgets.add(new OptionDoubleWidget(Config.leavesVOffset, -160, -5, 150, 40, id++, id++, "message.betterfoliage.vOffset", "%.3f"));
|
||||
|
||||
widgets.add(new OptionDoubleWidget(Config.grassSize, 10, -65, 150, 40, id++, id++, "message.betterfoliage.size", "%.2f"));
|
||||
widgets.add(new OptionDoubleWidget(Config.grassHOffset, 10, -35, 150, 40, id++, id++, "message.betterfoliage.hOffset", "%.3f"));
|
||||
widgets.add(new OptionDoubleWidget(Config.grassHeightMin, 10, -5, 150, 40, id++, id++, "message.betterfoliage.minHeight", "%.2f"));
|
||||
widgets.add(new OptionDoubleWidget(Config.grassHeightMax, 10, 25, 150, 40, id++, id++, "message.betterfoliage.maxHeight", "%.2f"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
int x = width / 2;
|
||||
int y = height / 2;
|
||||
for (OptionDoubleWidget widget : widgets) widget.drawStrings(this, fontRendererObj, x, y, 14737632, 16777120);
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void initGui() {
|
||||
int x = width / 2;
|
||||
int y = height / 2;
|
||||
for (OptionDoubleWidget widget : widgets) widget.addButtons(buttonList, x, y);
|
||||
buttonList.add(new GuiButton(Button.CLOSE.ordinal(), x - 50, y + 100, 100, 20, "Close"));
|
||||
buttonList.add(new GuiButton(Button.TOGGLE_LEAVES.ordinal(), x - 160, y - 100, 150, 20, ""));
|
||||
buttonList.add(new GuiButton(Button.TOGGLE_GRASS.ordinal(), x + 10, y - 100, 150, 20, ""));
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
protected void updateButtons() {
|
||||
setButtonOptionBoolean(Button.TOGGLE_LEAVES, "message.betterfoliage.betterLeaves", Config.leavesEnabled);
|
||||
setButtonOptionBoolean(Button.TOGGLE_GRASS, "message.betterfoliage.betterGrass", Config.grassEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(GuiButton button) {
|
||||
super.actionPerformed(button);
|
||||
|
||||
if (button.id == Button.CLOSE.ordinal()) {
|
||||
Config.save();
|
||||
Minecraft.getMinecraft().renderGlobal.loadRenderers();
|
||||
FMLClientHandler.instance().showGuiScreen(parent);
|
||||
}
|
||||
if (button.id == Button.TOGGLE_LEAVES.ordinal()) Config.leavesEnabled = !Config.leavesEnabled;
|
||||
if (button.id == Button.TOGGLE_GRASS.ordinal()) Config.grassEnabled = !Config.grassEnabled;
|
||||
|
||||
for (OptionDoubleWidget widget : widgets) {
|
||||
if (button.id == widget.idDecrement) widget.option.decrement();
|
||||
if (button.id == widget.idIncrement) widget.option.increment();
|
||||
if (widget.option == Config.grassHeightMin && Config.grassHeightMin.value > Config.grassHeightMax.value) Config.grassHeightMin.value = Config.grassHeightMax.value;
|
||||
if (widget.option == Config.grassHeightMax && Config.grassHeightMin.value > Config.grassHeightMax.value) Config.grassHeightMax.value = Config.grassHeightMin.value;
|
||||
}
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void setButtonOptionBoolean(Button enumButton, String msgKey, boolean option) {
|
||||
for (GuiButton button : (List<GuiButton>) buttonList) {
|
||||
if (button.id == enumButton.ordinal()) {
|
||||
String optionText = option ? (EnumChatFormatting.GREEN + I18n.format("message.betterfoliage.optionOn")) : (EnumChatFormatting.RED + I18n.format("message.betterfoliage.optionOff"));
|
||||
button.displayString = I18n.format(msgKey, optionText);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package mods.betterfoliage.client.gui;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
import mods.betterfoliage.common.config.OptionDouble;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class OptionDoubleWidget {
|
||||
|
||||
public OptionDouble option;
|
||||
public int x;
|
||||
public int y;
|
||||
public int width;
|
||||
public int numWidth;
|
||||
public int idDecrement;
|
||||
public int idIncrement;
|
||||
public String keyLabel;
|
||||
public String formatString;
|
||||
|
||||
public OptionDoubleWidget(OptionDouble option, int x, int y, int width, int numWidth, int idDecrement, int idIncrement, String keyLabel, String formatString) {
|
||||
this.option = option;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.numWidth = numWidth;
|
||||
this.idDecrement = idDecrement;
|
||||
this.idIncrement = idIncrement;
|
||||
this.keyLabel = keyLabel;
|
||||
this.formatString = formatString;
|
||||
}
|
||||
|
||||
public void addButtons(List<GuiButton> buttonList, int xOffset, int yOffset) {
|
||||
buttonList.add(new GuiButton(idDecrement, xOffset + x + width - numWidth - 40, yOffset + y, 20, 20, "-"));
|
||||
buttonList.add(new GuiButton(idIncrement, xOffset + x + width - 20, yOffset + y, 20, 20, "+"));
|
||||
}
|
||||
|
||||
public void drawStrings(GuiScreen screen, FontRenderer fontRenderer, int xOffset, int yOffset, int labelColor, int numColor) {
|
||||
screen.drawString(fontRenderer, I18n.format(keyLabel), xOffset + x, yOffset + y + 5, labelColor);
|
||||
screen.drawCenteredString(fontRenderer, String.format(formatString, option.value), xOffset + x + width - 20 - numWidth / 2, yOffset + y + 5, numColor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
package mods.betterfoliage.client.render;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import mods.betterfoliage.common.util.Double3;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.renderer.RenderBlocks;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.util.MathHelper;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
/** Block renderer base class. Stores calculated ambient occlusion light and color values when rendering
|
||||
* block sides for later use.
|
||||
* @author octarine-noise
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class RenderBlockAOBase extends RenderBlocks {
|
||||
|
||||
/** AO light and color values
|
||||
* @author octarine-noise
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static class ShadingValues {
|
||||
public int passCounter = 0;
|
||||
public int brightness;
|
||||
public float red;
|
||||
public float green;
|
||||
public float blue;
|
||||
}
|
||||
|
||||
protected double[] uValues = new double[] {0.0, 16.0, 16.0, 0.0};
|
||||
protected double[] vValues = new double[] {0.0, 0.0, 16.0, 16.0};
|
||||
|
||||
/** Random vector pool. Unit rotation vectors in the XZ plane, Y coord goes between [-1.0, 1.0].
|
||||
* Filled at init time */
|
||||
public Double3[] pRot = new Double3[64];
|
||||
|
||||
/** Pool of random double values. Filled at init time. */
|
||||
public double[] pRand = new double[64];
|
||||
|
||||
public ShadingValues aoXPYZPP = new ShadingValues();
|
||||
public ShadingValues aoXPYZPN = new ShadingValues();
|
||||
public ShadingValues aoXPYZNP = new ShadingValues();
|
||||
public ShadingValues aoXPYZNN = new ShadingValues();
|
||||
public ShadingValues aoXNYZPP = new ShadingValues();
|
||||
public ShadingValues aoXNYZPN = new ShadingValues();
|
||||
public ShadingValues aoXNYZNP = new ShadingValues();
|
||||
public ShadingValues aoXNYZNN = new ShadingValues();
|
||||
public ShadingValues aoYPXZPP = new ShadingValues();
|
||||
public ShadingValues aoYPXZPN = new ShadingValues();
|
||||
public ShadingValues aoYPXZNP = new ShadingValues();
|
||||
public ShadingValues aoYPXZNN = new ShadingValues();
|
||||
public ShadingValues aoYNXZPP = new ShadingValues();
|
||||
public ShadingValues aoYNXZPN = new ShadingValues();
|
||||
public ShadingValues aoYNXZNP = new ShadingValues();
|
||||
public ShadingValues aoYNXZNN = new ShadingValues();
|
||||
public ShadingValues aoZPXYPP = new ShadingValues();
|
||||
public ShadingValues aoZPXYPN = new ShadingValues();
|
||||
public ShadingValues aoZPXYNP = new ShadingValues();
|
||||
public ShadingValues aoZPXYNN = new ShadingValues();
|
||||
public ShadingValues aoZNXYPP = new ShadingValues();
|
||||
public ShadingValues aoZNXYPN = new ShadingValues();
|
||||
public ShadingValues aoZNXYNP = new ShadingValues();
|
||||
public ShadingValues aoZNXYNN = new ShadingValues();
|
||||
|
||||
/** Initialize random values */
|
||||
public void init() {
|
||||
List<Double3> perturbs = new ArrayList<Double3>(64);
|
||||
for (int idx = 0; idx < 64; idx++) {
|
||||
double angle = (double) idx * Math.PI * 2.0 / 64.0;
|
||||
perturbs.add(new Double3(Math.cos(angle), Math.random() * 2.0 - 1.0, Math.sin(angle)));
|
||||
pRand[idx] = Math.random();
|
||||
}
|
||||
Collections.shuffle(perturbs);
|
||||
Iterator<Double3> iter = perturbs.iterator();
|
||||
for (int idx = 0; idx < 64; idx++) pRot[idx] = iter.next();
|
||||
}
|
||||
|
||||
/** Get a semi-random value depending on block position.
|
||||
* @param x block X coord
|
||||
* @param y block Y coord
|
||||
* @param z block Z coord
|
||||
* @param seed additional seed
|
||||
* @return semirandom value
|
||||
*/
|
||||
protected int getSemiRandomFromPos(double x, double y, double z, int seed) {
|
||||
int sum = MathHelper.floor_double(x) * 3 + MathHelper.floor_double(y) * 5 + MathHelper.floor_double(z) * 7 + seed * 11;
|
||||
return sum & 63;
|
||||
}
|
||||
|
||||
protected void renderStandardBlockAsItem(RenderBlocks renderer, Block p_147800_1_, int p_147800_2_, float p_147800_3_) {
|
||||
Tessellator tessellator = Tessellator.instance;
|
||||
boolean flag = p_147800_1_ == Blocks.grass;
|
||||
|
||||
float f2;
|
||||
float f3;
|
||||
int k;
|
||||
|
||||
p_147800_1_.setBlockBoundsForItemRender();
|
||||
renderer.setRenderBoundsFromBlock(p_147800_1_);
|
||||
GL11.glRotatef(90.0F, 0.0F, 1.0F, 0.0F);
|
||||
GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.setNormal(0.0F, -1.0F, 0.0F);
|
||||
renderer.renderFaceYNeg(p_147800_1_, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(p_147800_1_, 0, p_147800_2_));
|
||||
tessellator.draw();
|
||||
|
||||
if (flag && renderer.useInventoryTint)
|
||||
{
|
||||
k = p_147800_1_.getRenderColor(p_147800_2_);
|
||||
f2 = (float)(k >> 16 & 255) / 255.0F;
|
||||
f3 = (float)(k >> 8 & 255) / 255.0F;
|
||||
float f4 = (float)(k & 255) / 255.0F;
|
||||
GL11.glColor4f(f2 * p_147800_3_, f3 * p_147800_3_, f4 * p_147800_3_, 1.0F);
|
||||
}
|
||||
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.setNormal(0.0F, 1.0F, 0.0F);
|
||||
renderer.renderFaceYPos(p_147800_1_, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(p_147800_1_, 1, p_147800_2_));
|
||||
tessellator.draw();
|
||||
|
||||
if (flag && renderer.useInventoryTint)
|
||||
{
|
||||
GL11.glColor4f(p_147800_3_, p_147800_3_, p_147800_3_, 1.0F);
|
||||
}
|
||||
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.setNormal(0.0F, 0.0F, -1.0F);
|
||||
renderer.renderFaceZNeg(p_147800_1_, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(p_147800_1_, 2, p_147800_2_));
|
||||
tessellator.draw();
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.setNormal(0.0F, 0.0F, 1.0F);
|
||||
renderer.renderFaceZPos(p_147800_1_, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(p_147800_1_, 3, p_147800_2_));
|
||||
tessellator.draw();
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.setNormal(-1.0F, 0.0F, 0.0F);
|
||||
renderer.renderFaceXNeg(p_147800_1_, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(p_147800_1_, 4, p_147800_2_));
|
||||
tessellator.draw();
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.setNormal(1.0F, 0.0F, 0.0F);
|
||||
renderer.renderFaceXPos(p_147800_1_, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(p_147800_1_, 5, p_147800_2_));
|
||||
tessellator.draw();
|
||||
GL11.glTranslatef(0.5F, 0.5F, 0.5F);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderFaceZNeg(Block block, double x, double y, double z, IIcon icon) {
|
||||
super.renderFaceZNeg(block, x, y, z, icon);
|
||||
saveShadingTopLeft(aoZNXYPP);
|
||||
saveShadingTopRight(aoZNXYNP);
|
||||
saveShadingBottomLeft(aoZNXYPN);
|
||||
saveShadingBottomRight(aoZNXYNN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderFaceZPos(Block block, double x, double y, double z, IIcon icon) {
|
||||
super.renderFaceZPos(block, x, y, z, icon);
|
||||
saveShadingTopLeft(aoZPXYNP);
|
||||
saveShadingTopRight(aoZPXYPP);
|
||||
saveShadingBottomLeft(aoZPXYNN);
|
||||
saveShadingBottomRight(aoZPXYPN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderFaceXNeg(Block block, double x, double y, double z, IIcon icon) {
|
||||
super.renderFaceXNeg(block, x, y, z, icon);
|
||||
saveShadingTopLeft(aoXNYZPN);
|
||||
saveShadingTopRight(aoXNYZPP);
|
||||
saveShadingBottomLeft(aoXNYZNN);
|
||||
saveShadingBottomRight(aoXNYZNP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderFaceXPos(Block block, double x, double y, double z, IIcon icon) {
|
||||
super.renderFaceXPos(block, x, y, z, icon);
|
||||
saveShadingTopLeft(aoXPYZPP);
|
||||
saveShadingTopRight(aoXPYZPN);
|
||||
saveShadingBottomLeft(aoXPYZNP);
|
||||
saveShadingBottomRight(aoXPYZNN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderFaceYNeg(Block block, double x, double y, double z, IIcon icon) {
|
||||
super.renderFaceYNeg(block, x, y, z, icon);
|
||||
saveShadingTopLeft(aoYNXZNP);
|
||||
saveShadingTopRight(aoYNXZPP);
|
||||
saveShadingBottomLeft(aoYNXZNN);
|
||||
saveShadingBottomRight(aoYNXZPN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderFaceYPos(Block block, double x, double y, double z, IIcon icon) {
|
||||
super.renderFaceYPos(block, x, y, z, icon);
|
||||
saveShadingTopLeft(aoYPXZPP);
|
||||
saveShadingTopRight(aoYPXZNP);
|
||||
saveShadingBottomLeft(aoYPXZPN);
|
||||
saveShadingBottomRight(aoYPXZNN);
|
||||
}
|
||||
|
||||
/** Save AO values for top left vertex
|
||||
* @param values {@link ShadingValues} to store values in
|
||||
*/
|
||||
protected void saveShadingTopLeft(ShadingValues values) {
|
||||
if (--values.passCounter != 0) return;
|
||||
values.brightness = brightnessTopLeft;
|
||||
values.red = colorRedTopLeft;
|
||||
values.green = colorGreenTopLeft;
|
||||
values.blue = colorBlueTopLeft;
|
||||
}
|
||||
|
||||
protected void saveShadingTopRight(ShadingValues values) {
|
||||
if (--values.passCounter != 0) return;
|
||||
values.brightness = brightnessTopRight;
|
||||
values.red = colorRedTopRight;
|
||||
values.green = colorGreenTopRight;
|
||||
values.blue = colorBlueTopRight;
|
||||
}
|
||||
|
||||
protected void saveShadingBottomLeft(ShadingValues values) {
|
||||
if (--values.passCounter != 0) return;
|
||||
values.brightness = brightnessBottomLeft;
|
||||
values.red = colorRedBottomLeft;
|
||||
values.green = colorGreenBottomLeft;
|
||||
values.blue = colorBlueBottomLeft;
|
||||
}
|
||||
|
||||
protected void saveShadingBottomRight(ShadingValues values) {
|
||||
if (--values.passCounter != 0) return;
|
||||
values.brightness = brightnessBottomRight;
|
||||
values.red = colorRedBottomRight;
|
||||
values.green = colorGreenBottomRight;
|
||||
values.blue = colorBlueBottomRight;
|
||||
}
|
||||
|
||||
/** Set pass counter on all shading value objects.
|
||||
* Used to collect AO values from a specific draw pass
|
||||
* if the underlying renderer draws overlays
|
||||
* @param value pass counter
|
||||
*/
|
||||
protected void setPassCounters(int value) {
|
||||
aoXPYZPP.passCounter = value;
|
||||
aoXPYZPN.passCounter = value;
|
||||
aoXPYZNP.passCounter = value;
|
||||
aoXPYZNN.passCounter = value;
|
||||
aoXNYZPP.passCounter = value;
|
||||
aoXNYZPN.passCounter = value;
|
||||
aoXNYZNP.passCounter = value;
|
||||
aoXNYZNN.passCounter = value;
|
||||
aoYPXZPP.passCounter = value;
|
||||
aoYPXZPN.passCounter = value;
|
||||
aoYPXZNP.passCounter = value;
|
||||
aoYPXZNN.passCounter = value;
|
||||
aoYNXZPP.passCounter = value;
|
||||
aoYNXZPN.passCounter = value;
|
||||
aoYNXZNP.passCounter = value;
|
||||
aoYNXZNN.passCounter = value;
|
||||
aoZPXYPP.passCounter = value;
|
||||
aoZPXYPN.passCounter = value;
|
||||
aoZPXYNP.passCounter = value;
|
||||
aoZPXYNN.passCounter = value;
|
||||
aoZNXYPP.passCounter = value;
|
||||
aoZNXYPN.passCounter = value;
|
||||
aoZNXYNP.passCounter = value;
|
||||
aoZNXYNN.passCounter = value;
|
||||
}
|
||||
|
||||
/** Render textured quad
|
||||
* @param icon texture to use
|
||||
* @param center center of quad
|
||||
* @param vec1 vector to the half-point of one of the sides
|
||||
* @param vec2 vector to half-point of side next to vec1
|
||||
* @param uvRot number of increments to rotate UV coordinates by
|
||||
*/
|
||||
protected void renderQuad(IIcon icon, Double3 center, Double3 vec1, Double3 vec2, int uvRot) {
|
||||
Tessellator tessellator = Tessellator.instance;
|
||||
tessellator.addVertexWithUV(center.x + vec1.x + vec2.x, center.y + vec1.y + vec2.y, center.z + vec1.z + vec2.z, icon.getInterpolatedU(uValues[uvRot & 3]), icon.getInterpolatedV(vValues[uvRot & 3]));
|
||||
tessellator.addVertexWithUV(center.x - vec1.x + vec2.x, center.y - vec1.y + vec2.y, center.z - vec1.z + vec2.z, icon.getInterpolatedU(uValues[(uvRot + 1) & 3]), icon.getInterpolatedV(vValues[(uvRot + 1) & 3]));
|
||||
tessellator.addVertexWithUV(center.x - vec1.x - vec2.x, center.y - vec1.y - vec2.y, center.z - vec1.z - vec2.z, icon.getInterpolatedU(uValues[(uvRot + 2) & 3]), icon.getInterpolatedV(vValues[(uvRot + 2) & 3]));
|
||||
tessellator.addVertexWithUV(center.x + vec1.x - vec2.x, center.y + vec1.y - vec2.y, center.z + vec1.z - vec2.z, icon.getInterpolatedU(uValues[(uvRot + 3) & 3]), icon.getInterpolatedV(vValues[(uvRot + 3) & 3]));
|
||||
}
|
||||
|
||||
/** Render textured quad using AO information
|
||||
* @param icon texture to use
|
||||
* @param center center of quad
|
||||
* @param vec1 vector to the half-point of one of the sides
|
||||
* @param vec2 vector to half-point of side next to vec1
|
||||
* @param uvRot number of increments to rotate UV coordinates by
|
||||
* @param aoPP AO values for vertex at (+vec1, +vec2)
|
||||
* @param aoNP AO values for vertex at (-vec1, +vec2)
|
||||
* @param aoNN AO values for vertex at (-vec1, -vec2)
|
||||
* @param aoPN AO values for vertex at (+vec1, -vec2)
|
||||
*/
|
||||
protected void renderQuadWithShading(IIcon icon, Double3 center, Double3 vec1, Double3 vec2, int uvRot, ShadingValues aoPP, ShadingValues aoNP, ShadingValues aoNN, ShadingValues aoPN) {
|
||||
Tessellator tessellator = Tessellator.instance;
|
||||
tessellator.setBrightness(aoPP.brightness);
|
||||
tessellator.setColorOpaque_F(aoPP.red, aoPP.green, aoPP.blue);
|
||||
tessellator.addVertexWithUV(center.x + vec1.x + vec2.x, center.y + vec1.y + vec2.y, center.z + vec1.z + vec2.z, icon.getInterpolatedU(uValues[uvRot & 3]), icon.getInterpolatedV(vValues[uvRot & 3]));
|
||||
tessellator.setBrightness(aoNP.brightness);
|
||||
tessellator.setColorOpaque_F(aoNP.red, aoNP.green, aoNP.blue);
|
||||
tessellator.addVertexWithUV(center.x - vec1.x + vec2.x, center.y - vec1.y + vec2.y, center.z - vec1.z + vec2.z, icon.getInterpolatedU(uValues[(uvRot + 1) & 3]), icon.getInterpolatedV(vValues[(uvRot + 1) & 3]));
|
||||
tessellator.setBrightness(aoNN.brightness);
|
||||
tessellator.setColorOpaque_F(aoNN.red, aoNN.green, aoNN.blue);
|
||||
tessellator.addVertexWithUV(center.x - vec1.x - vec2.x, center.y - vec1.y - vec2.y, center.z - vec1.z - vec2.z, icon.getInterpolatedU(uValues[(uvRot + 2) & 3]), icon.getInterpolatedV(vValues[(uvRot + 2) & 3]));
|
||||
tessellator.setBrightness(aoPN.brightness);
|
||||
tessellator.setColorOpaque_F(aoPN.red, aoPN.green, aoPN.blue);
|
||||
tessellator.addVertexWithUV(center.x + vec1.x - vec2.x, center.y + vec1.y - vec2.y, center.z + vec1.z - vec2.z, icon.getInterpolatedU(uValues[(uvRot + 3) & 3]), icon.getInterpolatedV(vValues[(uvRot + 3) & 3]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package mods.betterfoliage.client.render;
|
||||
|
||||
import mods.betterfoliage.common.config.Config;
|
||||
import mods.betterfoliage.common.util.Double3;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.RenderBlocks;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
|
||||
import cpw.mods.fml.client.registry.RenderingRegistry;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class RenderBlockBetterGrass extends RenderBlockAOBase implements ISimpleBlockRenderingHandler {
|
||||
|
||||
public IIcon grassIcons[] = new IIcon[2];
|
||||
|
||||
public static int register() {
|
||||
int result = RenderingRegistry.getNextAvailableRenderId();
|
||||
RenderBlockBetterGrass renderGrass = new RenderBlockBetterGrass();
|
||||
RenderingRegistry.registerBlockHandler(result, renderGrass);
|
||||
MinecraftForge.EVENT_BUS.register(renderGrass);
|
||||
renderGrass.init();
|
||||
return result;
|
||||
}
|
||||
|
||||
public void renderInventoryBlock(Block block, int metadata, int modelId, RenderBlocks renderer) {
|
||||
renderStandardBlockAsItem(renderer, block, metadata, 1.0f);
|
||||
}
|
||||
|
||||
public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) {
|
||||
// store world for later use
|
||||
blockAccess = world;
|
||||
|
||||
// render grass block
|
||||
setRenderBoundsFromBlock(block);
|
||||
setPassCounters(1);
|
||||
boolean result = renderStandardBlock(block, x, y, z);
|
||||
|
||||
if (y == 255 || !blockAccess.isAirBlock(x, y + 1, z)) return result;
|
||||
|
||||
int variation = getSemiRandomFromPos(x, y, z, 0);
|
||||
int heightVariation = getSemiRandomFromPos(x, y, z, 1);
|
||||
double halfSize = Config.grassSize.value * 0.5;
|
||||
double halfHeight = 0.5 * (Config.grassHeightMin.value + pRand[heightVariation] * (Config.grassHeightMax.value - Config.grassHeightMin.value));
|
||||
Double3 drawCenter = new Double3(x + 0.5, y + 1.0 + halfHeight, z + 0.5).add(pRot[variation].scaleAxes(Config.grassHOffset.value, 0.0, Config.grassHOffset.value));
|
||||
Double3 horz1 = new Double3(halfSize, 0.0, halfSize);
|
||||
Double3 horz2 = new Double3(halfSize, 0.0, -halfSize);
|
||||
Double3 vert1 = new Double3(0.0, halfHeight, 0.0);
|
||||
IIcon grassIcon = grassIcons[variation % 2];
|
||||
|
||||
if (Minecraft.isAmbientOcclusionEnabled()) {
|
||||
renderQuadWithShading(grassIcon, drawCenter, horz1, vert1, 0, aoYPXZPP, aoYPXZNN, aoYPXZNN, aoYPXZPP);
|
||||
renderQuadWithShading(grassIcon, drawCenter, horz1.inverse(), vert1, 0, aoYPXZNN, aoYPXZPP, aoYPXZPP, aoYPXZNN);
|
||||
renderQuadWithShading(grassIcon, drawCenter, horz2, vert1, 0, aoYPXZPN, aoYPXZNP, aoYPXZNP, aoYPXZPN);
|
||||
renderQuadWithShading(grassIcon, drawCenter, horz2.inverse(), vert1, 0, aoYPXZNP, aoYPXZPN, aoYPXZPN, aoYPXZNP);
|
||||
} else {
|
||||
Tessellator.instance.setBrightness(block.getMixedBrightnessForBlock(blockAccess, x, y + 1, z));
|
||||
renderQuad(grassIcon, drawCenter, horz1, vert1, 0);
|
||||
renderQuad(grassIcon, drawCenter, horz1.inverse(), vert1, 0);
|
||||
renderQuad(grassIcon, drawCenter, horz2, vert1, 0);
|
||||
renderQuad(grassIcon, drawCenter, horz2.inverse(), vert1, 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean shouldRender3DInInventory(int modelId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getRenderId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void handleTextureReload(TextureStitchEvent.Pre event) {
|
||||
if (event.map.getTextureType() != 0) return;
|
||||
for (int idx = 0; idx < 2; idx++) {
|
||||
grassIcons[idx] = event.map.registerIcon(String.format("betterfoliage:grass_%d", idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package mods.betterfoliage.client.render;
|
||||
|
||||
import mods.betterfoliage.client.BetterFoliageClient;
|
||||
import mods.betterfoliage.common.config.Config;
|
||||
import mods.betterfoliage.common.util.Double3;
|
||||
import mods.betterfoliage.common.util.ReflectionUtil;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.RenderBlocks;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
|
||||
import cpw.mods.fml.client.registry.RenderingRegistry;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class RenderBlockBetterLeaves extends RenderBlockAOBase implements ISimpleBlockRenderingHandler {
|
||||
|
||||
public static int register() {
|
||||
int result = RenderingRegistry.getNextAvailableRenderId();
|
||||
RenderBlockBetterLeaves renderLeaves = new RenderBlockBetterLeaves();
|
||||
RenderingRegistry.registerBlockHandler(result, renderLeaves);
|
||||
renderLeaves.init();
|
||||
return result;
|
||||
}
|
||||
|
||||
public void renderInventoryBlock(Block block, int metadata, int modelId, RenderBlocks renderer) {
|
||||
renderStandardBlockAsItem(renderer, block, metadata, 1.0f);
|
||||
}
|
||||
|
||||
public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) {
|
||||
// store world for later use
|
||||
blockAccess = world;
|
||||
|
||||
// render leaves center
|
||||
setPassCounters(1);
|
||||
int origRenderType = block.getRenderType();
|
||||
boolean result;
|
||||
|
||||
setRenderBoundsFromBlock(block);
|
||||
if (origRenderType == 0) {
|
||||
result = renderStandardBlock(block, x, y, z);
|
||||
} else {
|
||||
ISimpleBlockRenderingHandler handler = ReflectionUtil.getRenderingHandler(origRenderType);
|
||||
result = handler.renderWorldBlock(world, x, y, z, block, origRenderType, this);
|
||||
}
|
||||
|
||||
if (isBlockSurrounded(x, y, z)) return result;
|
||||
|
||||
// find generated texture to render with, assume the
|
||||
// "true" texture of the block is the one on the north size
|
||||
TextureAtlasSprite blockLeafIcon = (TextureAtlasSprite) block.getIcon(world, x, y, z, ForgeDirection.NORTH.ordinal());
|
||||
IIcon crossLeafIcon = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(BetterFoliageClient.leafGenerator.domainName + ":" + blockLeafIcon.getIconName());
|
||||
if (crossLeafIcon == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int variation = getSemiRandomFromPos(x, y, z, 0);
|
||||
double halfSize = 0.5 * Config.leavesSize.value;
|
||||
boolean isAirTop = y == 255 || blockAccess.isAirBlock(x, y + 1, z);
|
||||
boolean isAirBottom = y == 0 || blockAccess.isAirBlock(x, y - 1, z);
|
||||
Double3 drawCenter = new Double3(x + 0.5, y + 0.5, z + 0.5);
|
||||
Double3 horz1 = new Double3(halfSize, 0.0, halfSize).add(pRot[variation].scaleAxes(Config.leavesHOffset.value, Config.leavesVOffset.value, Config.leavesHOffset.value));
|
||||
Double3 horz2 = new Double3(halfSize, 0.0, -halfSize).add(pRot[(variation + 1) & 63].scaleAxes(Config.leavesHOffset.value, Config.leavesVOffset.value, Config.leavesHOffset.value));
|
||||
Double3 vert1 = new Double3(0.0, halfSize * 1.41, 0.0);
|
||||
|
||||
if (Minecraft.isAmbientOcclusionEnabled()) {
|
||||
renderQuadWithShading(crossLeafIcon, drawCenter, horz1, vert1, variation,
|
||||
isAirTop ? aoYPXZPP : aoZPXYPP, isAirTop ? aoYPXZNN : aoXNYZPN, isAirBottom ? aoYNXZNN : aoXNYZNN, isAirBottom ? aoYNXZPP : aoZPXYPN);
|
||||
renderQuadWithShading(crossLeafIcon, drawCenter, horz1.inverse(), vert1, variation,
|
||||
isAirTop ? aoYPXZNN : aoZNXYNP, isAirTop ? aoYPXZPP : aoXPYZPP, isAirBottom ? aoYNXZPP : aoXPYZNP, isAirBottom ? aoYNXZNN : aoZNXYNN);
|
||||
renderQuadWithShading(crossLeafIcon, drawCenter, horz2, vert1, variation,
|
||||
isAirTop ? aoYPXZPN : aoXPYZPN, isAirTop ? aoYPXZNP : aoZPXYNP, isAirBottom ? aoYNXZNP : aoZPXYNN, isAirBottom ? aoYNXZPN : aoXPYZNN);
|
||||
renderQuadWithShading(crossLeafIcon, drawCenter, horz2.inverse(), vert1, variation,
|
||||
isAirTop ? aoYPXZNP : aoXNYZPP, isAirTop ? aoYPXZPN : aoZNXYPP, isAirBottom ? aoYNXZPN : aoZNXYPN, isAirBottom ? aoYNXZNP : aoXNYZNP);
|
||||
} else {
|
||||
if (isAirTop) Tessellator.instance.setBrightness(block.getMixedBrightnessForBlock(blockAccess, x, y + 1, z));
|
||||
else if (isAirBottom) Tessellator.instance.setBrightness(block.getMixedBrightnessForBlock(blockAccess, x, y - 1, z));
|
||||
else Tessellator.instance.setBrightness(block.getMixedBrightnessForBlock(blockAccess, x, y, z));
|
||||
|
||||
renderQuad(crossLeafIcon, drawCenter, horz1, vert1, variation);
|
||||
renderQuad(crossLeafIcon, drawCenter, horz1.inverse(), vert1, variation);
|
||||
renderQuad(crossLeafIcon, drawCenter, horz2, vert1, variation);
|
||||
renderQuad(crossLeafIcon, drawCenter, horz2.inverse(), vert1, variation);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean shouldRender3DInInventory(int modelId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getRenderId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected boolean isBlockSurrounded(int x, int y, int z) {
|
||||
if (blockAccess.isAirBlock(x + 1, y, z)) return false;
|
||||
if (blockAccess.isAirBlock(x - 1, y, z)) return false;
|
||||
if (blockAccess.isAirBlock(x, y, z + 1)) return false;
|
||||
if (blockAccess.isAirBlock(x, y, z - 1)) return false;
|
||||
if (y == 255 || blockAccess.isAirBlock(x, y + 1, z)) return false;
|
||||
if (y == 0 || blockAccess.isAirBlock(x, y - 1, z)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package mods.betterfoliage.client.resource;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public interface ILeafTextureRecognizer {
|
||||
|
||||
public boolean isLeafTexture(TextureAtlasSprite icon);
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package mods.betterfoliage.client.resource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import mods.betterfoliage.BetterFoliage;
|
||||
import mods.betterfoliage.client.BetterFoliageClient;
|
||||
import mods.betterfoliage.common.util.DeobfNames;
|
||||
import mods.betterfoliage.common.util.ReflectionUtil;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.IIconRegister;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
/** Generates rounded crossleaf textures for all registered normal leaf textures at stitch time.
|
||||
* @author octarine-noise
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class LeafTextureGenerator implements IIconRegister, IResourceManager {
|
||||
|
||||
/** Resource domain name of autogenerated crossleaf textures */
|
||||
public String domainName = "bf_leaves_autogen";
|
||||
|
||||
/** Resource location for fallback texture (if the generation process fails) */
|
||||
public ResourceLocation missing_resource = new ResourceLocation("betterfoliage", "textures/blocks/missingleaf.png");
|
||||
|
||||
/** Texture atlas for block textures used in the current run */
|
||||
public TextureMap blockTextures;
|
||||
|
||||
/** List of helpers which can identify leaf textures loaded by alternate means */
|
||||
public List<ILeafTextureRecognizer> recognizers = Lists.newLinkedList();
|
||||
|
||||
/** Number of textures generated in the current run */
|
||||
int counter = 0;
|
||||
|
||||
/** Map leaf types to alpha masks */
|
||||
public Map<String, String> maskMappings = Maps.newHashMap();
|
||||
|
||||
public Set<String> getResourceDomains() {
|
||||
return ImmutableSet.<String>of(domainName);
|
||||
}
|
||||
|
||||
public IResource getResource(ResourceLocation resourceLocation) throws IOException {
|
||||
// remove "/blocks/textures/" from beginning
|
||||
String origResPath = resourceLocation.getResourcePath().substring(16);
|
||||
LeafTextureResource result = new LeafTextureResource(new ResourceLocation(origResPath), maskMappings);
|
||||
if (result.data == null) {
|
||||
return Minecraft.getMinecraft().getResourceManager().getResource(missing_resource);
|
||||
} else {
|
||||
counter++;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public List<IResource> getAllResources(ResourceLocation resource) throws IOException {
|
||||
return ImmutableList.<IResource>of();
|
||||
}
|
||||
|
||||
/** Leaf blocks register their textures here. An extra texture will be registered in the atlas
|
||||
* for each, with the resource domain of this generator.
|
||||
* @return the originally registered {@link IIcon} already in the atlas
|
||||
*/
|
||||
public IIcon registerIcon(String resourceLocation) {
|
||||
IIcon original = blockTextures.getTextureExtry(resourceLocation);
|
||||
blockTextures.registerIcon(new ResourceLocation(domainName, resourceLocation).toString());
|
||||
BetterFoliage.log.debug(String.format("Found leaf texture: %s", resourceLocation));
|
||||
return original;
|
||||
}
|
||||
|
||||
/** Iterates through all leaf blocks in the registry and makes them register
|
||||
* their textures to "sniff out" all leaf textures.
|
||||
* @param event
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@SubscribeEvent
|
||||
public void handleTextureReload(TextureStitchEvent.Pre event) {
|
||||
if (event.map.getTextureType() != 0) return;
|
||||
|
||||
blockTextures = event.map;
|
||||
counter = 0;
|
||||
BetterFoliage.log.info("Reloading leaf textures");
|
||||
|
||||
Map<String, IResourceManager> domainManagers = ReflectionUtil.getDomainResourceManagers();
|
||||
if (domainManagers == null) {
|
||||
BetterFoliage.log.warn("Failed to inject leaf texture generator");
|
||||
return;
|
||||
}
|
||||
domainManagers.put(domainName, this);
|
||||
|
||||
// register simple block textures
|
||||
Iterator<Block> iter = Block.blockRegistry.iterator();
|
||||
while(iter.hasNext()) {
|
||||
Block block = iter.next();
|
||||
for (Class<?> clazz : BetterFoliageClient.blockLeavesClasses) if (clazz.isAssignableFrom(block.getClass())) {
|
||||
BetterFoliage.log.debug(String.format("Inspecting leaf block: %s", block.getClass().getName()));
|
||||
block.registerBlockIcons(this);
|
||||
}
|
||||
}
|
||||
|
||||
// enumerate all registered textures, find leaf textures among them
|
||||
Map<String, TextureAtlasSprite> mapAtlas = null;
|
||||
mapAtlas = ReflectionUtil.getField(blockTextures, DeobfNames.TM_MRS_SRG, Map.class);
|
||||
if (mapAtlas == null) mapAtlas = ReflectionUtil.getField(blockTextures, DeobfNames.TM_MRS_MCP, Map.class);
|
||||
if (mapAtlas == null) {
|
||||
BetterFoliage.log.warn("Failed to reflect texture atlas, textures may be missing");
|
||||
} else {
|
||||
Set<String> foundLeafTextures = Sets.newHashSet();
|
||||
for (TextureAtlasSprite icon : mapAtlas.values())
|
||||
for (ILeafTextureRecognizer recognizer : recognizers)
|
||||
if (recognizer.isLeafTexture(icon))
|
||||
foundLeafTextures.add(icon.getIconName());
|
||||
for (String resourceLocation : foundLeafTextures) {
|
||||
BetterFoliage.log.debug(String.format("Found non-block-registered leaf texture: %s", resourceLocation));
|
||||
blockTextures.registerIcon(new ResourceLocation(domainName, resourceLocation).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void endTextureReload(TextureStitchEvent.Post event) {
|
||||
blockTextures = null;
|
||||
if (event.map.getTextureType() == 0) BetterFoliage.log.info(String.format("Generated %d leaf textures", counter));
|
||||
}
|
||||
|
||||
public void loadLeafMappings(File leafMaskFile) {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
FileInputStream fis = new FileInputStream(leafMaskFile);
|
||||
props.load(fis);
|
||||
} catch (Exception e) {
|
||||
maskMappings.put("spruce", "fine");
|
||||
maskMappings.put("fir", "fine");
|
||||
maskMappings.put("bamboo", "fine");
|
||||
saveLeafMappings(leafMaskFile);
|
||||
return;
|
||||
}
|
||||
|
||||
for (Map.Entry<Object, Object> entry : props.entrySet()) {
|
||||
maskMappings.put(entry.getKey().toString(), entry.getValue().toString());
|
||||
}
|
||||
BetterFoliage.log.info(String.format("Loaded %d leaf mask mappings", maskMappings.size()));
|
||||
}
|
||||
|
||||
protected void saveLeafMappings(File leafMaskFile) {
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(leafMaskFile);
|
||||
Properties props = new Properties();
|
||||
props.putAll(maskMappings);
|
||||
props.store(fos, "");
|
||||
} catch (Exception e) {
|
||||
BetterFoliage.log.info("Failed to save default leaf mask mappings");
|
||||
return;
|
||||
}
|
||||
BetterFoliage.log.info("Created default leaf mask mappings");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package mods.betterfoliage.client.resource;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import mods.betterfoliage.BetterFoliage;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.data.IMetadataSection;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
/** {@link IResource} containing an autogenerated round crossleaf texture
|
||||
* @author octarine-noise
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class LeafTextureResource implements IResource {
|
||||
|
||||
/** Raw PNG data*/
|
||||
protected byte[] data = null;
|
||||
|
||||
/** Name of the default alpha mask to use */
|
||||
public static String defaultMask = "rough";
|
||||
|
||||
public LeafTextureResource(ResourceLocation resLeaf, Map<String, String> maskMappings) {
|
||||
IResourceManager resourceManager = Minecraft.getMinecraft().getResourceManager();
|
||||
try {
|
||||
// load normal leaf texture
|
||||
ResourceLocation origResource = new ResourceLocation(resLeaf.getResourceDomain(), "textures/blocks/" + resLeaf.getResourcePath());
|
||||
BufferedImage origImage = ImageIO.read(resourceManager.getResource(origResource).getInputStream());
|
||||
if (origImage.getWidth() != origImage.getHeight()) return;
|
||||
int size = origImage.getWidth();
|
||||
|
||||
// load alpha mask of appropriate size
|
||||
String maskType = defaultMask;
|
||||
for(Map.Entry<String, String> entry : maskMappings.entrySet()) if (resLeaf.getResourcePath().contains(entry.getKey())) {
|
||||
maskType = entry.getValue();
|
||||
break;
|
||||
}
|
||||
BufferedImage maskImage = loadLeafMaskImage(maskType, size * 2);
|
||||
int scale = size * 2 / maskImage.getWidth();
|
||||
|
||||
// tile leaf texture 2x2
|
||||
BufferedImage overlayIcon = new BufferedImage(size * 2, size * 2, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
Graphics2D graphics = overlayIcon.createGraphics();
|
||||
graphics.drawImage(origImage, 0, 0, null);
|
||||
graphics.drawImage(origImage, 0, size, null);
|
||||
graphics.drawImage(origImage, size, 0, null);
|
||||
graphics.drawImage(origImage, size, size, null);
|
||||
|
||||
// overlay mask alpha on texture
|
||||
for (int x = 0; x < overlayIcon.getWidth(); x++) {
|
||||
for (int y = 0; y < overlayIcon.getHeight(); y++) {
|
||||
long origPixel = overlayIcon.getRGB(x, y) & 0xFFFFFFFFl;
|
||||
long maskPixel = maskImage.getRGB(x / scale, y / scale) & 0xFF000000l | 0x00FFFFFF;
|
||||
overlayIcon.setRGB(x, y, (int) (origPixel & maskPixel));
|
||||
}
|
||||
}
|
||||
|
||||
// create PNG image
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ImageIO.write(overlayIcon, "PNG", baos);
|
||||
data = baos.toByteArray();
|
||||
} catch (Exception e) {
|
||||
BetterFoliage.log.info(String.format("Could not create leaf texture: %s, exception: %s", resLeaf.toString(), e.getClass().getSimpleName()));
|
||||
}
|
||||
}
|
||||
|
||||
/** Loads the alpha mask of the given type and size. If a mask of the exact size can not be found,
|
||||
* will try to load progressively smaller masks down to 16x16
|
||||
* @param type mask type
|
||||
* @param size texture size
|
||||
* @return alpha mask
|
||||
*/
|
||||
protected BufferedImage loadLeafMaskImage(String type, int size) {
|
||||
IResourceManager resourceManager = Minecraft.getMinecraft().getResourceManager();
|
||||
IResource maskResource = null;
|
||||
|
||||
while (maskResource == null && size >= 16) {
|
||||
try {
|
||||
maskResource = resourceManager.getResource(new ResourceLocation(String.format("betterfoliage:textures/blocks/leafmask_%d_%s.png", size, type)));
|
||||
} catch (Exception e) {}
|
||||
size /= 2;
|
||||
}
|
||||
|
||||
try {
|
||||
return maskResource == null ? null : ImageIO.read(maskResource.getInputStream());
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return data != null ? new ByteArrayInputStream(data) : null;
|
||||
}
|
||||
|
||||
public boolean hasMetadata() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public IMetadataSection getMetadata(String var1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
74
src/main/java/mods/betterfoliage/common/config/Config.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package mods.betterfoliage.common.config;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import mods.betterfoliage.BetterFoliage;
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
|
||||
public class Config {
|
||||
|
||||
public static boolean leavesEnabled = true;
|
||||
public static boolean grassEnabled = true;
|
||||
|
||||
public static OptionDouble leavesHOffset = new OptionDouble(0.0, 0.4, 0.025, 0.2);
|
||||
public static OptionDouble leavesVOffset = new OptionDouble(0.0, 0.4, 0.025, 0.1);
|
||||
public static OptionDouble leavesSize = new OptionDouble(0.75, 1.8, 0.05, 1.4);
|
||||
|
||||
public static OptionDouble grassHOffset = new OptionDouble(0.0, 0.4, 0.025, 0.2);
|
||||
public static OptionDouble grassHeightMin = new OptionDouble(0.1, 1.5, 0.05, 0.5);
|
||||
public static OptionDouble grassHeightMax = new OptionDouble(0.1, 1.5, 0.05, 1.0);
|
||||
public static OptionDouble grassSize = new OptionDouble(0.5, 1.5, 0.05, 1.0);
|
||||
|
||||
private Config() {}
|
||||
|
||||
public static void load() {
|
||||
Configuration config = new Configuration(new File(BetterFoliage.configDir, "betterfoliage.cfg"));
|
||||
config.load();
|
||||
|
||||
leavesEnabled = config.get("render", "leavesEnabled", true).getBoolean(true);
|
||||
loadValue(config, "render", "leavesHorizontalOffset", leavesHOffset);
|
||||
loadValue(config, "render", "leavesVerticalOffset", leavesVOffset);
|
||||
loadValue(config, "render", "leavesSize", leavesSize);
|
||||
|
||||
grassEnabled = config.get("render", "grassEnabled", true).getBoolean(true);
|
||||
loadValue(config, "render", "grassHorizontalOffset", grassHOffset);
|
||||
loadValue(config, "render", "grassHeightMin", grassHeightMin);
|
||||
loadValue(config, "render", "grassHeightMax", grassHeightMax);
|
||||
if (grassHeightMin.value > grassHeightMax.value) grassHeightMin.value = grassHeightMax.value;
|
||||
|
||||
if (config.hasChanged()) config.save();
|
||||
}
|
||||
|
||||
public static void save() {
|
||||
Configuration config = new Configuration(new File(BetterFoliage.configDir, "betterfoliage.cfg"));
|
||||
config.load();
|
||||
|
||||
config.get("render", "leavesEnabled", true).set(leavesEnabled);
|
||||
saveValue(config, "render", "leavesHorizontalOffset", leavesHOffset);
|
||||
saveValue(config, "render", "leavesVerticalOffset", leavesVOffset);
|
||||
saveValue(config, "render", "leavesSize", leavesSize);
|
||||
|
||||
config.get("render", "grassEnabled", true).set(grassEnabled);
|
||||
saveValue(config, "render", "grassHorizontalOffset", grassHOffset);
|
||||
saveValue(config, "render", "grassHeightMin", grassHeightMin);
|
||||
saveValue(config, "render", "grassHeightMax", grassHeightMax);
|
||||
|
||||
if (config.hasChanged()) config.save();
|
||||
}
|
||||
|
||||
protected static void saveValue(Configuration config, String category, String key, OptionDouble option) {
|
||||
config.get(category, key, option.value).set(option.value);
|
||||
}
|
||||
|
||||
protected static void loadValue(Configuration config, String category, String key, OptionDouble option) {
|
||||
option.value = config.get(category, key, option.value).getDouble(option.value);
|
||||
if (option.value > option.max) {
|
||||
option.value = option.max;
|
||||
saveValue(config, category, key, option);
|
||||
}
|
||||
if (option.value < option.min) {
|
||||
option.value = option.min;
|
||||
saveValue(config, category, key, option);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package mods.betterfoliage.common.config;
|
||||
|
||||
public class OptionDouble {
|
||||
|
||||
public double min;
|
||||
public double max;
|
||||
public double step;
|
||||
public double value;
|
||||
|
||||
public OptionDouble(double min, double max, double step, double value) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.step = step;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void increment() {
|
||||
value += step;
|
||||
if (value > max) value = max;
|
||||
}
|
||||
|
||||
public void decrement() {
|
||||
value -= step;
|
||||
if (value < min) value = min;
|
||||
}
|
||||
}
|
||||
39
src/main/java/mods/betterfoliage/common/util/DeobfNames.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package mods.betterfoliage.common.util;
|
||||
|
||||
public class DeobfNames {
|
||||
|
||||
private DeobfNames() {}
|
||||
|
||||
/** MCP name of RenderBlocks.renderBlockByRenderType() */
|
||||
public static final String RB_RBBRT_NAME_MCP = "renderBlockByRenderType";
|
||||
|
||||
/** Obfuscated name of RenderBlocks.renderBlockByRenderType() */
|
||||
public static final String RB_RBBRT_NAME_OBF = "b";
|
||||
|
||||
/** MCP signature of RenderBlocks.renderBlockByRenderType() */
|
||||
public static final String RB_RBBRT_SIG_MCP = "(Lnet/minecraft/block/Block;III)Z";
|
||||
|
||||
/** Obfuscated signature of RenderBlocks.renderBlockByRenderType() */
|
||||
public static final String RB_RBBRT_SIG_OBF = "(Lahu;III)Z";
|
||||
|
||||
/** MCP signature of BlockRenderTypeOverride.getRenderType(Block) */
|
||||
public static final String BRTO_GRT_SIG_MCP = "(Lnet/minecraft/block/Block;)I";
|
||||
|
||||
/** Obfuscated signature of BlockRenderTypeOverride.getRenderType(Block) */
|
||||
public static final String BRTO_GRT_SIG_OBF = "(Lahu;)I";
|
||||
|
||||
/** MCP name of SimpleReloadableResourceManager.domainResourceManagers */
|
||||
public static final String SRRM_DRM_MCP = "domainResourceManagers";
|
||||
|
||||
/** SRG name of SimpleReloadableResourceManager.domainResourceManagers */
|
||||
public static final String SRRM_DRM_SRGNAME = "field_110548_a";
|
||||
|
||||
/** MCP name of TextureMap.mapRegisteredSprites */
|
||||
public static final String TM_MRS_MCP = "mapRegisteredSprites";
|
||||
|
||||
/** Obfuscated name of TextureMap.mapRegisteredSprites */
|
||||
public static final String TM_MRS_OBF = "bpr";
|
||||
|
||||
/** SRG name of TextureMap.mapRegisteredSprites */
|
||||
public static final String TM_MRS_SRG = "field_110574_e";
|
||||
}
|
||||
30
src/main/java/mods/betterfoliage/common/util/Double3.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package mods.betterfoliage.common.util;
|
||||
|
||||
public class Double3 {
|
||||
|
||||
public final double x;
|
||||
public final double y;
|
||||
public final double z;
|
||||
|
||||
public Double3(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Double3 add(Double3 other) {
|
||||
return new Double3(x + other.x, y + other.y, z + other.z);
|
||||
}
|
||||
|
||||
public Double3 scaleAxes(double sx, double sy, double sz) {
|
||||
return new Double3(x * sx, y * sy, z * sz);
|
||||
}
|
||||
|
||||
public Double3 scale(double s) {
|
||||
return new Double3(x * s, y * s, z * s);
|
||||
}
|
||||
|
||||
public Double3 inverse() {
|
||||
return new Double3(-x, -y, -z);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package mods.betterfoliage.common.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
|
||||
import cpw.mods.fml.client.registry.RenderingRegistry;
|
||||
|
||||
public class ReflectionUtil {
|
||||
|
||||
private ReflectionUtil() {}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, IResourceManager> getDomainResourceManagers() {
|
||||
IResourceManager manager = Minecraft.getMinecraft().getResourceManager();
|
||||
Map<String, IResourceManager> result = getField(manager, DeobfNames.SRRM_DRM_MCP, Map.class);
|
||||
if (result == null) result = getField(manager, DeobfNames.SRRM_DRM_SRGNAME, Map.class);
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getField(Object target, String fieldName, Class<T> resultClass) {
|
||||
try {
|
||||
Field field = target.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(target);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getStaticField(Class<?> clazz, String fieldName, Class<T> resultClass) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(null);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static ISimpleBlockRenderingHandler getRenderingHandler(int renderType) {
|
||||
try {
|
||||
Field field = RenderingRegistry.class.getDeclaredField("INSTANCE");
|
||||
field.setAccessible(true);
|
||||
RenderingRegistry inst = (RenderingRegistry) field.get(null);
|
||||
field = RenderingRegistry.class.getDeclaredField("blockRenderers");
|
||||
field.setAccessible(true);
|
||||
return ((Map<Integer, ISimpleBlockRenderingHandler>) field.get(inst)).get(renderType);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package mods.betterfoliage.loader;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||
|
||||
@IFMLLoadingPlugin.MCVersion("1.7.2")
|
||||
public class BetterFoliageLoader implements IFMLLoadingPlugin {
|
||||
|
||||
public String[] getASMTransformerClass() {
|
||||
return new String[] {"mods.betterfoliage.loader.BetterFoliageTransformer"};
|
||||
}
|
||||
|
||||
public String getModContainerClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getSetupClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void injectData(Map<String, Object> data) {
|
||||
}
|
||||
|
||||
public String getAccessTransformerClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package mods.betterfoliage.loader;
|
||||
|
||||
import mods.betterfoliage.common.util.DeobfNames;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
/** Transformer overriding the first line of RenderBlocks.renderBlockByRenderType()
|
||||
* with the following instruction:<br/><br/>
|
||||
* int l = mods.betterfoliage.BlockRenderTypeOverride.getRenderType(block);<br/><br/>
|
||||
*
|
||||
* @author octarine-noise
|
||||
*/
|
||||
public class BetterFoliageTransformer implements IClassTransformer {
|
||||
|
||||
Logger log = LogManager.getLogger("BetterFoliageCore");
|
||||
|
||||
public byte[] transform(String name, String transformedName, byte[] basicClass) {
|
||||
if (basicClass == null) return null;
|
||||
|
||||
if (transformedName.equals("net.minecraft.client.renderer.RenderBlocks")) {
|
||||
log.info(String.format("Found class %s", transformedName));
|
||||
ClassNode classNode = new ClassNode();
|
||||
ClassReader classReader = new ClassReader(basicClass);
|
||||
classReader.accept(classNode, 0);
|
||||
|
||||
for (MethodNode mn : classNode.methods) {
|
||||
boolean found = false;
|
||||
boolean obf = false;
|
||||
if (mn.desc.equals(DeobfNames.RB_RBBRT_SIG_MCP) && (mn.name.equals(DeobfNames.RB_RBBRT_NAME_MCP))) {
|
||||
found = true;
|
||||
} else if (mn.desc.equals(DeobfNames.RB_RBBRT_SIG_OBF) && (mn.name.equals(DeobfNames.RB_RBBRT_NAME_OBF))) {
|
||||
found = true;
|
||||
obf = true;
|
||||
}
|
||||
if (found) {
|
||||
log.info("Overriding RenderBlocks.renderBlockByRenderType()");
|
||||
int invokeNodeIdx = 0;
|
||||
for (int idx = 0; idx < mn.instructions.size(); idx++) if (mn.instructions.get(idx) instanceof MethodInsnNode) {
|
||||
invokeNodeIdx = idx;
|
||||
break;
|
||||
}
|
||||
mn.instructions.remove(mn.instructions.get(invokeNodeIdx));
|
||||
MethodInsnNode replacement = new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/BlockRenderTypeOverride", "getRenderType", obf ? DeobfNames.BRTO_GRT_SIG_OBF : DeobfNames.BRTO_GRT_SIG_MCP);
|
||||
mn.instructions.insertBefore(mn.instructions.get(invokeNodeIdx), replacement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ClassWriter writer = new ClassWriter(0);
|
||||
classNode.accept(writer);
|
||||
return writer.toByteArray();
|
||||
}
|
||||
return basicClass;
|
||||
}
|
||||
}
|
||||
13
src/main/resources/assets/betterfoliage/lang/en_US.lang
Normal file
@@ -0,0 +1,13 @@
|
||||
key.betterfoliage.gui=Open Settings
|
||||
|
||||
message.betterfoliage.optionOn=ON
|
||||
message.betterfoliage.optionOff=OFF
|
||||
|
||||
message.betterfoliage.close=Close
|
||||
message.betterfoliage.betterLeaves=Better Leaves: %s
|
||||
message.betterfoliage.betterGrass=Better Grass: %s
|
||||
message.betterfoliage.size=Size
|
||||
message.betterfoliage.hOffset=H.Offset
|
||||
message.betterfoliage.vOffset=V.Offset
|
||||
message.betterfoliage.minHeight=Min.Height
|
||||
message.betterfoliage.maxHeight=Max.Height
|
||||
|
After Width: | Height: | Size: 204 B |
|
After Width: | Height: | Size: 285 B |
|
After Width: | Height: | Size: 305 B |
|
After Width: | Height: | Size: 176 B |
|
After Width: | Height: | Size: 345 B |
|
After Width: | Height: | Size: 219 B |
|
After Width: | Height: | Size: 139 B |
8
src/main/resources/mcmod.info
Normal file
@@ -0,0 +1,8 @@
|
||||
[{
|
||||
"modid": "BetterFoliage",
|
||||
"name": "Better Foliage",
|
||||
"version": "$version",
|
||||
"mcversion": "$mcversion",
|
||||
"description": "Leafier leaves and grassier grass",
|
||||
"credits": "Made by octarine-noise"
|
||||
}]
|
||||