mirror of
https://github.com/GTNewHorizons/CodeChickenCore.git
synced 2026-11-11 07:47:47 +00:00
Initial 1.7 commit
This commit is contained in:
1 parent
34154fc011
commit
ca675b5f31
72 files changed
+2967
-3335
No files matched your search
+104
-142
@@ -23,45 +23,42 @@ import com.google.common.collect.Multimap;
|
||||
import codechicken.lib.asm.InstructionComparator.InsnListSection;
|
||||
|
||||
public class ASMHelper
|
||||
{
|
||||
{
|
||||
public static class CodeBlock
|
||||
{
|
||||
public Label start = new Label();
|
||||
public Label end = new Label();
|
||||
}
|
||||
|
||||
|
||||
public static class ForBlock extends CodeBlock
|
||||
{
|
||||
public Label cmp = new Label();
|
||||
public Label inc = new Label();
|
||||
public Label body = new Label();
|
||||
}
|
||||
|
||||
|
||||
public static abstract class MethodAltercator
|
||||
{
|
||||
public final ObfMapping method;
|
||||
|
||||
public MethodAltercator(ObfMapping method)
|
||||
{
|
||||
this.method = method;
|
||||
|
||||
public MethodAltercator(ObfMapping method) {
|
||||
this.method = method.toClassloading();
|
||||
}
|
||||
|
||||
|
||||
public abstract void alter(MethodNode mv);
|
||||
}
|
||||
|
||||
|
||||
public static abstract class MethodWriter
|
||||
{
|
||||
public final int access;
|
||||
public final ObfMapping method;
|
||||
public final String[] exceptions;
|
||||
|
||||
public MethodWriter(int access, ObfMapping method)
|
||||
{
|
||||
public MethodWriter(int access, ObfMapping method) {
|
||||
this(access, method, null);
|
||||
}
|
||||
|
||||
public MethodWriter(int access, ObfMapping method, String[] exceptions)
|
||||
{
|
||||
|
||||
public MethodWriter(int access, ObfMapping method, String[] exceptions) {
|
||||
this.access = access;
|
||||
this.method = method;
|
||||
this.exceptions = exceptions;
|
||||
@@ -69,69 +66,60 @@ public class ASMHelper
|
||||
|
||||
public abstract void write(MethodNode mv);
|
||||
}
|
||||
|
||||
|
||||
public static class MethodInjector
|
||||
{
|
||||
public final ObfMapping method;
|
||||
public final InsnList needle;
|
||||
public final InsnList injection;
|
||||
public final boolean before;
|
||||
|
||||
public MethodInjector(ObfMapping method, InsnList needle, InsnList injection, boolean before)
|
||||
{
|
||||
|
||||
public MethodInjector(ObfMapping method, InsnList needle, InsnList injection, boolean before) {
|
||||
this.method = method;
|
||||
this.needle = needle;
|
||||
this.injection = injection;
|
||||
this.before = before;
|
||||
}
|
||||
}
|
||||
|
||||
public static MethodNode findMethod(ObfMapping methodmap, ClassNode cnode)
|
||||
{
|
||||
for(MethodNode mnode : cnode.methods)
|
||||
if(methodmap.matches(mnode))
|
||||
|
||||
public static MethodNode findMethod(ObfMapping methodmap, ClassNode cnode) {
|
||||
for (MethodNode mnode : cnode.methods)
|
||||
if (methodmap.matches(mnode))
|
||||
return mnode;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static FieldNode findField(ObfMapping fieldmap, ClassNode cnode)
|
||||
{
|
||||
for(FieldNode fnode : cnode.fields)
|
||||
if(fieldmap.matches(fnode))
|
||||
public static FieldNode findField(ObfMapping fieldmap, ClassNode cnode) {
|
||||
for (FieldNode fnode : cnode.fields)
|
||||
if (fieldmap.matches(fnode))
|
||||
return fnode;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ClassNode createClassNode(byte[] bytes)
|
||||
{
|
||||
public static ClassNode createClassNode(byte[] bytes) {
|
||||
return createClassNode(bytes, 0);
|
||||
}
|
||||
|
||||
public static ClassNode createClassNode(byte[] bytes, int flags)
|
||||
{
|
||||
|
||||
public static ClassNode createClassNode(byte[] bytes, int flags) {
|
||||
ClassNode cnode = new ClassNode();
|
||||
ClassReader reader = new ClassReader(bytes);
|
||||
reader.accept(cnode, flags);
|
||||
return cnode;
|
||||
}
|
||||
|
||||
public static byte[] createBytes(ClassNode cnode, int flags)
|
||||
{
|
||||
public static byte[] createBytes(ClassNode cnode, int flags) {
|
||||
ClassWriter cw = new CC_ClassWriter(flags);
|
||||
cnode.accept(cw);
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] writeMethods(String name, byte[] bytes, Multimap<String, MethodWriter> writers)
|
||||
{
|
||||
if(writers.containsKey(name))
|
||||
{
|
||||
|
||||
public static byte[] writeMethods(String name, byte[] bytes, Multimap<String, MethodWriter> writers) {
|
||||
if (writers.containsKey(name)) {
|
||||
ClassNode cnode = createClassNode(bytes);
|
||||
|
||||
for(MethodWriter mw : writers.get(name))
|
||||
{
|
||||
|
||||
for (MethodWriter mw : writers.get(name)) {
|
||||
MethodNode mv = findMethod(mw.method, cnode);
|
||||
if(mv == null)
|
||||
if (mv == null)
|
||||
mv = (MethodNode) cnode.visitMethod(mw.access, mw.method.s_name, mw.method.s_desc, null, mw.exceptions);
|
||||
|
||||
mv.access = mw.access;
|
||||
@@ -143,41 +131,33 @@ public class ASMHelper
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static byte[] injectMethods(String name, byte[] bytes, Multimap<String, MethodInjector> injectors)
|
||||
{
|
||||
if(injectors.containsKey(name))
|
||||
{
|
||||
|
||||
public static byte[] injectMethods(String name, byte[] bytes, Multimap<String, MethodInjector> injectors) {
|
||||
if (injectors.containsKey(name)) {
|
||||
ClassNode cnode = createClassNode(bytes);
|
||||
|
||||
for(MethodInjector injector : injectors.get(name))
|
||||
{
|
||||
|
||||
for (MethodInjector injector : injectors.get(name)) {
|
||||
MethodNode method = findMethod(injector.method, cnode);
|
||||
if(method == null)
|
||||
throw new RuntimeException("Method not found: "+injector.method);
|
||||
if (method == null)
|
||||
throw new RuntimeException("Method not found: " + injector.method);
|
||||
System.out.println("Injecting into " + injector.method + "\n" + printInsnList(injector.injection));
|
||||
|
||||
|
||||
List<AbstractInsnNode> callNodes;
|
||||
if(injector.before)
|
||||
if (injector.before)
|
||||
callNodes = InstructionComparator.insnListFindStart(method.instructions, injector.needle);
|
||||
else
|
||||
callNodes = InstructionComparator.insnListFindEnd(method.instructions, injector.needle);
|
||||
|
||||
if(callNodes.size() == 0)
|
||||
{
|
||||
throw new RuntimeException("Needle not found in Haystack: " + injector.method+"\n" + printInsnList(injector.needle));
|
||||
|
||||
if (callNodes.size() == 0) {
|
||||
throw new RuntimeException("Needle not found in Haystack: " + injector.method + "\n" + printInsnList(injector.needle));
|
||||
}
|
||||
|
||||
for(AbstractInsnNode node : callNodes)
|
||||
{
|
||||
if(injector.before)
|
||||
{
|
||||
System.out.println("Injected before: "+printInsn(node));
|
||||
|
||||
for (AbstractInsnNode node : callNodes) {
|
||||
if (injector.before) {
|
||||
System.out.println("Injected before: " + printInsn(node));
|
||||
method.instructions.insertBefore(node, cloneInsnList(injector.injection));
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("Injected after: "+printInsn(node));
|
||||
} else {
|
||||
System.out.println("Injected after: " + printInsn(node));
|
||||
method.instructions.insert(node, cloneInsnList(injector.injection));
|
||||
}
|
||||
}
|
||||
@@ -187,144 +167,126 @@ public class ASMHelper
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static String printInsnList(InsnList list)
|
||||
{
|
||||
InsnListPrinter p = new InsnListPrinter();
|
||||
|
||||
public static String printInsnList(InsnList list) {
|
||||
InsnListPrinter p = new InsnListPrinter();
|
||||
p.visitInsnList(list);
|
||||
return p.textString();
|
||||
}
|
||||
|
||||
public static String printInsn(AbstractInsnNode insn)
|
||||
{
|
||||
|
||||
public static String printInsn(AbstractInsnNode insn) {
|
||||
InsnListPrinter p = new InsnListPrinter();
|
||||
p.visitInsn(insn);
|
||||
return p.textString();
|
||||
}
|
||||
|
||||
public static Map<LabelNode, LabelNode> cloneLabels(InsnList insns)
|
||||
{
|
||||
|
||||
public static Map<LabelNode, LabelNode> cloneLabels(InsnList insns) {
|
||||
HashMap<LabelNode, LabelNode> labelMap = new HashMap<LabelNode, LabelNode>();
|
||||
for(AbstractInsnNode insn = insns.getFirst(); insn != null; insn = insn.getNext())
|
||||
if(insn.getType() == 8)
|
||||
for (AbstractInsnNode insn = insns.getFirst(); insn != null; insn = insn.getNext())
|
||||
if (insn.getType() == 8)
|
||||
labelMap.put((LabelNode) insn, new LabelNode());
|
||||
return labelMap;
|
||||
}
|
||||
|
||||
public static InsnList cloneInsnList(InsnList insns)
|
||||
{
|
||||
|
||||
public static InsnList cloneInsnList(InsnList insns) {
|
||||
return cloneInsnList(cloneLabels(insns), insns);
|
||||
}
|
||||
|
||||
public static InsnList cloneInsnList(Map<LabelNode, LabelNode> labelMap, InsnList insns)
|
||||
{
|
||||
|
||||
public static InsnList cloneInsnList(Map<LabelNode, LabelNode> labelMap, InsnList insns) {
|
||||
InsnList clone = new InsnList();
|
||||
for(AbstractInsnNode insn = insns.getFirst(); insn != null; insn = insn.getNext())
|
||||
for (AbstractInsnNode insn = insns.getFirst(); insn != null; insn = insn.getNext())
|
||||
clone.add(insn.clone(labelMap));
|
||||
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public static List<TryCatchBlockNode> cloneTryCatchBlocks(Map<LabelNode, LabelNode> labelMap, List<TryCatchBlockNode> tcblocks)
|
||||
{
|
||||
|
||||
public static List<TryCatchBlockNode> cloneTryCatchBlocks(Map<LabelNode, LabelNode> labelMap, List<TryCatchBlockNode> tcblocks) {
|
||||
ArrayList<TryCatchBlockNode> clone = new ArrayList<TryCatchBlockNode>();
|
||||
for(TryCatchBlockNode node : tcblocks)
|
||||
for (TryCatchBlockNode node : tcblocks)
|
||||
clone.add(new TryCatchBlockNode(
|
||||
labelMap.get(node.start),
|
||||
labelMap.get(node.end),
|
||||
labelMap.get(node.handler),
|
||||
labelMap.get(node.start),
|
||||
labelMap.get(node.end),
|
||||
labelMap.get(node.handler),
|
||||
node.type));
|
||||
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public static List<LocalVariableNode> cloneLocals(Map<LabelNode, LabelNode> labelMap, List<LocalVariableNode> locals)
|
||||
{
|
||||
|
||||
public static List<LocalVariableNode> cloneLocals(Map<LabelNode, LabelNode> labelMap, List<LocalVariableNode> locals) {
|
||||
ArrayList<LocalVariableNode> clone = new ArrayList<LocalVariableNode>();
|
||||
for(LocalVariableNode node : locals)
|
||||
for (LocalVariableNode node : locals)
|
||||
clone.add(new LocalVariableNode(
|
||||
node.name, node.desc, node.signature,
|
||||
labelMap.get(node.start),
|
||||
labelMap.get(node.end),
|
||||
node.name, node.desc, node.signature,
|
||||
labelMap.get(node.start),
|
||||
labelMap.get(node.end),
|
||||
node.index));
|
||||
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public static void copy(MethodNode src, MethodNode dst)
|
||||
{
|
||||
|
||||
public static void copy(MethodNode src, MethodNode dst) {
|
||||
Map<LabelNode, LabelNode> labelMap = cloneLabels(src.instructions);
|
||||
dst.instructions = cloneInsnList(labelMap, src.instructions);
|
||||
dst.tryCatchBlocks = cloneTryCatchBlocks(labelMap, src.tryCatchBlocks);
|
||||
if(src.localVariables != null)
|
||||
if (src.localVariables != null)
|
||||
dst.localVariables = cloneLocals(labelMap, src.localVariables);
|
||||
dst.visibleAnnotations = src.visibleAnnotations;
|
||||
dst.invisibleAnnotations = src.invisibleAnnotations;
|
||||
dst.visitMaxs(src.maxStack, src.maxLocals);
|
||||
}
|
||||
|
||||
public static byte[] alterMethods(String name, byte[] bytes, HashMultimap<String, MethodAltercator> altercators)
|
||||
{
|
||||
if(altercators.containsKey(name))
|
||||
{
|
||||
public static byte[] alterMethods(String name, byte[] bytes, HashMultimap<String, MethodAltercator> altercators) {
|
||||
if (altercators.containsKey(name)) {
|
||||
ClassNode cnode = createClassNode(bytes);
|
||||
|
||||
for(MethodAltercator injector : altercators.get(name))
|
||||
{
|
||||
|
||||
for (MethodAltercator injector : altercators.get(name)) {
|
||||
MethodNode method = findMethod(injector.method, cnode);
|
||||
if(method == null)
|
||||
throw new RuntimeException("Method not found: "+injector.method);
|
||||
|
||||
if (method == null)
|
||||
throw new RuntimeException("Method not found: " + injector.method);
|
||||
|
||||
injector.alter(method);
|
||||
}
|
||||
|
||||
|
||||
bytes = createBytes(cnode, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
public static String printInsnList(InsnListSection subsection)
|
||||
{
|
||||
InsnListPrinter p = new InsnListPrinter();
|
||||
|
||||
public static String printInsnList(InsnListSection subsection) {
|
||||
InsnListPrinter p = new InsnListPrinter();
|
||||
p.visitInsnList(subsection);
|
||||
return p.textString();
|
||||
}
|
||||
|
||||
public static int getLocal(List<LocalVariableNode> list, String name)
|
||||
{
|
||||
public static int getLocal(List<LocalVariableNode> list, String name) {
|
||||
int found = -1;
|
||||
for(LocalVariableNode node : list)
|
||||
{
|
||||
if(node.name.equals(name))
|
||||
{
|
||||
if(found >= 0)
|
||||
throw new RuntimeException("Duplicate local variable: "+name+" not coded to handle this scenario.");
|
||||
|
||||
for (LocalVariableNode node : list) {
|
||||
if (node.name.equals(name)) {
|
||||
if (found >= 0)
|
||||
throw new RuntimeException("Duplicate local variable: " + name + " not coded to handle this scenario.");
|
||||
|
||||
found = node.index;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
public static void replaceMethodCode(MethodNode original, MethodNode replacement)
|
||||
{
|
||||
public static void replaceMethodCode(MethodNode original, MethodNode replacement) {
|
||||
original.instructions.clear();
|
||||
if(original.localVariables != null)
|
||||
if (original.localVariables != null)
|
||||
original.localVariables.clear();
|
||||
if(original.tryCatchBlocks != null)
|
||||
if (original.tryCatchBlocks != null)
|
||||
original.tryCatchBlocks.clear();
|
||||
replacement.accept(original);
|
||||
}
|
||||
|
||||
public static void removeBlock(InsnList insns, InsnListSection block)
|
||||
{
|
||||
public static void removeBlock(InsnList insns, InsnListSection block) {
|
||||
AbstractInsnNode insn = block.first;
|
||||
while(true)
|
||||
{
|
||||
while (true) {
|
||||
AbstractInsnNode next = insn.getNext();
|
||||
insns.remove(insn);
|
||||
if(insn == block.last)
|
||||
if (insn == block.last)
|
||||
break;
|
||||
insn = next;
|
||||
}
|
||||
|
||||
@@ -301,14 +301,14 @@ public class ASMReader
|
||||
insn = new VarInsnNode(opcode, Integer.parseInt(split[1]));
|
||||
break;
|
||||
case TYPE_INSN:
|
||||
insn = new ObfMapping(split[1]).toInsn(opcode);
|
||||
insn = new ObfMapping(split[1]).toClassloading().toInsn(opcode);
|
||||
break;
|
||||
case FIELD_INSN:
|
||||
case METHOD_INSN:
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(int i = 1; i < split.length; i++)
|
||||
sb.append(split[i]);
|
||||
insn = ObfMapping.fromDesc(sb.toString()).toInsn(opcode);
|
||||
insn = ObfMapping.fromDesc(sb.toString()).toClassloading().toInsn(opcode);
|
||||
break;
|
||||
case INVOKE_DYNAMIC_INSN:
|
||||
throw new Exception("Found INVOKEDYNAMIC while reading");
|
||||
|
||||
+143
-123
@@ -1,8 +1,12 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
@@ -19,219 +23,235 @@ import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
|
||||
|
||||
public class ObfMapping
|
||||
{
|
||||
/**
|
||||
* CCC will deal with this.
|
||||
*/
|
||||
public static Remapper runtimeMapper = FMLDeobfuscatingRemapper.INSTANCE;
|
||||
public static Remapper mcpMapper = null;
|
||||
|
||||
public static final boolean obfuscated;
|
||||
|
||||
static
|
||||
public static class ObfRemapper extends Remapper
|
||||
{
|
||||
boolean obf = true;
|
||||
try
|
||||
{
|
||||
obf = ((LaunchClassLoader)ObfMapping.class.getClassLoader()).getClassBytes("net.minecraft.world.World") == null;
|
||||
private HashMap<String, String> fields = new HashMap<String, String>();
|
||||
private HashMap<String, String> funcs = new HashMap<String, String>();
|
||||
|
||||
public ObfRemapper() {
|
||||
try {
|
||||
Field rawFieldMapsField = FMLDeobfuscatingRemapper.class.getDeclaredField("rawFieldMaps");
|
||||
Field rawMethodMapsField = FMLDeobfuscatingRemapper.class.getDeclaredField("rawMethodMaps");
|
||||
rawFieldMapsField.setAccessible(true);
|
||||
rawMethodMapsField.setAccessible(true);
|
||||
Map<String, Map<String, String>> rawFieldMaps = (Map<String, Map<String, String>>) rawFieldMapsField.get(FMLDeobfuscatingRemapper.INSTANCE);
|
||||
Map<String, Map<String, String>> rawMethodMaps = (Map<String, Map<String, String>>) rawMethodMapsField.get(FMLDeobfuscatingRemapper.INSTANCE);
|
||||
|
||||
if(rawFieldMaps == null)
|
||||
throw new IllegalStateException("codechicken.lib.asm.ObfMapping loaded too early. Make sure all references are in or after the asm transformer load stage");
|
||||
|
||||
for(Map<String, String> map : rawFieldMaps.values())
|
||||
for(Entry<String, String> entry : map.entrySet())
|
||||
if(entry.getValue().startsWith("field"))
|
||||
fields.put(entry.getValue(), entry.getKey().substring(0, entry.getKey().indexOf(':')));
|
||||
for(Map<String, String> map : rawMethodMaps.values())
|
||||
for(Entry<String, String> entry : map.entrySet())
|
||||
if(entry.getValue().startsWith("func"))
|
||||
funcs.put(entry.getValue(), entry.getKey().substring(0, entry.getKey().indexOf('(')));
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
catch(IOException iox) {}
|
||||
|
||||
@Override
|
||||
public String mapMethodName(String owner, String name, String desc) {
|
||||
String s = funcs.get(name);
|
||||
return s == null ? name : s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapFieldName(String owner, String name, String desc) {
|
||||
String s = fields.get(name);
|
||||
return s == null ? name : s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String map(String typeName) {
|
||||
return FMLDeobfuscatingRemapper.INSTANCE.unmap(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
public static ObfRemapper obfMapper = new ObfRemapper();
|
||||
public static Remapper mcpMapper = null;
|
||||
|
||||
public static final boolean obfuscated;
|
||||
|
||||
static {
|
||||
boolean obf = true;
|
||||
try {
|
||||
obf = Launch.classLoader.getClassBytes("net.minecraft.world.World") == null;
|
||||
} catch (IOException ignored) {}
|
||||
obfuscated = obf;
|
||||
}
|
||||
|
||||
|
||||
public String s_owner;
|
||||
public String s_name;
|
||||
public String s_desc;
|
||||
|
||||
public boolean runtime;
|
||||
|
||||
public ObfMapping(String owner)
|
||||
{
|
||||
|
||||
public ObfMapping(String owner) {
|
||||
this(owner, "", "");
|
||||
}
|
||||
|
||||
public ObfMapping(String owner, String name, String desc)
|
||||
{
|
||||
|
||||
public ObfMapping(String owner, String name, String desc) {
|
||||
this.s_owner = owner;
|
||||
this.s_name = name;
|
||||
this.s_desc = desc;
|
||||
|
||||
if(s_owner.contains("."))
|
||||
if (s_owner.contains("."))
|
||||
throw new IllegalArgumentException(s_owner);
|
||||
|
||||
if(mcpMapper != null)
|
||||
map(mcpMapper);
|
||||
}
|
||||
|
||||
public ObfMapping(ObfMapping descmap, String subclass)
|
||||
{
|
||||
|
||||
public ObfMapping(ObfMapping descmap, String subclass) {
|
||||
this(subclass, descmap.s_name, descmap.s_desc);
|
||||
}
|
||||
|
||||
public static ObfMapping fromDesc(String s)
|
||||
{
|
||||
public static ObfMapping fromDesc(String s) {
|
||||
int lastDot = s.lastIndexOf('.');
|
||||
if(lastDot < 0)
|
||||
if (lastDot < 0)
|
||||
return new ObfMapping(s, "", "");
|
||||
int sep = s.indexOf('(');//methods
|
||||
int sep_end = sep;
|
||||
if(sep < 0) {
|
||||
if (sep < 0) {
|
||||
sep = s.indexOf(' ');//some stuffs
|
||||
sep_end = sep+1;
|
||||
sep_end = sep + 1;
|
||||
}
|
||||
if(sep < 0) {
|
||||
if (sep < 0) {
|
||||
sep = s.indexOf(':');//fields
|
||||
sep_end = sep+1;
|
||||
sep_end = sep + 1;
|
||||
}
|
||||
if(sep < 0)
|
||||
if (sep < 0)
|
||||
return new ObfMapping(s.substring(0, lastDot), s.substring(lastDot + 1), "");
|
||||
|
||||
return new ObfMapping(s.substring(0, lastDot), s.substring(lastDot+1, sep), s.substring(sep_end));
|
||||
return new ObfMapping(s.substring(0, lastDot), s.substring(lastDot + 1, sep), s.substring(sep_end));
|
||||
}
|
||||
|
||||
public ObfMapping subclass(String subclass)
|
||||
{
|
||||
|
||||
public ObfMapping subclass(String subclass) {
|
||||
return new ObfMapping(this, subclass);
|
||||
}
|
||||
|
||||
public boolean matches(MethodNode node)
|
||||
{
|
||||
public boolean matches(MethodNode node) {
|
||||
return s_name.equals(node.name) && s_desc.equals(node.desc);
|
||||
}
|
||||
|
||||
public boolean matches(MethodInsnNode node)
|
||||
{
|
||||
|
||||
public boolean matches(MethodInsnNode node) {
|
||||
return s_owner.equals(node.owner) && s_name.equals(node.name) && s_desc.equals(node.desc);
|
||||
}
|
||||
|
||||
public AbstractInsnNode toInsn(int opcode)
|
||||
{
|
||||
if(isClass())
|
||||
public AbstractInsnNode toInsn(int opcode) {
|
||||
if (isClass())
|
||||
return new TypeInsnNode(opcode, s_owner);
|
||||
else if(isMethod())
|
||||
else if (isMethod())
|
||||
return new MethodInsnNode(opcode, s_owner, s_name, s_desc);
|
||||
else
|
||||
return new FieldInsnNode(opcode, s_owner, s_name, s_desc);
|
||||
}
|
||||
|
||||
public void visitTypeInsn(MethodVisitor mv, int opcode)
|
||||
{
|
||||
|
||||
public void visitTypeInsn(MethodVisitor mv, int opcode) {
|
||||
mv.visitTypeInsn(opcode, s_owner);
|
||||
}
|
||||
|
||||
public void visitMethodInsn(MethodVisitor mv, int opcode)
|
||||
{
|
||||
|
||||
public void visitMethodInsn(MethodVisitor mv, int opcode) {
|
||||
mv.visitMethodInsn(opcode, s_owner, s_name, s_desc);
|
||||
}
|
||||
|
||||
public void visitFieldInsn(MethodVisitor mv, int opcode)
|
||||
{
|
||||
public void visitFieldInsn(MethodVisitor mv, int opcode) {
|
||||
mv.visitFieldInsn(opcode, s_owner, s_name, s_desc);
|
||||
}
|
||||
|
||||
public boolean isClass(String name)
|
||||
{
|
||||
public boolean isClass(String name) {
|
||||
return name.replace('.', '/').equals(s_owner);
|
||||
}
|
||||
|
||||
public boolean matches(String name, String desc)
|
||||
{
|
||||
public boolean matches(String name, String desc) {
|
||||
return s_name.equals(name) && s_desc.equals(desc);
|
||||
}
|
||||
|
||||
public boolean matches(FieldNode node)
|
||||
{
|
||||
public boolean matches(FieldNode node) {
|
||||
return s_name.equals(node.name) && s_desc.equals(node.desc);
|
||||
}
|
||||
|
||||
public boolean matches(FieldInsnNode node)
|
||||
{
|
||||
|
||||
public boolean matches(FieldInsnNode node) {
|
||||
return s_owner.equals(node.owner) && s_name.equals(node.name) && s_desc.equals(node.desc);
|
||||
}
|
||||
|
||||
public String javaClass()
|
||||
{
|
||||
public String javaClass() {
|
||||
return s_owner.replace('/', '.');
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(!(obj instanceof ObfMapping))
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ObfMapping))
|
||||
return false;
|
||||
|
||||
ObfMapping desc = (ObfMapping)obj;
|
||||
|
||||
ObfMapping desc = (ObfMapping) obj;
|
||||
return s_owner.equals(desc.s_owner) && s_name.equals(desc.s_name) && s_desc.equals(desc.s_desc);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(s_desc, s_name, s_owner);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if(s_name.length() == 0)
|
||||
return "["+s_owner+"]";
|
||||
if(s_desc.length() == 0)
|
||||
return "["+s_owner+"."+s_name+"]";
|
||||
return "["+(isMethod() ? methodDesc() : fieldDesc())+"]";
|
||||
public String toString() {
|
||||
if (s_name.length() == 0)
|
||||
return "[" + s_owner + "]";
|
||||
if (s_desc.length() == 0)
|
||||
return "[" + s_owner + "." + s_name + "]";
|
||||
return "[" + (isMethod() ? methodDesc() : fieldDesc()) + "]";
|
||||
}
|
||||
|
||||
public String methodDesc()
|
||||
{
|
||||
return s_owner+"."+s_name+s_desc;
|
||||
public String methodDesc() {
|
||||
return s_owner + "." + s_name + s_desc;
|
||||
}
|
||||
|
||||
public String fieldDesc()
|
||||
{
|
||||
return s_owner+"."+s_name+":"+s_desc;
|
||||
public String fieldDesc() {
|
||||
return s_owner + "." + s_name + ":" + s_desc;
|
||||
}
|
||||
|
||||
public boolean isClass()
|
||||
{
|
||||
|
||||
public boolean isClass() {
|
||||
return s_name.length() == 0;
|
||||
}
|
||||
|
||||
public boolean isMethod()
|
||||
{
|
||||
|
||||
public boolean isMethod() {
|
||||
return s_desc.contains("(");
|
||||
}
|
||||
|
||||
public boolean isField()
|
||||
{
|
||||
|
||||
public boolean isField() {
|
||||
return !isClass() && !isMethod();
|
||||
}
|
||||
|
||||
public ObfMapping map(Remapper mapper)
|
||||
{
|
||||
if(isMethod())
|
||||
|
||||
public ObfMapping map(Remapper mapper) {
|
||||
if(mapper == null)
|
||||
return this;
|
||||
|
||||
if (isMethod())
|
||||
s_name = mapper.mapMethodName(s_owner, s_name, s_desc);
|
||||
else if(isField())
|
||||
else if (isField())
|
||||
s_name = mapper.mapFieldName(s_owner, s_name, s_desc);
|
||||
|
||||
|
||||
s_owner = mapper.mapType(s_owner);
|
||||
|
||||
if(isMethod())
|
||||
|
||||
if (isMethod())
|
||||
s_desc = mapper.mapMethodDesc(s_desc);
|
||||
else if(s_desc.length() > 0)
|
||||
else if (s_desc.length() > 0)
|
||||
s_desc = mapper.mapDesc(s_desc);
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfMapping toRuntime()
|
||||
{
|
||||
if(!runtime)
|
||||
map(runtimeMapper);
|
||||
|
||||
runtime = true;
|
||||
|
||||
public ObfMapping toRuntime() {
|
||||
map(mcpMapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfMapping copy()
|
||||
{
|
||||
|
||||
public ObfMapping toClassloading() {
|
||||
map(obfuscated ? obfMapper : mcpMapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfMapping copy() {
|
||||
return new ObfMapping(s_owner, s_name, s_desc);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package codechicken.lib.colour;
|
||||
|
||||
import codechicken.lib.util.Copyable;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.math.MathHelper;
|
||||
@@ -7,7 +8,7 @@ import codechicken.lib.math.MathHelper;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public abstract class Colour
|
||||
public abstract class Colour implements Copyable<Colour>
|
||||
{
|
||||
public byte r;
|
||||
public byte g;
|
||||
|
||||
@@ -1,40 +1,49 @@
|
||||
package codechicken.lib.colour;
|
||||
|
||||
public class ColourRGBA extends Colour
|
||||
{
|
||||
public ColourRGBA(int colour)
|
||||
{
|
||||
public class ColourRGBA extends Colour {
|
||||
public ColourRGBA(int colour) {
|
||||
super((colour >> 24) & 0xFF, (colour >> 16) & 0xFF, (colour >> 8) & 0xFF, colour & 0xFF);
|
||||
}
|
||||
|
||||
public ColourRGBA(double r, double g, double b, double a)
|
||||
{
|
||||
public ColourRGBA(double r, double g, double b, double a) {
|
||||
super((int) (255 * r), (int) (255 * g), (int) (255 * b), (int) (255 * a));
|
||||
}
|
||||
|
||||
public ColourRGBA(int r, int g, int b, int a)
|
||||
{
|
||||
public ColourRGBA(int r, int g, int b, int a) {
|
||||
super(r, g, b, a);
|
||||
}
|
||||
|
||||
public ColourRGBA(ColourRGBA colour)
|
||||
{
|
||||
public ColourRGBA(ColourRGBA colour) {
|
||||
super(colour);
|
||||
}
|
||||
|
||||
public int pack()
|
||||
{
|
||||
public int pack() {
|
||||
return pack(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Colour copy()
|
||||
{
|
||||
public Colour copy() {
|
||||
return new ColourRGBA(this);
|
||||
}
|
||||
|
||||
public static int pack(Colour colour)
|
||||
{
|
||||
return (colour.r&0xFF) << 24 | (colour.g&0xFF) << 16 | (colour.b&0xFF) << 8 | (colour.a&0xFF);
|
||||
public static int pack(Colour colour) {
|
||||
return (colour.r & 0xFF) << 24 | (colour.g & 0xFF) << 16 | (colour.b & 0xFF) << 8 | (colour.a & 0xFF);
|
||||
}
|
||||
|
||||
public static int multiply(int c1, int c2) {
|
||||
if(c1 == -1) return c2;
|
||||
if(c2 == -1) return c1;
|
||||
int r = (((c1 >>> 24) * (c2 >>> 24)) & 0xFF00) << 16;
|
||||
int g = (((c1 >> 16 & 0xFF) * (c2 >> 16 & 0xFF)) & 0xFF00) << 8;
|
||||
int b = ((c1 >> 8 & 0xFF) * (c2 >> 8 & 0xFF)) & 0xFF00;
|
||||
int a = ((c1 & 0xFF) * (c2 & 0xFF)) >> 8;
|
||||
return r|g|b|a;
|
||||
}
|
||||
|
||||
public static int multiplyC(int c, float f) {
|
||||
int r = (int) ((c >>> 24) * f);
|
||||
int g = (int) ((c >> 16 & 0xFF) * f);
|
||||
int b = (int) ((c >> 8 & 0xFF) * f);
|
||||
return r<<24 | g<<16 | b<<8 | c&0xFF;
|
||||
}
|
||||
}
|
||||
@@ -8,146 +8,118 @@ import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
public class ConfigFile extends ConfigTagParent
|
||||
{
|
||||
public ConfigFile(File file)
|
||||
{
|
||||
if(!file.exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
public ConfigFile(File file) {
|
||||
try {
|
||||
if(!file.getParentFile().exists())
|
||||
file.getParentFile().mkdirs();
|
||||
if (!file.exists())
|
||||
file.createNewFile();
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.file = file;
|
||||
newlinemode = 2;
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
private void loadConfig()
|
||||
{
|
||||
|
||||
private void loadConfig() {
|
||||
loading = true;
|
||||
BufferedReader reader;
|
||||
try
|
||||
{
|
||||
try {
|
||||
reader = new BufferedReader(new FileReader(file));
|
||||
|
||||
while(true)
|
||||
{
|
||||
|
||||
while (true) {
|
||||
reader.mark(2000);
|
||||
String line = reader.readLine();
|
||||
if(line != null && line.startsWith("#"))
|
||||
{
|
||||
if(comment == null || comment.equals(""))
|
||||
if (line != null && line.startsWith("#")) {
|
||||
if (comment == null || comment.equals(""))
|
||||
comment = line.substring(1);
|
||||
else
|
||||
comment = comment+"\n"+line.substring(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
comment = comment + "\n" + line.substring(1);
|
||||
} else {
|
||||
reader.reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
loadChildren(reader);
|
||||
reader.close();
|
||||
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ConfigFile setComment(String header)
|
||||
{
|
||||
public ConfigFile setComment(String header) {
|
||||
super.setComment(header);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ConfigFile setSortMode(int mode)
|
||||
{
|
||||
public ConfigFile setSortMode(int mode) {
|
||||
super.setSortMode(mode);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getNameQualifier()
|
||||
{
|
||||
public String getNameQualifier() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String readLine(BufferedReader reader) throws IOException
|
||||
{
|
||||
|
||||
public static String readLine(BufferedReader reader) throws IOException {
|
||||
String line = reader.readLine();
|
||||
if(line != null)
|
||||
if (line != null)
|
||||
return line.replace("\t", "");
|
||||
return line;
|
||||
}
|
||||
|
||||
public static String formatLine(String line)
|
||||
{
|
||||
|
||||
public static String formatLine(String line) {
|
||||
line = line.replace("\t", "");
|
||||
if(line.startsWith("#"))
|
||||
{
|
||||
if (line.startsWith("#")) {
|
||||
return line;
|
||||
}
|
||||
else if(line.contains("="))
|
||||
{
|
||||
line = line.substring(0, line.indexOf("=")).replace(" ", "")+line.substring(line.indexOf("="));
|
||||
} else if (line.contains("=")) {
|
||||
line = line.substring(0, line.indexOf("=")).replace(" ", "") + line.substring(line.indexOf("="));
|
||||
return line;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
line = line.replace(" ", "");
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeLine(PrintWriter writer, String line, int tabs)
|
||||
{
|
||||
for(int i = 0; i < tabs; i++)
|
||||
|
||||
public static void writeLine(PrintWriter writer, String line, int tabs) {
|
||||
for (int i = 0; i < tabs; i++)
|
||||
writer.print('\t');
|
||||
|
||||
|
||||
writer.println(line);
|
||||
}
|
||||
|
||||
public void saveConfig()
|
||||
{
|
||||
if(loading)
|
||||
|
||||
public void saveConfig() {
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
|
||||
PrintWriter writer;
|
||||
try
|
||||
{
|
||||
try {
|
||||
writer = new PrintWriter(file);
|
||||
}
|
||||
catch(FileNotFoundException e)
|
||||
{
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
writeComment(writer, 0);
|
||||
ConfigFile.writeLine(writer, "", 0);
|
||||
saveTagTree(writer, 0, "");
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
|
||||
public boolean isLoading()
|
||||
{
|
||||
|
||||
public boolean isLoading() {
|
||||
return loading;
|
||||
}
|
||||
|
||||
|
||||
public File file;
|
||||
private boolean loading;
|
||||
|
||||
|
||||
public static final byte[] lineend = new byte[]{0xD, 0xA};
|
||||
}
|
||||
@@ -12,11 +12,13 @@ public interface MCDataInput
|
||||
public short readShort();
|
||||
public int readUShort();
|
||||
public byte readByte();
|
||||
public int readUByte();
|
||||
public short readUByte();
|
||||
public double readDouble();
|
||||
public float readFloat();
|
||||
public boolean readBoolean();
|
||||
public char readChar();
|
||||
public int readVarShort();
|
||||
public int readVarInt();
|
||||
public byte[] readByteArray(int length);
|
||||
public String readString();
|
||||
public BlockCoord readCoord();
|
||||
|
||||
@@ -15,6 +15,8 @@ public interface MCDataOutput
|
||||
public MCDataOutput writeFloat(float f);
|
||||
public MCDataOutput writeBoolean(boolean b);
|
||||
public MCDataOutput writeChar(char c);
|
||||
public MCDataOutput writeVarInt(int i);
|
||||
public MCDataOutput writeVarShort(int s);
|
||||
public MCDataOutput writeByteArray(byte[] array);
|
||||
public MCDataOutput writeString(String s);
|
||||
public MCDataOutput writeCoord(int x, int y, int z);
|
||||
|
||||
@@ -3,6 +3,7 @@ package codechicken.lib.data;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompressedStreamTools;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
@@ -122,7 +123,31 @@ public class MCOutputStreamWrapper implements MCDataOutput
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MCDataOutput writeVarInt(int i) {
|
||||
while ((i & 0x80) != 0)
|
||||
{
|
||||
writeByte(i & 0x7F | 0x80);
|
||||
i >>>= 7;
|
||||
}
|
||||
|
||||
writeByte(i);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MCDataOutput writeVarShort(int s) {
|
||||
int low = s & 0x7FFF;
|
||||
int high = (s & 0x7F8000) >> 15;
|
||||
if (high != 0)
|
||||
low |= 0x8000;
|
||||
writeShort(low);
|
||||
if (high != 0)
|
||||
writeByte(high);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCOutputStreamWrapper writeByteArray(byte[] barray)
|
||||
{
|
||||
try
|
||||
@@ -174,16 +199,12 @@ public class MCOutputStreamWrapper implements MCDataOutput
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCOutputStreamWrapper writeItemStack(ItemStack stack, boolean large)
|
||||
{
|
||||
if (stack == null)
|
||||
{
|
||||
public MCOutputStreamWrapper writeItemStack(ItemStack stack, boolean large) {
|
||||
if (stack == null) {
|
||||
writeShort(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeShort(stack.itemID);
|
||||
if(large)
|
||||
} else {
|
||||
writeShort(Item.getIdFromItem(stack.getItem()));
|
||||
if (large)
|
||||
writeInt(stack.stackSize);
|
||||
else
|
||||
writeByte(stack.stackSize);
|
||||
|
||||
@@ -1,246 +0,0 @@
|
||||
package codechicken.lib.data;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagByte;
|
||||
import net.minecraft.nbt.NBTTagByteArray;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagDouble;
|
||||
import net.minecraft.nbt.NBTTagFloat;
|
||||
import net.minecraft.nbt.NBTTagInt;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.nbt.NBTTagLong;
|
||||
import net.minecraft.nbt.NBTTagShort;
|
||||
import net.minecraft.nbt.NBTTagString;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import codechicken.lib.vec.BlockCoord;
|
||||
|
||||
public class NBTDataWrapper implements MCDataInput, MCDataOutput
|
||||
{
|
||||
private NBTTagList readList;
|
||||
private int readTag = 0;
|
||||
private NBTTagList writeList;
|
||||
|
||||
public NBTDataWrapper(NBTTagList input)
|
||||
{
|
||||
readList = input;
|
||||
}
|
||||
|
||||
public NBTDataWrapper()
|
||||
{
|
||||
writeList = new NBTTagList();
|
||||
}
|
||||
|
||||
public NBTTagList toTag()
|
||||
{
|
||||
return writeList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeLong(long l)
|
||||
{
|
||||
writeList.appendTag(new NBTTagLong(null, l));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeInt(int i)
|
||||
{
|
||||
writeList.appendTag(new NBTTagInt(null, i));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeShort(int s)
|
||||
{
|
||||
writeList.appendTag(new NBTTagShort(null, (short) s));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeByte(int b)
|
||||
{
|
||||
writeList.appendTag(new NBTTagByte(null, (byte) b));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeDouble(double d)
|
||||
{
|
||||
writeList.appendTag(new NBTTagDouble(null, d));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeFloat(float f)
|
||||
{
|
||||
writeList.appendTag(new NBTTagFloat(null, f));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeBoolean(boolean b)
|
||||
{
|
||||
writeList.appendTag(new NBTTagByte(null, (byte) (b ? 1 : 0)));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeChar(char c)
|
||||
{
|
||||
writeList.appendTag(new NBTTagShort(null, (short)c));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeByteArray(byte[] array)
|
||||
{
|
||||
writeList.appendTag(new NBTTagByteArray(null, array));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeString(String s)
|
||||
{
|
||||
writeList.appendTag(new NBTTagString(null, s));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeCoord(int x, int y, int z)
|
||||
{
|
||||
writeInt(x);
|
||||
writeInt(y);
|
||||
writeInt(z);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeCoord(BlockCoord coord)
|
||||
{
|
||||
writeCoord(coord.x, coord.y, coord.z);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeNBTTagCompound(NBTTagCompound tag)
|
||||
{
|
||||
writeList.appendTag(tag);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeItemStack(ItemStack stack)
|
||||
{
|
||||
writeList.appendTag(stack.writeToNBT(new NBTTagCompound()));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTDataWrapper writeFluidStack(FluidStack liquid)
|
||||
{
|
||||
writeList.appendTag(liquid.writeToNBT(new NBTTagCompound()));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong()
|
||||
{
|
||||
return ((NBTTagLong)readTag()).data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readInt()
|
||||
{
|
||||
return ((NBTTagInt)readTag()).data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShort()
|
||||
{
|
||||
return ((NBTTagShort)readTag()).data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUShort()
|
||||
{
|
||||
return ((NBTTagShort)readTag()).data & 0xFFFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readByte()
|
||||
{
|
||||
return ((NBTTagByte)readTag()).data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUByte()
|
||||
{
|
||||
return ((NBTTagByte)readTag()).data & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readDouble()
|
||||
{
|
||||
return ((NBTTagDouble)readTag()).data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float readFloat()
|
||||
{
|
||||
return ((NBTTagFloat)readTag()).data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBoolean()
|
||||
{
|
||||
return ((NBTTagByte)readTag()).data != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char readChar()
|
||||
{
|
||||
return (char)((NBTTagShort)readTag()).data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] readByteArray(int length)
|
||||
{
|
||||
return ((NBTTagByteArray)readTag()).byteArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readString()
|
||||
{
|
||||
return ((NBTTagString)readTag()).data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockCoord readCoord()
|
||||
{
|
||||
return new BlockCoord(readInt(), readInt(), readInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTTagCompound readNBTTagCompound()
|
||||
{
|
||||
return (NBTTagCompound)readTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack readItemStack()
|
||||
{
|
||||
return ItemStack.loadItemStackFromNBT(readNBTTagCompound());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack readFluidStack()
|
||||
{
|
||||
return FluidStack.loadFluidStackFromNBT(readNBTTagCompound());
|
||||
}
|
||||
|
||||
private NBTBase readTag()
|
||||
{
|
||||
return readList.tagAt(readTag++);
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ public class Canvas9Seg
|
||||
public void draw(int x, int y, int w, int h) {
|
||||
CCRenderState.changeTexture(tex);
|
||||
CCRenderState.reset();
|
||||
CCRenderState.startDrawing(7);
|
||||
CCRenderState.startDrawing();
|
||||
|
||||
int[] sw = new int[]{x, x+seg_w[0], x+w-seg_w[2], x+w};
|
||||
int[] sh = new int[]{y, y+seg_h[0], y+h-seg_h[2], y+h};
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
package codechicken.lib.gui;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
|
||||
import codechicken.lib.math.MathHelper;
|
||||
import codechicken.lib.render.CCRenderState;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class GuiDraw
|
||||
{
|
||||
public static class GuiHook extends Gui
|
||||
{
|
||||
public void setZLevel(float f) {
|
||||
zLevel = f;
|
||||
}
|
||||
|
||||
public float getZLevel() {
|
||||
return zLevel;
|
||||
}
|
||||
|
||||
public void incZLevel(float f) {
|
||||
zLevel += f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawGradientRect(int par1, int par2, int par3, int par4, int par5, int par6) {
|
||||
super.drawGradientRect(par1, par2, par3, par4, par5, par6);
|
||||
}
|
||||
}
|
||||
|
||||
public static final GuiHook gui = new GuiHook();
|
||||
public static FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer;
|
||||
public static TextureManager renderEngine = Minecraft.getMinecraft().renderEngine;
|
||||
|
||||
public static void drawRect(int x, int y, int w, int h, int colour) {
|
||||
drawGradientRect(x, y, w, h, colour, colour);
|
||||
}
|
||||
|
||||
public static void drawGradientRect(int x, int y, int w, int h, int colour1, int colour2) {
|
||||
gui.drawGradientRect(x, y, x + w, y + h, colour1, colour2);
|
||||
}
|
||||
|
||||
public static void drawTexturedModalRect(int x, int y, int tx, int ty, int w, int h) {
|
||||
gui.drawTexturedModalRect(x, y, tx, ty, w, h);
|
||||
}
|
||||
|
||||
public static void drawString(String text, int x, int y, int colour, boolean shadow) {
|
||||
if (shadow)
|
||||
fontRenderer.drawStringWithShadow(text, x, y, colour);
|
||||
else
|
||||
fontRenderer.drawString(text, x, y, colour);
|
||||
}
|
||||
|
||||
public static void drawString(String text, int x, int y, int colour) {
|
||||
drawString(text, x, y, colour, true);
|
||||
}
|
||||
|
||||
public static void drawStringC(String text, int x, int y, int w, int h, int colour, boolean shadow) {
|
||||
drawString(text, x + (w - getStringWidth(text)) / 2, y + (h - 8) / 2, colour, shadow);
|
||||
}
|
||||
|
||||
public static void drawStringC(String text, int x, int y, int w, int h, int colour) {
|
||||
drawStringC(text, x, y, w, h, colour, true);
|
||||
}
|
||||
|
||||
public static void drawStringC(String text, int x, int y, int colour, boolean shadow) {
|
||||
drawString(text, x - getStringWidth(text) / 2, y, colour, shadow);
|
||||
}
|
||||
|
||||
public static void drawStringC(String text, int x, int y, int colour) {
|
||||
drawStringC(text, x, y, colour, true);
|
||||
}
|
||||
|
||||
public static void drawStringR(String text, int x, int y, int colour, boolean shadow) {
|
||||
drawString(text, x - getStringWidth(text), y, colour, shadow);
|
||||
}
|
||||
|
||||
public static void drawStringR(String text, int x, int y, int colour) {
|
||||
drawStringR(text, x, y, colour, true);
|
||||
}
|
||||
|
||||
|
||||
public static int getStringWidth(String s) {
|
||||
if (s == null || s.equals(""))
|
||||
return 0;
|
||||
return fontRenderer.getStringWidth(EnumChatFormatting.getTextWithoutFormattingCodes(s));
|
||||
}
|
||||
|
||||
public static Dimension displaySize() {
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
ScaledResolution res = new ScaledResolution(mc.gameSettings, mc.displayWidth, mc.displayHeight);
|
||||
return new Dimension(res.getScaledWidth(), res.getScaledHeight());
|
||||
}
|
||||
|
||||
public static Dimension displayRes() {
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
return new Dimension(mc.displayWidth, mc.displayHeight);
|
||||
}
|
||||
|
||||
public static Point getMousePosition() {
|
||||
Dimension size = displaySize();
|
||||
Dimension res = displayRes();
|
||||
return new Point(Mouse.getX() * size.width / res.width, size.height - Mouse.getY() * size.height / res.height - 1);
|
||||
}
|
||||
|
||||
public static void changeTexture(String s) {
|
||||
CCRenderState.changeTexture(s);
|
||||
}
|
||||
|
||||
public static void changeTexture(ResourceLocation r) {
|
||||
CCRenderState.changeTexture(r);
|
||||
}
|
||||
|
||||
public static void drawTip(int x, int y, String text) {
|
||||
drawMultilineTip(x, y, Arrays.asList(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a string in the tooltip list with TOOLTIP_LINESPACE to have a small gap between it and the next line
|
||||
*/
|
||||
public static final String TOOLTIP_LINESPACE = "\u00A7h";
|
||||
/**
|
||||
* Have a string in the tooltip list with TOOLTIP_HANDLER + getTipLineId(handler) for a custom handler
|
||||
*/
|
||||
public static final String TOOLTIP_HANDLER = "\u00A7x";
|
||||
private static List<ITooltipLineHandler> tipLineHandlers = new ArrayList<ITooltipLineHandler>();
|
||||
|
||||
public static interface ITooltipLineHandler
|
||||
{
|
||||
public Dimension getSize();
|
||||
|
||||
public void draw(int x, int y);
|
||||
}
|
||||
|
||||
public static int getTipLineId(ITooltipLineHandler handler) {
|
||||
tipLineHandlers.add(handler);
|
||||
return tipLineHandlers.size()-1;
|
||||
}
|
||||
|
||||
public static ITooltipLineHandler getTipLine(String line) {
|
||||
if(!line.startsWith(TOOLTIP_HANDLER))
|
||||
return null;
|
||||
return tipLineHandlers.get(Integer.parseInt(line.substring(2)));
|
||||
}
|
||||
|
||||
public static void drawMultilineTip(int x, int y, List<String> list) {
|
||||
if (list.isEmpty())
|
||||
return;
|
||||
|
||||
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
|
||||
GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
|
||||
int w = 0;
|
||||
int h = -2;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
String s = list.get(i);
|
||||
ITooltipLineHandler line = getTipLine(s);
|
||||
Dimension d = line != null ?
|
||||
line.getSize() :
|
||||
new Dimension(getStringWidth(s), list.get(i).endsWith(TOOLTIP_LINESPACE) && i + 1 < list.size() ? 12 : 10);
|
||||
w = Math.max(w, d.width);
|
||||
h += d.height;
|
||||
}
|
||||
|
||||
if (x < 8) x = 8;
|
||||
else if (x > displaySize().width - w - 8) x -= 24 + w;//flip side of cursor
|
||||
y = (int) MathHelper.clip(y, 8, displaySize().height - 8 - h);
|
||||
|
||||
gui.incZLevel(300);
|
||||
drawTooltipBox(x - 4, y - 4, w + 7, h + 7);
|
||||
for (String s : list) {
|
||||
ITooltipLineHandler line = getTipLine(s);
|
||||
if(line != null) {
|
||||
line.draw(x, y);
|
||||
y += line.getSize().height;
|
||||
}
|
||||
else {
|
||||
fontRenderer.drawStringWithShadow(s, x, y, -1);
|
||||
y += s.endsWith(TOOLTIP_LINESPACE) ? 12 : 10;
|
||||
}
|
||||
}
|
||||
|
||||
tipLineHandlers.clear();
|
||||
gui.incZLevel(-300);
|
||||
|
||||
GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
}
|
||||
|
||||
public static void drawTooltipBox(int x, int y, int w, int h) {
|
||||
int bg = 0xf0100010;
|
||||
drawGradientRect(x + 1, y, w - 1, 1, bg, bg);
|
||||
drawGradientRect(x + 1, y + h, w - 1, 1, bg, bg);
|
||||
drawGradientRect(x + 1, y + 1, w - 1, h - 1, bg, bg);//center
|
||||
drawGradientRect(x, y + 1, 1, h - 1, bg, bg);
|
||||
drawGradientRect(x + w, y + 1, 1, h - 1, bg, bg);
|
||||
int grad1 = 0x505000ff;
|
||||
int grad2 = 0x5028007F;
|
||||
drawGradientRect(x + 1, y + 2, 1, h - 3, grad1, grad2);
|
||||
drawGradientRect(x + w - 1, y + 2, 1, h - 3, grad1, grad2);
|
||||
|
||||
drawGradientRect(x + 1, y + 1, w - 1, 1, grad1, grad1);
|
||||
drawGradientRect(x + 1, y + h - 1, w - 1, 1, grad2, grad2);
|
||||
}
|
||||
}
|
||||
@@ -76,11 +76,11 @@ public class InventoryCopy implements IInventory
|
||||
public void setInventorySlotContents(int slot, ItemStack stack)
|
||||
{
|
||||
items[slot] = stack;
|
||||
onInventoryChanged();
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInvName()
|
||||
public String getInventoryName()
|
||||
{
|
||||
return "copy";
|
||||
}
|
||||
@@ -91,12 +91,13 @@ public class InventoryCopy implements IInventory
|
||||
return true;
|
||||
}
|
||||
|
||||
public void openChest()
|
||||
@Override
|
||||
public void openInventory()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeChest()
|
||||
public void closeInventory()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -106,9 +107,8 @@ public class InventoryCopy implements IInventory
|
||||
return 64;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onInventoryChanged()
|
||||
public void markDirty()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public class InventoryCopy implements IInventory
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvNameLocalized()
|
||||
public boolean hasCustomInventoryName()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class InventoryNBT implements IInventory
|
||||
private void readNBT()
|
||||
{
|
||||
if(tag.hasKey("items"))
|
||||
InventoryUtils.readItemStacksFromTag(items, tag.getTagList("items"));
|
||||
InventoryUtils.readItemStacksFromTag(items, tag.getTagList("items", 10));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,11 +59,11 @@ public class InventoryNBT implements IInventory
|
||||
public void setInventorySlotContents(int slot, ItemStack stack)
|
||||
{
|
||||
items[slot] = stack;
|
||||
onInventoryChanged();
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInvName()
|
||||
public String getInventoryName()
|
||||
{
|
||||
return "NBT";
|
||||
}
|
||||
@@ -75,7 +75,7 @@ public class InventoryNBT implements IInventory
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInventoryChanged()
|
||||
public void markDirty()
|
||||
{
|
||||
writeNBT();
|
||||
}
|
||||
@@ -87,12 +87,12 @@ public class InventoryNBT implements IInventory
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openChest()
|
||||
public void openInventory()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeChest()
|
||||
public void closeInventory()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ public class InventoryNBT implements IInventory
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvNameLocalized()
|
||||
public boolean hasCustomInventoryName()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -83,11 +83,11 @@ public class InventorySimple implements IInventory
|
||||
public void setInventorySlotContents(int slot, ItemStack stack)
|
||||
{
|
||||
items[slot] = stack;
|
||||
onInventoryChanged();
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInvName()
|
||||
public String getInventoryName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
@@ -105,12 +105,12 @@ public class InventorySimple implements IInventory
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openChest()
|
||||
public void openInventory()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeChest()
|
||||
public void closeInventory()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -121,13 +121,13 @@ public class InventorySimple implements IInventory
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvNameLocalized()
|
||||
public boolean hasCustomInventoryName()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInventoryChanged()
|
||||
public void markDirty()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -5,44 +5,54 @@ import com.google.common.base.Objects;
|
||||
import codechicken.lib.vec.Vector3;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.InventoryLargeChest;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagInt;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.nbt.NBTTagShort;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityChest;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.ForgeDirection;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
public class InventoryUtils
|
||||
{
|
||||
/**
|
||||
* Constructor for ItemStack with tag
|
||||
*/
|
||||
public static ItemStack newItemStack(Item item, int size, int damage, NBTTagCompound tag) {
|
||||
ItemStack stack = new ItemStack(item, size, damage);
|
||||
stack.stackTagCompound = tag;
|
||||
return stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the actual damage of an item without asking the Item
|
||||
*/
|
||||
public static int actualDamage(ItemStack stack) {
|
||||
return Items.diamond.getDamage(stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static default implementation for IInventory method
|
||||
*/
|
||||
public static ItemStack decrStackSize(IInventory inv, int slot, int size)
|
||||
{
|
||||
public static ItemStack decrStackSize(IInventory inv, int slot, int size) {
|
||||
ItemStack item = inv.getStackInSlot(slot);
|
||||
|
||||
if(item != null)
|
||||
{
|
||||
if(item.stackSize <= size)
|
||||
{
|
||||
ItemStack itemstack = item;
|
||||
|
||||
if (item != null) {
|
||||
if (item.stackSize <= size) {
|
||||
inv.setInventorySlotContents(slot, null);
|
||||
inv.onInventoryChanged();
|
||||
return itemstack;
|
||||
inv.markDirty();
|
||||
return item;
|
||||
}
|
||||
ItemStack itemstack1 = item.splitStack(size);
|
||||
if(item.stackSize == 0)
|
||||
{
|
||||
if (item.stackSize == 0)
|
||||
inv.setInventorySlotContents(slot, null);
|
||||
}
|
||||
inv.onInventoryChanged();
|
||||
|
||||
inv.markDirty();
|
||||
return itemstack1;
|
||||
}
|
||||
return null;
|
||||
@@ -51,8 +61,7 @@ public class InventoryUtils
|
||||
/**
|
||||
* Static default implementation for IInventory method
|
||||
*/
|
||||
public static ItemStack getStackInSlotOnClosing(IInventory inv, int slot)
|
||||
{
|
||||
public static ItemStack getStackInSlotOnClosing(IInventory inv, int slot) {
|
||||
ItemStack stack = inv.getStackInSlot(slot);
|
||||
inv.setInventorySlotContents(slot, null);
|
||||
return stack;
|
||||
@@ -61,56 +70,50 @@ public class InventoryUtils
|
||||
/**
|
||||
* @return The quantity of items from addition that can be added to base
|
||||
*/
|
||||
public static int incrStackSize(ItemStack base, ItemStack addition)
|
||||
{
|
||||
public static int incrStackSize(ItemStack base, ItemStack addition) {
|
||||
if (canStack(base, addition))
|
||||
return incrStackSize(base, addition.stackSize);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The quantity of items from addition that can be added to base
|
||||
*/
|
||||
public static int incrStackSize(ItemStack base, int addition)
|
||||
{
|
||||
public static int incrStackSize(ItemStack base, int addition) {
|
||||
int totalSize = base.stackSize + addition;
|
||||
|
||||
if (totalSize <= base.getMaxStackSize())
|
||||
return addition;
|
||||
else if (base.stackSize < base.getMaxStackSize())
|
||||
return base.getMaxStackSize() - base.stackSize;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* NBT item saving function
|
||||
*/
|
||||
public static NBTTagList writeItemStacksToTag(ItemStack[] items)
|
||||
{
|
||||
public static NBTTagList writeItemStacksToTag(ItemStack[] items) {
|
||||
return writeItemStacksToTag(items, 64);
|
||||
}
|
||||
|
||||
/**
|
||||
* NBT item saving function with support for stack sizes > 32K
|
||||
*/
|
||||
public static NBTTagList writeItemStacksToTag(ItemStack[] items, int maxQuantity)
|
||||
{
|
||||
public static NBTTagList writeItemStacksToTag(ItemStack[] items, int maxQuantity) {
|
||||
NBTTagList tagList = new NBTTagList();
|
||||
for(int i = 0; i < items.length; i++)
|
||||
{
|
||||
if (items[i] != null)
|
||||
{
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
if (items[i] != null) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
tag.setShort("Slot", (short) i);
|
||||
items[i].writeToNBT(tag);
|
||||
|
||||
if(maxQuantity > Short.MAX_VALUE)
|
||||
|
||||
if (maxQuantity > Short.MAX_VALUE)
|
||||
tag.setInteger("Quantity", items[i].stackSize);
|
||||
else if(maxQuantity > Byte.MAX_VALUE)
|
||||
else if (maxQuantity > Byte.MAX_VALUE)
|
||||
tag.setShort("Quantity", (short) items[i].stackSize);
|
||||
|
||||
|
||||
tagList.appendTag(tag);
|
||||
}
|
||||
}
|
||||
@@ -120,29 +123,20 @@ public class InventoryUtils
|
||||
/**
|
||||
* NBT item loading function with support for stack sizes > 32K
|
||||
*/
|
||||
public static void readItemStacksFromTag(ItemStack[] items, NBTTagList tagList)
|
||||
{
|
||||
for(int i = 0; i < tagList.tagCount(); i++)
|
||||
{
|
||||
NBTTagCompound tag = (NBTTagCompound) tagList.tagAt(i);
|
||||
public static void readItemStacksFromTag(ItemStack[] items, NBTTagList tagList) {
|
||||
for (int i = 0; i < tagList.tagCount(); i++) {
|
||||
NBTTagCompound tag = tagList.getCompoundTagAt(i);
|
||||
int b = tag.getShort("Slot");
|
||||
items[b] = ItemStack.loadItemStackFromNBT(tag);
|
||||
if(tag.hasKey("Quantity"))
|
||||
{
|
||||
NBTBase qtag = tag.getTag("Quantity");
|
||||
if(qtag instanceof NBTTagInt)
|
||||
items[b].stackSize = ((NBTTagInt)qtag).data;
|
||||
else if(qtag instanceof NBTTagShort)
|
||||
items[b].stackSize = ((NBTTagShort)qtag).data;
|
||||
}
|
||||
if (tag.hasKey("Quantity"))
|
||||
items[b].stackSize = ((NBTBase.NBTPrimitive) tag.getTag("Quantity")).func_150287_d();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns an itemstack in the world at a location
|
||||
*/
|
||||
public static void dropItem(ItemStack stack, World world, Vector3 dropLocation)
|
||||
{
|
||||
public static void dropItem(ItemStack stack, World world, Vector3 dropLocation) {
|
||||
EntityItem item = new EntityItem(world, dropLocation.x, dropLocation.y, dropLocation.z, stack);
|
||||
item.motionX = world.rand.nextGaussian() * 0.05;
|
||||
item.motionY = world.rand.nextGaussian() * 0.05 + 0.2F;
|
||||
@@ -153,11 +147,10 @@ public class InventoryUtils
|
||||
/**
|
||||
* Copies an itemstack with a new quantity
|
||||
*/
|
||||
public static ItemStack copyStack(ItemStack stack, int quantity)
|
||||
{
|
||||
if(stack == null)
|
||||
public static ItemStack copyStack(ItemStack stack, int quantity) {
|
||||
if (stack == null)
|
||||
return null;
|
||||
|
||||
|
||||
stack = stack.copy();
|
||||
stack.stackSize = quantity;
|
||||
return stack;
|
||||
@@ -166,102 +159,87 @@ public class InventoryUtils
|
||||
/**
|
||||
* Gets the maximum quantity of an item that can be inserted into inv
|
||||
*/
|
||||
public static int getInsertibleQuantity(InventoryRange inv, ItemStack stack)
|
||||
{
|
||||
public static int getInsertibleQuantity(InventoryRange inv, ItemStack stack) {
|
||||
int quantity = 0;
|
||||
stack = copyStack(stack, Integer.MAX_VALUE);
|
||||
for(int slot : inv.slots)
|
||||
quantity+=fitStackInSlot(inv, slot, stack);
|
||||
|
||||
for (int slot : inv.slots)
|
||||
quantity += fitStackInSlot(inv, slot, stack);
|
||||
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public static int getInsertibleQuantity(IInventory inv, ItemStack stack)
|
||||
{
|
||||
public static int getInsertibleQuantity(IInventory inv, ItemStack stack) {
|
||||
return getInsertibleQuantity(new InventoryRange(inv), stack);
|
||||
}
|
||||
|
||||
public static int fitStackInSlot(InventoryRange inv, int slot, ItemStack stack)
|
||||
{
|
||||
|
||||
public static int fitStackInSlot(InventoryRange inv, int slot, ItemStack stack) {
|
||||
ItemStack base = inv.inv.getStackInSlot(slot);
|
||||
if(!canStack(base, stack) || !inv.canInsertItem(slot, stack))
|
||||
if (!canStack(base, stack) || !inv.canInsertItem(slot, stack))
|
||||
return 0;
|
||||
|
||||
int fit = base != null ? incrStackSize(base, inv.inv.getInventoryStackLimit()-base.stackSize) : inv.inv.getInventoryStackLimit();
|
||||
int fit = base != null ? incrStackSize(base, inv.inv.getInventoryStackLimit() - base.stackSize) : inv.inv.getInventoryStackLimit();
|
||||
return Math.min(fit, stack.stackSize);
|
||||
}
|
||||
|
||||
public static int fitStackInSlot(IInventory inv, int slot, ItemStack stack)
|
||||
{
|
||||
public static int fitStackInSlot(IInventory inv, int slot, ItemStack stack) {
|
||||
return fitStackInSlot(new InventoryRange(inv), slot, stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param simulate. If set to true, no items will actually be inserted
|
||||
* @param simulate If set to true, no items will actually be inserted
|
||||
* @return The number of items unable to be inserted
|
||||
*/
|
||||
public static int insertItem(InventoryRange inv, ItemStack stack, boolean simulate)
|
||||
{
|
||||
public static int insertItem(InventoryRange inv, ItemStack stack, boolean simulate) {
|
||||
stack = stack.copy();
|
||||
for(int pass = 0; pass < 2; pass++)
|
||||
{
|
||||
for(int slot : inv.slots)
|
||||
{
|
||||
for (int pass = 0; pass < 2; pass++) {
|
||||
for (int slot : inv.slots) {
|
||||
ItemStack base = inv.inv.getStackInSlot(slot);
|
||||
int fit = fitStackInSlot(inv, slot, stack);
|
||||
if(fit == 0)
|
||||
if (fit == 0)
|
||||
continue;
|
||||
|
||||
if(base != null)
|
||||
{
|
||||
stack.stackSize-=fit;
|
||||
if(!simulate)
|
||||
{
|
||||
base.stackSize+=fit;
|
||||
|
||||
if (base != null) {
|
||||
stack.stackSize -= fit;
|
||||
if (!simulate) {
|
||||
base.stackSize += fit;
|
||||
inv.inv.setInventorySlotContents(slot, base);
|
||||
}
|
||||
}
|
||||
else if(pass == 1)
|
||||
{
|
||||
if(!simulate)
|
||||
} else if (pass == 1) {
|
||||
if (!simulate)
|
||||
inv.inv.setInventorySlotContents(slot, copyStack(stack, fit));
|
||||
stack.stackSize-=fit;
|
||||
stack.stackSize -= fit;
|
||||
}
|
||||
if(stack.stackSize == 0)
|
||||
if (stack.stackSize == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return stack.stackSize;
|
||||
}
|
||||
|
||||
public static int insertItem(IInventory inv, ItemStack stack, boolean simulate)
|
||||
{
|
||||
public static int insertItem(IInventory inv, ItemStack stack, boolean simulate) {
|
||||
return insertItem(new InventoryRange(inv), stack, simulate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the stack in slot if it can be extracted
|
||||
*/
|
||||
public static ItemStack getExtractableStack(InventoryRange inv, int slot)
|
||||
{
|
||||
public static ItemStack getExtractableStack(InventoryRange inv, int slot) {
|
||||
ItemStack stack = inv.inv.getStackInSlot(slot);
|
||||
if(stack == null || !inv.canExtractItem(slot, stack))
|
||||
if (stack == null || !inv.canExtractItem(slot, stack))
|
||||
return null;
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
public static ItemStack getExtractableStack(IInventory inv, int slot)
|
||||
{
|
||||
public static ItemStack getExtractableStack(IInventory inv, int slot) {
|
||||
return getExtractableStack(new InventoryRange(inv), slot);
|
||||
}
|
||||
|
||||
public static boolean areStacksIdentical(ItemStack stack1, ItemStack stack2)
|
||||
{
|
||||
if(stack1 == null || stack2 == null)
|
||||
public static boolean areStacksIdentical(ItemStack stack1, ItemStack stack2) {
|
||||
if (stack1 == null || stack2 == null)
|
||||
return stack1 == stack2;
|
||||
|
||||
return stack1.itemID == stack2.itemID
|
||||
return stack1.getItem() == stack2.getItem()
|
||||
&& stack1.getItemDamage() == stack2.getItemDamage()
|
||||
&& stack1.stackSize == stack2.stackSize
|
||||
&& Objects.equal(stack1.getTagCompound(), stack2.getTagCompound());
|
||||
@@ -270,53 +248,46 @@ public class InventoryUtils
|
||||
/**
|
||||
* Gets an IInventory from a coordinate with support for double chests
|
||||
*/
|
||||
public static IInventory getInventory(World world, int x, int y, int z)
|
||||
{
|
||||
TileEntity tile = world.getBlockTileEntity(x, y, z);
|
||||
if(!(tile instanceof IInventory))
|
||||
public static IInventory getInventory(World world, int x, int y, int z) {
|
||||
TileEntity tile = world.getTileEntity(x, y, z);
|
||||
if (!(tile instanceof IInventory))
|
||||
return null;
|
||||
|
||||
if(tile instanceof TileEntityChest)
|
||||
|
||||
if (tile instanceof TileEntityChest)
|
||||
return getChest((TileEntityChest) tile);
|
||||
return (IInventory)tile;
|
||||
|
||||
return (IInventory) tile;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static final ForgeDirection[] chestSides = new ForgeDirection[]{ForgeDirection.WEST, ForgeDirection.EAST, ForgeDirection.NORTH, ForgeDirection.SOUTH};
|
||||
public static IInventory getChest(TileEntityChest chest)
|
||||
{
|
||||
for(ForgeDirection fside : chestSides)
|
||||
{
|
||||
if(chest.worldObj.getBlockId(chest.xCoord+fside.offsetX, chest.yCoord+fside.offsetY, chest.zCoord+fside.offsetZ) == chest.getBlockType().blockID)
|
||||
return new InventoryLargeChest("container.chestDouble",
|
||||
(TileEntityChest)chest.worldObj.getBlockTileEntity(chest.xCoord+fside.offsetX, chest.yCoord+fside.offsetY, chest.zCoord+fside.offsetZ), chest);
|
||||
|
||||
public static IInventory getChest(TileEntityChest chest) {
|
||||
for (ForgeDirection fside : chestSides) {
|
||||
if (chest.getWorldObj().getBlock(chest.xCoord + fside.offsetX, chest.yCoord + fside.offsetY, chest.zCoord + fside.offsetZ) == chest.getBlockType())
|
||||
return new InventoryLargeChest("container.chestDouble",
|
||||
(TileEntityChest) chest.getWorldObj().getTileEntity(chest.xCoord + fside.offsetX, chest.yCoord + fside.offsetY, chest.zCoord + fside.offsetZ), chest);
|
||||
}
|
||||
return chest;
|
||||
}
|
||||
|
||||
public static boolean canStack(ItemStack stack1, ItemStack stack2)
|
||||
{
|
||||
return stack1 == null || stack2 == null ||
|
||||
(stack1.itemID == stack2.itemID &&
|
||||
(!stack2.getHasSubtypes() || stack2.getItemDamage() == stack1.getItemDamage()) &&
|
||||
ItemStack.areItemStackTagsEqual(stack2, stack1)) &&
|
||||
stack1.isStackable();
|
||||
public static boolean canStack(ItemStack stack1, ItemStack stack2) {
|
||||
return stack1 == null || stack2 == null ||
|
||||
(stack1.getItem() == stack2.getItem() &&
|
||||
(!stack2.getHasSubtypes() || stack2.getItemDamage() == stack1.getItemDamage()) &&
|
||||
ItemStack.areItemStackTagsEqual(stack2, stack1)) &&
|
||||
stack1.isStackable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes one item from slot in inv with support for containers.
|
||||
*/
|
||||
public static void consumeItem(IInventory inv, int slot)
|
||||
{
|
||||
public static void consumeItem(IInventory inv, int slot) {
|
||||
ItemStack stack = inv.getStackInSlot(slot);
|
||||
Item item = stack.getItem();
|
||||
if(item.hasContainerItem())
|
||||
{
|
||||
ItemStack container = item.getContainerItemStack(stack);
|
||||
if (item.hasContainerItem(stack)) {
|
||||
ItemStack container = item.getContainerItem(stack);
|
||||
inv.setInventorySlotContents(slot, container);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
inv.decrStackSize(slot, 1);
|
||||
}
|
||||
}
|
||||
@@ -324,8 +295,7 @@ public class InventoryUtils
|
||||
/**
|
||||
* Gets the size of the stack in a slot. Returns 0 on null stacks
|
||||
*/
|
||||
public static int stackSize(IInventory inv, int slot)
|
||||
{
|
||||
public static int stackSize(IInventory inv, int slot) {
|
||||
ItemStack stack = inv.getStackInSlot(slot);
|
||||
return stack == null ? 0 : stack.stackSize;
|
||||
}
|
||||
@@ -333,21 +303,30 @@ public class InventoryUtils
|
||||
/**
|
||||
* Drops all items from inv using getStackInSlotOnClosing
|
||||
*/
|
||||
public static void dropOnClose(EntityPlayer player, IInventory inv)
|
||||
{
|
||||
for (int i = 0; i < inv.getSizeInventory(); i++)
|
||||
{
|
||||
public static void dropOnClose(EntityPlayer player, IInventory inv) {
|
||||
for (int i = 0; i < inv.getSizeInventory(); i++) {
|
||||
ItemStack stack = inv.getStackInSlotOnClosing(i);
|
||||
if (stack != null)
|
||||
player.dropPlayerItem(stack);
|
||||
player.dropPlayerItemWithRandomChoice(stack, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the actual damage of an item without asking the Item
|
||||
*/
|
||||
public static int actualDamage(ItemStack stack)
|
||||
{
|
||||
return Item.diamond.getDamage(stack);
|
||||
public static NBTTagCompound savePersistant(ItemStack stack, NBTTagCompound tag) {
|
||||
stack.writeToNBT(tag);
|
||||
tag.removeTag("id");
|
||||
tag.setString("name", Item.itemRegistry.getNameForObject(stack.getItem()));
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static ItemStack loadPersistant(NBTTagCompound tag) {
|
||||
String name = tag.getString("name");
|
||||
Item item = (Item) Item.itemRegistry.getObject(name);
|
||||
if(item == null) return null;
|
||||
int count = tag.hasKey("Count") ? tag.getByte("Count") : 1;
|
||||
int damage = tag.hasKey("Damage") ? tag.getShort("Damage") : 0;
|
||||
ItemStack stack = new ItemStack(item, count, damage);
|
||||
if(tag.hasKey("tag", 10))
|
||||
stack.stackTagCompound = tag.getCompoundTag("tag");
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
package codechicken.lib.inventory;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import static codechicken.lib.inventory.InventoryUtils.*;
|
||||
|
||||
/**
|
||||
@@ -11,55 +14,52 @@ import static codechicken.lib.inventory.InventoryUtils.*;
|
||||
*/
|
||||
public class ItemKey implements Comparable<ItemKey>
|
||||
{
|
||||
public ItemStack item;
|
||||
public ItemStack stack;
|
||||
private int hashcode = 0;
|
||||
|
||||
public ItemKey(ItemStack k)
|
||||
{
|
||||
item = k;
|
||||
|
||||
public ItemKey(ItemStack k) {
|
||||
stack = k;
|
||||
}
|
||||
|
||||
public ItemKey(int id, int damage)
|
||||
{
|
||||
this(new ItemStack(id, 1, damage));
|
||||
public ItemKey(Item item, int damage) {
|
||||
this(new ItemStack(item, 1, damage));
|
||||
}
|
||||
|
||||
public ItemKey(int id, int damage, NBTTagCompound compound)
|
||||
{
|
||||
this(id, damage);
|
||||
item.setTagCompound(compound);
|
||||
|
||||
public ItemKey(Item item, NBTTagCompound tag) {
|
||||
this(item, OreDictionary.WILDCARD_VALUE, tag);
|
||||
}
|
||||
|
||||
public ItemKey(Item item, int damage, NBTTagCompound tag) {
|
||||
this(item, damage);
|
||||
stack.setTagCompound(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(!(obj instanceof ItemKey))
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ItemKey))
|
||||
return false;
|
||||
|
||||
ItemKey k = (ItemKey)obj;
|
||||
return item.itemID == k.item.itemID &&
|
||||
actualDamage(item) == actualDamage(k.item) &&
|
||||
Objects.equal(item.stackTagCompound, k.item.stackTagCompound);
|
||||
|
||||
ItemKey k = (ItemKey) obj;
|
||||
return stack.getItem() == k.stack.getItem() &&
|
||||
actualDamage(stack) == actualDamage(k.stack) &&
|
||||
Objects.equal(stack.stackTagCompound, k.stack.stackTagCompound);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return hashcode != 0 ? hashcode : (hashcode = Objects.hashCode(item.itemID, actualDamage(item), item.stackTagCompound));
|
||||
public int hashCode() {
|
||||
return hashcode != 0 ? hashcode : (hashcode = Objects.hashCode(stack.getItem(), actualDamage(stack), stack.stackTagCompound));
|
||||
}
|
||||
|
||||
public int compareInt(int a, int b)
|
||||
{
|
||||
|
||||
public int compareInt(int a, int b) {
|
||||
return a == b ? 0 : a < b ? -1 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ItemKey o)
|
||||
{
|
||||
if(item.itemID != o.item.itemID)
|
||||
return compareInt(item.itemID, o.item.itemID);
|
||||
if(actualDamage(item) != actualDamage(o.item))
|
||||
return compareInt(actualDamage(item), actualDamage(o.item));
|
||||
public int compareTo(ItemKey o) {
|
||||
if (stack.getItem() != o.stack.getItem())
|
||||
return compareInt(Item.getIdFromItem(stack.getItem()), Item.getIdFromItem(o.stack.getItem()));
|
||||
if (actualDamage(stack) != actualDamage(o.stack))
|
||||
return compareInt(actualDamage(stack), actualDamage(o.stack));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
package codechicken.lib.lang;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.SortedSet;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.Language;
|
||||
import net.minecraft.client.resources.Resource;
|
||||
import net.minecraft.client.resources.ResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.StatCollector;
|
||||
|
||||
import cpw.mods.fml.common.registry.LanguageRegistry;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* Easy localisation access.
|
||||
*/
|
||||
public class LangUtil
|
||||
{
|
||||
public static LangUtil instance = new LangUtil(null);
|
||||
|
||||
public String prefix;
|
||||
|
||||
public LangUtil(String prefix)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public static String translateG(String s, Object... format)
|
||||
{
|
||||
return instance.translate(s, format);
|
||||
}
|
||||
|
||||
public String translate(String s, Object... format)
|
||||
{
|
||||
if(prefix != null && !s.startsWith(prefix+"."))
|
||||
s = prefix+"."+s;
|
||||
String ret = LanguageRegistry.instance().getStringLocalization(s);
|
||||
if(ret.length() == 0)
|
||||
ret = LanguageRegistry.instance().getStringLocalization(s, "en_US");
|
||||
if(ret.length() == 0)
|
||||
ret = StatCollector.translateToLocal(s);
|
||||
if(ret.length() == 0)
|
||||
return s;
|
||||
if(format.length > 0)
|
||||
ret = String.format(ret, format);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void addLangFile(InputStream resource, String lang) throws IOException
|
||||
{
|
||||
LanguageRegistry reg = LanguageRegistry.instance();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(resource, "UTF-8"));
|
||||
while(true)
|
||||
{
|
||||
String read = reader.readLine();
|
||||
if(read == null)
|
||||
break;
|
||||
|
||||
int equalIndex = read.indexOf('=');
|
||||
if(equalIndex == -1)
|
||||
continue;
|
||||
String key = read.substring(0, equalIndex);
|
||||
String value = read.substring(equalIndex+1);
|
||||
if(prefix != null)
|
||||
key = prefix+"."+key;
|
||||
reg.addStringLocalization(key, lang, value);
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static LangUtil loadLangDir(String domain)
|
||||
{
|
||||
return new LangUtil(domain).addLangDir(new ResourceLocation(domain, "lang"));
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public LangUtil addLangDir(ResourceLocation dir)
|
||||
{
|
||||
ResourceManager resManager = Minecraft.getMinecraft().getResourceManager();
|
||||
for(Language lang : (SortedSet<Language>)Minecraft.getMinecraft().getLanguageManager().getLanguages())
|
||||
{
|
||||
String langID = lang.getLanguageCode();
|
||||
Resource langRes;
|
||||
try
|
||||
{
|
||||
langRes = resManager.getResource(new ResourceLocation(dir.getResourceDomain(), dir.getResourcePath()+'/'+langID+".lang"));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
addLangFile(langRes.getInputStream(), langID);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
System.err.println("Failed to load lang resource. domain="+prefix+", resource="+langRes);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package codechicken.lib.lighting;
|
||||
|
||||
import codechicken.lib.render.CCModel;
|
||||
import codechicken.lib.render.Vertex5;
|
||||
|
||||
public class CCRBModel extends CCModel
|
||||
{
|
||||
public LC[] lightCoefficents;
|
||||
|
||||
/**
|
||||
* Lighting sides and coefficients are computed for each vertex of the model. All faces must be axis planar and all verts are assumed to be in the range (0,0,0) to (1,1,1)
|
||||
*/
|
||||
public CCRBModel(CCModel m)
|
||||
{
|
||||
super(m.vertexMode);
|
||||
verts = new Vertex5[m.verts.length];
|
||||
copy(m, 0, this, 0, m.verts.length);
|
||||
if(normals == null)
|
||||
computeNormals();
|
||||
if(colours == null)
|
||||
setColour(-1);
|
||||
computeLighting();
|
||||
}
|
||||
|
||||
private void computeLighting()
|
||||
{
|
||||
lightCoefficents = new LC[verts.length];
|
||||
for(int k = 0; k < verts.length; k++)
|
||||
lightCoefficents[k] = LC.compute(verts[k].vec, normals[k]);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,89 @@
|
||||
package codechicken.lib.lighting;
|
||||
|
||||
import codechicken.lib.render.CCModel;
|
||||
import codechicken.lib.util.Copyable;
|
||||
import codechicken.lib.vec.Rotation;
|
||||
import codechicken.lib.vec.Vector3;
|
||||
|
||||
public class LC
|
||||
public class LC implements Copyable<LC>
|
||||
{
|
||||
public LC(int s, float e, float f, float g, float h)
|
||||
{
|
||||
side = s;
|
||||
fa = e;
|
||||
fb = f;
|
||||
fc = g;
|
||||
fd = h;
|
||||
}
|
||||
|
||||
public int side;
|
||||
public float fa;
|
||||
public float fb;
|
||||
public float fc;
|
||||
public float fd;
|
||||
|
||||
public static LC compute(Vector3 vec, Vector3 normal)
|
||||
{
|
||||
|
||||
public LC() {
|
||||
this(0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public LC(int s, float a, float b, float c, float d) {
|
||||
side = s;
|
||||
fa = a;
|
||||
fb = b;
|
||||
fc = c;
|
||||
fd = d;
|
||||
}
|
||||
|
||||
public LC set(int s, float a, float b, float c, float d) {
|
||||
side = s;
|
||||
fa = a;
|
||||
fb = b;
|
||||
fc = c;
|
||||
fd = d;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LC set(LC lc) {
|
||||
return set(lc.side, lc.fa, lc.fb, lc.fc, lc.fd);
|
||||
}
|
||||
|
||||
public LC compute(Vector3 vec, Vector3 normal) {
|
||||
int side = CCModel.findSide(normal);
|
||||
if(side < 0)
|
||||
return new LC(12, 1, 0, 0, 0);
|
||||
if (side < 0)
|
||||
return set(12, 1, 0, 0, 0);
|
||||
return compute(vec, side);
|
||||
}
|
||||
|
||||
public static LC compute(Vector3 vec, int side)
|
||||
{
|
||||
|
||||
public LC compute(Vector3 vec, int side) {
|
||||
boolean offset = false;
|
||||
switch(side)
|
||||
{
|
||||
case 0: offset = vec.y <= 0; break;
|
||||
case 1: offset = vec.y >= 1; break;
|
||||
case 2: offset = vec.z <= 0; break;
|
||||
case 3: offset = vec.z >= 1; break;
|
||||
case 4: offset = vec.x <= 0; break;
|
||||
case 5: offset = vec.x >= 1; break;
|
||||
switch (side) {
|
||||
case 0:
|
||||
offset = vec.y <= 0;
|
||||
break;
|
||||
case 1:
|
||||
offset = vec.y >= 1;
|
||||
break;
|
||||
case 2:
|
||||
offset = vec.z <= 0;
|
||||
break;
|
||||
case 3:
|
||||
offset = vec.z >= 1;
|
||||
break;
|
||||
case 4:
|
||||
offset = vec.x <= 0;
|
||||
break;
|
||||
case 5:
|
||||
offset = vec.x >= 1;
|
||||
break;
|
||||
}
|
||||
if(!offset)
|
||||
side+=6;
|
||||
if (!offset)
|
||||
side += 6;
|
||||
return computeO(vec, side);
|
||||
}
|
||||
|
||||
public static LC computeO(Vector3 vec, int side)
|
||||
{
|
||||
Vector3 v1 = Rotation.axes[((side&0xE)+3)%6];
|
||||
Vector3 v2 = Rotation.axes[((side&0xE)+5)%6];
|
||||
public LC computeO(Vector3 vec, int side) {
|
||||
Vector3 v1 = Rotation.axes[((side & 0xE) + 3) % 6];
|
||||
Vector3 v2 = Rotation.axes[((side & 0xE) + 5) % 6];
|
||||
float d1 = (float) vec.scalarProject(v1);
|
||||
float d2 = 1-d1;
|
||||
float d2 = 1 - d1;
|
||||
float d3 = (float) vec.scalarProject(v2);
|
||||
float d4 = 1-d3;
|
||||
return new LC(side, d2*d4, d2*d3, d1*d4, d1*d3);
|
||||
float d4 = 1 - d3;
|
||||
return set(side, d2 * d4, d2 * d3, d1 * d4, d1 * d3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LC copy() {
|
||||
return new LC(side, fa, fb, fc, fd);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package codechicken.lib.lighting;
|
||||
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import codechicken.lib.vec.BlockCoord;
|
||||
|
||||
public class LazyLightMatrix
|
||||
{
|
||||
private BlockCoord pos = new BlockCoord();
|
||||
private IBlockAccess access;
|
||||
private boolean computed = false;
|
||||
private LightMatrix lightMatrix = new LightMatrix();
|
||||
|
||||
public LightMatrix lightMatrix()
|
||||
{
|
||||
if(computed)
|
||||
return lightMatrix;
|
||||
computed = true;
|
||||
lightMatrix.computeAt(access, pos.x, pos.y, pos.z);
|
||||
return lightMatrix;
|
||||
}
|
||||
|
||||
public void setPos(IBlockAccess access, int x, int y, int z)
|
||||
{
|
||||
computed = false;
|
||||
this.access = access;
|
||||
pos.set(x, y, z);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,31 @@
|
||||
package codechicken.lib.lighting;
|
||||
|
||||
import codechicken.lib.render.CCModel;
|
||||
import codechicken.lib.colour.ColourRGBA;
|
||||
import codechicken.lib.render.CCRenderState;
|
||||
import codechicken.lib.render.IVertexModifier;
|
||||
import codechicken.lib.render.UV;
|
||||
import codechicken.lib.vec.BlockCoord;
|
||||
import codechicken.lib.vec.Vector3;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
/**
|
||||
* Note that when using the class as a vertex transformer, the vertices are assumed to be within the BB (x, y, z) -> (x+1, y+1, z+1)
|
||||
*/
|
||||
public class LightMatrix implements IVertexModifier
|
||||
public class LightMatrix implements CCRenderState.IVertexOperation
|
||||
{
|
||||
public static final int operationIndex = CCRenderState.registerOperation();
|
||||
|
||||
public int computed = 0;
|
||||
public float[][] ao = new float[13][4];
|
||||
public int[][] brightness = new int[13][4];
|
||||
|
||||
public IBlockAccess access;
|
||||
public BlockCoord pos = new BlockCoord();
|
||||
|
||||
|
||||
private int sampled = 0;
|
||||
private float[] aSamples = new float[27];
|
||||
private int[] bSamples = new int[27];
|
||||
private Vector3 v_temp = new Vector3();
|
||||
|
||||
|
||||
/**
|
||||
* The 9 positions in the sample array for each side, sides >= 6 are centered on sample 13 (the block itself)
|
||||
*/
|
||||
@@ -73,137 +74,88 @@ public class LightMatrix implements IVertexModifier
|
||||
}
|
||||
System.out.println(Arrays.deepToString(ssamplem));
|
||||
}*/
|
||||
|
||||
public void computeAt(IBlockAccess a, int x, int y, int z)
|
||||
{
|
||||
|
||||
public void locate(IBlockAccess a, int x, int y, int z) {
|
||||
access = a;
|
||||
pos.set(x, y, z);
|
||||
computed = 0;
|
||||
//inc x, inc z, inc y
|
||||
sample( 0, aSamples, bSamples, a, x-1, y-1, z-1);
|
||||
sample( 1, aSamples, bSamples, a, x , y-1, z-1);
|
||||
sample( 2, aSamples, bSamples, a, x+1, y-1, z-1);
|
||||
sample( 3, aSamples, bSamples, a, x-1, y-1, z );
|
||||
sample( 4, aSamples, bSamples, a, x , y-1, z );
|
||||
sample( 5, aSamples, bSamples, a, x+1, y-1, z );
|
||||
sample( 6, aSamples, bSamples, a, x-1, y-1, z+1);
|
||||
sample( 7, aSamples, bSamples, a, x , y-1, z+1);
|
||||
sample( 8, aSamples, bSamples, a, x+1, y-1, z+1);
|
||||
sample( 9, aSamples, bSamples, a, x-1, y , z-1);
|
||||
sample(10, aSamples, bSamples, a, x , y , z-1);
|
||||
sample(11, aSamples, bSamples, a, x+1, y , z-1);
|
||||
sample(12, aSamples, bSamples, a, x-1, y , z );
|
||||
sample(13, aSamples, bSamples, a, x , y , z );
|
||||
sample(14, aSamples, bSamples, a, x+1, y , z );
|
||||
sample(15, aSamples, bSamples, a, x-1, y , z+1);
|
||||
sample(16, aSamples, bSamples, a, x , y , z+1);
|
||||
sample(17, aSamples, bSamples, a, x+1, y , z+1);
|
||||
sample(18, aSamples, bSamples, a, x-1, y+1, z-1);
|
||||
sample(19, aSamples, bSamples, a, x , y+1, z-1);
|
||||
sample(20, aSamples, bSamples, a, x+1, y+1, z-1);
|
||||
sample(21, aSamples, bSamples, a, x-1, y+1, z );
|
||||
sample(22, aSamples, bSamples, a, x , y+1, z );
|
||||
sample(23, aSamples, bSamples, a, x+1, y+1, z );
|
||||
sample(24, aSamples, bSamples, a, x-1, y+1, z+1);
|
||||
sample(25, aSamples, bSamples, a, x , y+1, z+1);
|
||||
sample(26, aSamples, bSamples, a, x+1, y+1, z+1);
|
||||
sampled = 0;
|
||||
}
|
||||
|
||||
public int[] brightness(int side)
|
||||
{
|
||||
|
||||
public void sample(int i) {
|
||||
if ((sampled & 1 << i) == 0) {
|
||||
int x = pos.x + (i % 3) - 1;
|
||||
int y = pos.y + (i / 9) - 1;
|
||||
int z = pos.z + (i / 3 % 3) - 1;
|
||||
Block b = access.getBlock(x, y, z);
|
||||
bSamples[i] = access.getLightBrightnessForSkyBlocks(x, y, z, b.getLightValue(access, x, y, z));
|
||||
aSamples[i] = b.getAmbientOcclusionLightValue();
|
||||
}
|
||||
}
|
||||
|
||||
public int[] brightness(int side) {
|
||||
sideSample(side);
|
||||
return brightness[side];
|
||||
}
|
||||
|
||||
public float[] ao(int side)
|
||||
{
|
||||
|
||||
public float[] ao(int side) {
|
||||
sideSample(side);
|
||||
return ao[side];
|
||||
}
|
||||
|
||||
public void sideSample(int side)
|
||||
{
|
||||
if((computed&1<<side) == 0)
|
||||
{
|
||||
|
||||
public void sideSample(int side) {
|
||||
if ((computed & 1 << side) == 0) {
|
||||
int[] ssample = ssamplem[side];
|
||||
for(int q = 0; q < 4; q++)
|
||||
{
|
||||
for (int q = 0; q < 4; q++) {
|
||||
int[] qsample = qsamplem[q];
|
||||
if(Minecraft.isAmbientOcclusionEnabled())
|
||||
if (Minecraft.isAmbientOcclusionEnabled())
|
||||
interp(side, q, ssample[qsample[0]], ssample[qsample[1]], ssample[qsample[2]], ssample[qsample[3]]);
|
||||
else
|
||||
interp(side, q, ssample[4], ssample[4], ssample[4], ssample[4]);
|
||||
}
|
||||
computed|=1<<side;
|
||||
computed |= 1 << side;
|
||||
}
|
||||
}
|
||||
|
||||
private void sample(int i, float[] aSamples, int[] bSamples, IBlockAccess a, int x, int y, int z)
|
||||
{
|
||||
int bid = a.getBlockId(x, y, z);
|
||||
Block b = Block.blocksList[bid];
|
||||
if(b == null)
|
||||
{
|
||||
bSamples[i] = a.getLightBrightnessForSkyBlocks(x, y, z, 0);
|
||||
aSamples[i] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bSamples[i] = a.getLightBrightnessForSkyBlocks(x, y, z, b.getLightValue(a, x, y, z));
|
||||
aSamples[i] = b.getAmbientOcclusionLightValue(a, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
private void interp(int s, int q, int a, int b, int c, int d)
|
||||
{
|
||||
private void interp(int s, int q, int a, int b, int c, int d) {
|
||||
sample(a); sample(b); sample(c); sample(d);
|
||||
ao[s][q] = interpAO(aSamples[a], aSamples[b], aSamples[c], aSamples[d])*sideao[s];
|
||||
brightness[s][q] = interpBrightness(bSamples[a], bSamples[b], bSamples[c], bSamples[d]);
|
||||
}
|
||||
|
||||
public static float interpAO(float a, float b, float c, float d)
|
||||
{
|
||||
return (a+b+c+d)/4F;
|
||||
|
||||
public static float interpAO(float a, float b, float c, float d) {
|
||||
return (a + b + c + d) / 4F;
|
||||
}
|
||||
|
||||
public static int interpBrightness(int a, int b, int c, int d)
|
||||
{
|
||||
if(a == 0)
|
||||
|
||||
public static int interpBrightness(int a, int b, int c, int d) {
|
||||
if (a == 0)
|
||||
a = d;
|
||||
if(b == 0)
|
||||
if (b == 0)
|
||||
b = d;
|
||||
if(c == 0)
|
||||
if (c == 0)
|
||||
c = d;
|
||||
return (a+b+c+d)>>2 & 0xFF00FF;
|
||||
return (a + b + c + d) >> 2 & 0xFF00FF;
|
||||
}
|
||||
|
||||
public void setColour(Tessellator tess, LC lc, int c)
|
||||
{
|
||||
float[] a = ao(lc.side);
|
||||
float f = (a[0]*lc.fa + a[1]*lc.fb + a[2]*lc.fc + a[3]*lc.fd);
|
||||
CCRenderState.vertexColour((int)((c>>>24)*f), (int)((c>>16&0xFF)*f), (int)((c>>8&0xFF)*f), (c&0xFF));
|
||||
}
|
||||
|
||||
public void setBrightness(Tessellator tess, LC lc)
|
||||
{
|
||||
int[] b = brightness(lc.side);
|
||||
tess.setBrightness((int)(b[0]*lc.fa + b[1]*lc.fb + b[2]*lc.fc+b[3]*lc.fd) & 0xFF00FF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyModifiers(CCModel m, Tessellator tess, Vector3 vec, UV uv, Vector3 normal, int i)
|
||||
{
|
||||
LC lc;
|
||||
if(m instanceof CCRBModel)
|
||||
lc = ((CCRBModel)m).lightCoefficents[i];
|
||||
else
|
||||
lc = LC.compute(v_temp.set(vec).add(-pos.x, -pos.y, -pos.z), normal);
|
||||
|
||||
setColour(tess, lc, (m == null || m.colours == null) ? -1 : m.colours[i]);
|
||||
setBrightness(tess, lc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsNormals()
|
||||
{
|
||||
public boolean load() {
|
||||
CCRenderState.pipeline.addDependency(CCRenderState.colourAttrib);
|
||||
CCRenderState.pipeline.addDependency(CCRenderState.lightCoordAttrib);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate() {
|
||||
LC lc = CCRenderState.lc;
|
||||
float[] a = ao(lc.side);
|
||||
float f = (a[0] * lc.fa + a[1] * lc.fb + a[2] * lc.fc + a[3] * lc.fd);
|
||||
int[] b = brightness(lc.side);
|
||||
CCRenderState.setColour(ColourRGBA.multiplyC(CCRenderState.colour, f));
|
||||
CCRenderState.setBrightness((int) (b[0] * lc.fa + b[1] * lc.fb + b[2] * lc.fc + b[3] * lc.fd) & 0xFF00FF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int operationID() {
|
||||
return operationIndex;
|
||||
}
|
||||
}
|
||||
@@ -3,60 +3,55 @@ package codechicken.lib.lighting;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import codechicken.lib.render.CCModel;
|
||||
import codechicken.lib.render.CCRenderState;
|
||||
import codechicken.lib.render.IVertexModifier;
|
||||
import codechicken.lib.render.UV;
|
||||
import codechicken.lib.render.uv.UV;
|
||||
import codechicken.lib.vec.Rotation;
|
||||
import codechicken.lib.vec.Vector3;
|
||||
|
||||
public class LightModel implements IVertexModifier
|
||||
public class LightModel implements CCRenderState.IVertexOperation
|
||||
{
|
||||
public static final int operationIndex = CCRenderState.registerOperation();
|
||||
|
||||
public static class Light
|
||||
{
|
||||
public Vector3 ambient = new Vector3();
|
||||
public Vector3 diffuse = new Vector3();
|
||||
public Vector3 position;
|
||||
|
||||
public Light(Vector3 pos)
|
||||
{
|
||||
|
||||
public Light(Vector3 pos) {
|
||||
position = pos.copy().normalize();
|
||||
}
|
||||
|
||||
public Light setDiffuse(Vector3 vec)
|
||||
{
|
||||
|
||||
public Light setDiffuse(Vector3 vec) {
|
||||
diffuse.set(vec);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Light setAmbient(Vector3 vec)
|
||||
{
|
||||
|
||||
public Light setAmbient(Vector3 vec) {
|
||||
ambient.set(vec);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public static LightModel standardLightModel;
|
||||
static
|
||||
{
|
||||
static {
|
||||
standardLightModel = new LightModel()
|
||||
.setAmbient(new Vector3(0.4, 0.4, 0.4))
|
||||
.addLight(new Light(new Vector3(0.2, 1, -0.7))
|
||||
.setDiffuse(new Vector3(0.6, 0.6, 0.6)))
|
||||
.setDiffuse(new Vector3(0.6, 0.6, 0.6)))
|
||||
.addLight(new Light(new Vector3(-0.2, 1, 0.7))
|
||||
.setDiffuse(new Vector3(0.6, 0.6, 0.6)));
|
||||
.setDiffuse(new Vector3(0.6, 0.6, 0.6)));
|
||||
}
|
||||
|
||||
private Vector3 ambient = new Vector3();
|
||||
private Light[] lights = new Light[8];
|
||||
private int lightCount;
|
||||
|
||||
public LightModel addLight(Light light)
|
||||
{
|
||||
|
||||
public LightModel addLight(Light light) {
|
||||
lights[lightCount++] = light;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LightModel setAmbient(Vector3 vec)
|
||||
{
|
||||
|
||||
public LightModel setAmbient(Vector3 vec) {
|
||||
ambient.set(vec);
|
||||
return this;
|
||||
}
|
||||
@@ -66,46 +61,48 @@ public class LightModel implements IVertexModifier
|
||||
* @param normal The normal at the vertex
|
||||
* @return The lighting applied colour
|
||||
*/
|
||||
public int apply(int colour, Vector3 normal)
|
||||
{
|
||||
public int apply(int colour, Vector3 normal) {
|
||||
Vector3 n_colour = ambient.copy();
|
||||
for(int l = 0; l < lightCount; l++)
|
||||
{
|
||||
for (int l = 0; l < lightCount; l++) {
|
||||
Light light = lights[l];
|
||||
double n_l = light.position.dotProduct(normal);
|
||||
double f = n_l > 0 ? 1 : 0;
|
||||
n_colour.x += light.ambient.x + f*light.diffuse.x*n_l;
|
||||
n_colour.y += light.ambient.y + f*light.diffuse.y*n_l;
|
||||
n_colour.z += light.ambient.z + f*light.diffuse.z*n_l;
|
||||
n_colour.x += light.ambient.x + f * light.diffuse.x * n_l;
|
||||
n_colour.y += light.ambient.y + f * light.diffuse.y * n_l;
|
||||
n_colour.z += light.ambient.z + f * light.diffuse.z * n_l;
|
||||
}
|
||||
|
||||
if(n_colour.x > 1)
|
||||
if (n_colour.x > 1)
|
||||
n_colour.x = 1;
|
||||
if(n_colour.y > 1)
|
||||
if (n_colour.y > 1)
|
||||
n_colour.y = 1;
|
||||
if(n_colour.z > 1)
|
||||
if (n_colour.z > 1)
|
||||
n_colour.z = 1;
|
||||
|
||||
n_colour.multiply((colour >>> 24)/255D, (colour >> 16 & 0xFF)/255D, (colour >> 8 & 0xFF)/255D);
|
||||
return (int)(n_colour.x*255)<<24 | (int)(n_colour.y*255)<<16 | (int)(n_colour.z*255)<<8 | colour&0xFF;
|
||||
|
||||
n_colour.multiply((colour >>> 24) / 255D, (colour >> 16 & 0xFF) / 255D, (colour >> 8 & 0xFF) / 255D);
|
||||
return (int) (n_colour.x * 255) << 24 | (int) (n_colour.y * 255) << 16 | (int) (n_colour.z * 255) << 8 | colour & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void applyModifiers(CCModel m, Tessellator tess, Vector3 vec, UV uv, Vector3 normal, int i)
|
||||
{
|
||||
CCRenderState.setColour(apply((m == null || m.colours == null) ? -1 : m.colours[i], normal));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsNormals()
|
||||
{
|
||||
public boolean load() {
|
||||
CCRenderState.pipeline.addDependency(CCRenderState.normalAttrib);
|
||||
CCRenderState.pipeline.addDependency(CCRenderState.colourAttrib);
|
||||
return true;
|
||||
}
|
||||
|
||||
public PlanarLightModel reducePlanar()
|
||||
{
|
||||
|
||||
@Override
|
||||
public void operate() {
|
||||
CCRenderState.setColour(apply(CCRenderState.colour, CCRenderState.normal));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int operationID() {
|
||||
return operationIndex;
|
||||
}
|
||||
|
||||
public PlanarLightModel reducePlanar() {
|
||||
int[] colours = new int[6];
|
||||
for(int i = 0; i < 6; i++)
|
||||
for (int i = 0; i < 6; i++)
|
||||
colours[i] = apply(-1, Rotation.axes[i]);
|
||||
return new PlanarLightModel(colours);
|
||||
}
|
||||
|
||||
@@ -1,42 +1,35 @@
|
||||
package codechicken.lib.lighting;
|
||||
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import codechicken.lib.colour.Colour;
|
||||
import codechicken.lib.colour.ColourRGBA;
|
||||
import codechicken.lib.render.CCModel;
|
||||
import codechicken.lib.render.CCRenderState;
|
||||
import codechicken.lib.render.IVertexModifier;
|
||||
import codechicken.lib.render.UV;
|
||||
import codechicken.lib.vec.Vector3;
|
||||
|
||||
/**
|
||||
* Faster precomputed version of LightModel that only works for axis planar sides
|
||||
*/
|
||||
public class PlanarLightModel implements IVertexModifier
|
||||
public class PlanarLightModel implements CCRenderState.IVertexOperation
|
||||
{
|
||||
public static PlanarLightModel standardLightModel = LightModel.standardLightModel.reducePlanar();
|
||||
|
||||
public ColourRGBA[] colours;
|
||||
|
||||
public PlanarLightModel(int[] colours)
|
||||
{
|
||||
this.colours = new ColourRGBA[6];
|
||||
for(int i = 0; i < 6; i++)
|
||||
this.colours[i] = new ColourRGBA(colours[i]);
|
||||
|
||||
public int[] colours;
|
||||
|
||||
public PlanarLightModel(int[] colours) {
|
||||
this.colours = colours;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyModifiers(CCModel m, Tessellator tess, Vector3 vec, UV uv, Vector3 normal, int i)
|
||||
{
|
||||
ColourRGBA light = colours[CCModel.findSide(normal)];
|
||||
int colour = (m == null || m.colours == null) ? -1 : m.colours[i];
|
||||
Colour res = new ColourRGBA(colour).multiply(light);
|
||||
CCRenderState.vertexColour(res.r&0xFF, res.g&0xFF, res.b&0xFF, res.a&0xFF) ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsNormals()
|
||||
{
|
||||
public boolean load() {
|
||||
CCRenderState.pipeline.addDependency(CCRenderState.sideAttrib);
|
||||
CCRenderState.pipeline.addDependency(CCRenderState.colourAttrib);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate() {
|
||||
CCRenderState.setColour(ColourRGBA.multiply(CCRenderState.colour, colours[CCRenderState.side]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int operationID() {
|
||||
return LightModel.operationIndex;
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
package codechicken.lib.packet;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
|
||||
import net.minecraft.network.packet.NetHandler;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.Packet250CustomPayload;
|
||||
|
||||
/**
|
||||
* A class that facilitates sending of multiple packets one after the other.
|
||||
* It first sends an empty 250 packet and then it's payloads.
|
||||
*/
|
||||
public class MetaPacket extends Packet250CustomPayload
|
||||
{
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
String fieldName = new ObfMapping("net/minecraft/network/packet/Packet", "packetClassToIdMap", "Ljava/util/Map;").toRuntime().s_name;
|
||||
Field field = Packet.class.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
Map<Class<? extends Packet>, Integer> packetClassToIdMap = (Map<Class<? extends Packet>, Integer>) field.get(null);
|
||||
packetClassToIdMap.put(MetaPacket.class, 250);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<Packet> packets = new ArrayList<Packet>();
|
||||
|
||||
public MetaPacket(Packet... packets)
|
||||
{
|
||||
super("", null);
|
||||
|
||||
for(Packet p : packets)
|
||||
this.packets.add(p);
|
||||
}
|
||||
|
||||
public MetaPacket(Collection<? extends Packet> packets)
|
||||
{
|
||||
this.packets.addAll(packets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readPacketData(DataInput datain)
|
||||
{
|
||||
throw new IllegalStateException("Meta packets can't be read");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePacketData(DataOutput dataout) {
|
||||
try {//TODO: fix super IOException
|
||||
//send a dummy 250
|
||||
super.writePacketData(dataout);
|
||||
|
||||
for(Packet p : packets)
|
||||
Packet.writePacket(p, dataout);
|
||||
|
||||
//adjust sent size for Packet.writePacket
|
||||
Packet.sentSize-=getPacketSize()-super.getPacketSize();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processPacket(NetHandler nethandler)
|
||||
{
|
||||
for(Packet p : packets)//Memory connection
|
||||
p.processPacket(nethandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPacketSize()
|
||||
{
|
||||
int size = 0;
|
||||
for(Packet p : packets)
|
||||
size+=p.getPacketSize()+1;
|
||||
return size;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -13,7 +13,7 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.util.EnumMovingObjectType;
|
||||
import net.minecraft.util.MovingObjectPosition.MovingObjectType;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
@@ -112,7 +112,7 @@ public class RayTracer
|
||||
MovingObjectPosition mop = rayTraceCuboid(start, end, cuboid);
|
||||
if(mop != null)
|
||||
{
|
||||
mop.typeOfHit = EnumMovingObjectType.TILE;
|
||||
mop.typeOfHit = MovingObjectType.BLOCK;
|
||||
mop.blockX = pos.x;
|
||||
mop.blockY = pos.y;
|
||||
mop.blockZ = pos.z;
|
||||
@@ -125,7 +125,7 @@ public class RayTracer
|
||||
MovingObjectPosition mop = rayTraceCuboid(start, end, cuboid);
|
||||
if(mop != null)
|
||||
{
|
||||
mop.typeOfHit = EnumMovingObjectType.ENTITY;
|
||||
mop.typeOfHit = MovingObjectType.ENTITY;
|
||||
mop.entityHit = e;
|
||||
}
|
||||
return mop;
|
||||
@@ -156,7 +156,7 @@ public class RayTracer
|
||||
MovingObjectPosition mop = rayTraceCuboids(start, end, cuboids);
|
||||
if(mop != null)
|
||||
{
|
||||
mop.typeOfHit = EnumMovingObjectType.TILE;
|
||||
mop.typeOfHit = MovingObjectType.BLOCK;
|
||||
mop.blockX = pos.x;
|
||||
mop.blockY = pos.y;
|
||||
mop.blockZ = pos.z;
|
||||
@@ -174,7 +174,7 @@ public class RayTracer
|
||||
if(mop != null)
|
||||
{
|
||||
ExtendedMOP emop = new ExtendedMOP(mop, cuboid.data, s_dist);
|
||||
emop.typeOfHit = EnumMovingObjectType.TILE;
|
||||
emop.typeOfHit = MovingObjectType.BLOCK;
|
||||
emop.blockX = pos.x;
|
||||
emop.blockY = pos.y;
|
||||
emop.blockZ = pos.z;
|
||||
@@ -185,9 +185,7 @@ public class RayTracer
|
||||
|
||||
public static MovingObjectPosition retraceBlock(World world, EntityPlayer player, int x, int y, int z)
|
||||
{
|
||||
Block block = Block.blocksList[world.getBlockId(x, y, z)];
|
||||
if(block == null)
|
||||
return null;
|
||||
Block block = world.getBlock(x, y, z);
|
||||
|
||||
Vec3 headVec = getCorrectedHeadVec(player);
|
||||
Vec3 lookVec = player.getLook(1.0F);
|
||||
@@ -217,7 +215,7 @@ public class RayTracer
|
||||
Vec3 headVec = getCorrectedHeadVec(player);
|
||||
Vec3 lookVec = player.getLook(1);
|
||||
Vec3 endVec = headVec.addVector(lookVec.xCoord * reach, lookVec.yCoord * reach, lookVec.zCoord * reach);
|
||||
return world.rayTraceBlocks_do_do(headVec, endVec, true, false);
|
||||
return world.func_147447_a(headVec, endVec, true, false, true);
|
||||
}
|
||||
|
||||
public static Vec3 getCorrectedHeadVec(EntityPlayer player)
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import codechicken.lib.lighting.LC;
|
||||
import codechicken.lib.vec.Cuboid6;
|
||||
|
||||
public class BlockRenderer
|
||||
{
|
||||
public static class BlockFace implements CCRenderState.IVertexSource
|
||||
{
|
||||
public Vertex5[] verts = new Vertex5[]{new Vertex5(), new Vertex5(), new Vertex5(), new Vertex5()};
|
||||
public LC[] lightCoords = new LC[]{new LC(), new LC(), new LC(), new LC()};
|
||||
public boolean lcComputed = false;
|
||||
public int side;
|
||||
|
||||
@Override
|
||||
public Vertex5[] getVertices() {
|
||||
return verts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getAttributes(CCRenderState.VertexAttribute<T> attr) {
|
||||
return attr == CCRenderState.lightCoordAttrib && lcComputed ? (T)lightCoords : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAttribute(CCRenderState.VertexAttribute<?> attr) {
|
||||
return attr == CCRenderState.sideAttrib || attr == CCRenderState.lightCoordAttrib && lcComputed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareVertex() {
|
||||
CCRenderState.side = side;
|
||||
}
|
||||
|
||||
public BlockFace computeLightCoords() {
|
||||
if(!lcComputed) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
lightCoords[i].compute(verts[i].vec, side);
|
||||
lcComputed = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockFace loadCuboidFace(Cuboid6 c, int side) {
|
||||
double x1 = c.min.x;
|
||||
double x2 = c.max.x;
|
||||
double y1 = c.min.y;
|
||||
double y2 = c.max.y;
|
||||
double z1 = c.min.z;
|
||||
double z2 = c.max.z;
|
||||
double u1; double u2; double v1; double v2;
|
||||
this.side = side;
|
||||
lcComputed = false;
|
||||
|
||||
switch(side) {
|
||||
case 0:
|
||||
u1 = x1; v1 = z1;
|
||||
u2 = x2; v2 = z2;
|
||||
verts[0].set(x1, y1, z2, u1, v2, 0);
|
||||
verts[1].set(x1, y1, z1, u1, v1, 0);
|
||||
verts[2].set(x2, y1, z1, u2, v1, 0);
|
||||
verts[3].set(x2, y1, z2, u2, v2, 0);
|
||||
break;
|
||||
case 1:
|
||||
u1 = x1; v1 = z1;
|
||||
u2 = x2; v2 = z2;
|
||||
verts[0].set(x2, y2, z2, u2, v2, 1);
|
||||
verts[1].set(x2, y2, z1, u2, v1, 1);
|
||||
verts[2].set(x1, y2, z1, u1, v1, 1);
|
||||
verts[3].set(x1, y2, z2, u1, v2, 1);
|
||||
break;
|
||||
case 2:
|
||||
u1 = 1-x1; v1 = 1-y2;
|
||||
u2 = 1-x2; v2 = 1-y1;
|
||||
verts[0].set(x1, y1, z1, u1, v2, 2);
|
||||
verts[1].set(x1, y2, z1, u1, v1, 2);
|
||||
verts[2].set(x2, y2, z1, u2, v1, 2);
|
||||
verts[3].set(x2, y1, z1, u2, v2, 2);
|
||||
break;
|
||||
case 3:
|
||||
u1 = x1; v1 = 1-y2;
|
||||
u2 = x2; v2 = 1-y1;
|
||||
verts[0].set(x2, y1, z2, u2, v2, 3);
|
||||
verts[1].set(x2, y2, z2, u2, v1, 3);
|
||||
verts[2].set(x1, y2, z2, u1, v1, 3);
|
||||
verts[3].set(x1, y1, z2, u1, v2, 3);
|
||||
break;
|
||||
case 4:
|
||||
u1 = z1; v1 = 1-y2;
|
||||
u2 = z2; v2 = 1-y1;
|
||||
verts[0].set(x1, y1, z2, u2, v2, 4);
|
||||
verts[1].set(x1, y2, z2, u2, v1, 4);
|
||||
verts[2].set(x1, y2, z1, u1, v1, 4);
|
||||
verts[3].set(x1, y1, z1, u1, v2, 4);
|
||||
break;
|
||||
case 5:
|
||||
u1 = 1-z1; v1 = 1-y2;
|
||||
u2 = 1-z2; v2 = 1-y1;
|
||||
verts[0].set(x2, y1, z1, u1, v2, 5);
|
||||
verts[1].set(x2, y2, z1, u1, v1, 5);
|
||||
verts[2].set(x2, y2, z2, u2, v1, 5);
|
||||
verts[3].set(x2, y1, z2, u2, v2, 5);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private static BlockFace face = new BlockFace();
|
||||
|
||||
/**
|
||||
* Renders faces of a cuboid with texture coordinates mapped to match a standard minecraft block
|
||||
* @param bounds The bounding cuboid to render
|
||||
* @param sideMask A mask of faces not to render
|
||||
*/
|
||||
public static void renderCuboid(Cuboid6 bounds, int sideMask) {
|
||||
if(sideMask == 0x3F)
|
||||
return;
|
||||
|
||||
CCRenderState.setModel(face);
|
||||
for(int s = 0; s < 6; s++)
|
||||
if((sideMask & 1<<s) == 0) {
|
||||
face.loadCuboidFace(bounds, s);
|
||||
CCRenderState.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
+195
-206
@@ -11,59 +11,96 @@ import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import codechicken.lib.lighting.LC;
|
||||
import codechicken.lib.render.uv.UV;
|
||||
import codechicken.lib.render.uv.UVTransformation;
|
||||
import codechicken.lib.render.uv.UVTranslation;
|
||||
import codechicken.lib.util.Copyable;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import codechicken.lib.lighting.CCRBModel;
|
||||
import codechicken.lib.lighting.LightModel;
|
||||
import codechicken.lib.vec.Cuboid6;
|
||||
import codechicken.lib.vec.RedundantTransformation;
|
||||
import codechicken.lib.vec.Transformation;
|
||||
import codechicken.lib.vec.TransformationList;
|
||||
import codechicken.lib.vec.Translation;
|
||||
import codechicken.lib.vec.Vector3;
|
||||
|
||||
import static codechicken.lib.vec.Rotation.*;
|
||||
|
||||
public class CCModel
|
||||
public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel>
|
||||
{
|
||||
private static class PositionNormalEntry
|
||||
{
|
||||
{
|
||||
public Vector3 pos;
|
||||
public LinkedList<Vector3> normals = new LinkedList<Vector3>();
|
||||
|
||||
|
||||
public PositionNormalEntry(Vector3 position)
|
||||
{
|
||||
pos = position;
|
||||
}
|
||||
|
||||
|
||||
public boolean positionEqual(Vector3 v)
|
||||
{
|
||||
return pos.x == v.x && pos.y == v.y && pos.z == v.z;
|
||||
}
|
||||
|
||||
|
||||
public PositionNormalEntry addNormal(Vector3 normal)
|
||||
{
|
||||
normals.add(normal);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final int vertexMode;
|
||||
public final int vp;
|
||||
public Vertex5[] verts;
|
||||
public Vector3[] normals;
|
||||
public int[] colours;
|
||||
|
||||
public ArrayList<Object> attributes = new ArrayList<Object>();
|
||||
|
||||
protected CCModel(int vertexMode)
|
||||
{
|
||||
if(vertexMode != 7 && vertexMode != 4)
|
||||
throw new IllegalArgumentException("Models must be GL_QUADS or GL_TRIANGLES");
|
||||
|
||||
|
||||
this.vertexMode = vertexMode;
|
||||
vp = vertexMode == 7 ? 4 : 3;
|
||||
}
|
||||
|
||||
|
||||
public Vector3[] normals() {
|
||||
return getAttributes(CCRenderState.normalAttrib);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vertex5[] getVertices() {
|
||||
return verts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getAttributes(CCRenderState.VertexAttribute<T> attr) {
|
||||
if(attr.attributeIndex < attributes.size())
|
||||
return (T) attributes.get(attr.attributeIndex);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAttribute(CCRenderState.VertexAttribute<?> attrib) {
|
||||
return attrib.attributeIndex < attributes.size() && attributes.get(attrib.attributeIndex) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareVertex() {
|
||||
}
|
||||
|
||||
public <T> T getOrAllocate(CCRenderState.VertexAttribute<T> attrib) {
|
||||
T array = getAttributes(attrib);
|
||||
if(array == null) {
|
||||
while(attributes.size() <= attrib.attributeIndex)
|
||||
attributes.add(null);
|
||||
attributes.set(attrib.attributeIndex, array = attrib.newArray(verts.length));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Each pixel corresponds to one unit of position when generating the model
|
||||
* @param i Vertex index to start generating at
|
||||
@@ -87,7 +124,7 @@ public class CCModel
|
||||
double y2 = y1+h;
|
||||
double z2 = z1+d;
|
||||
x1 /= f; x2 /= f; y1 /= f; y2 /= f; z1 /= f; z2 /= f;
|
||||
|
||||
|
||||
//bottom face
|
||||
u1 = (tx + d + w) / tw; v1 = (ty + d) / th;
|
||||
u2 = (tx + d*2 + w) / tw; v2 = ty / th;
|
||||
@@ -95,7 +132,7 @@ public class CCModel
|
||||
verts[i++] = new Vertex5(x1, y1, z1, u1, v1);
|
||||
verts[i++] = new Vertex5(x2, y1, z1, u2, v1);
|
||||
verts[i++] = new Vertex5(x2, y1, z2, u2, v2);
|
||||
|
||||
|
||||
//top face
|
||||
u1 = (tx + d) / tw; v1 = (ty + d) / th;
|
||||
u2 = (tx + d + w) / tw; v2 = ty / th;
|
||||
@@ -103,7 +140,7 @@ public class CCModel
|
||||
verts[i++] = new Vertex5(x2, y2, z1, u2, v1);
|
||||
verts[i++] = new Vertex5(x1, y2, z1, u1, v1);
|
||||
verts[i++] = new Vertex5(x1, y2, z2, u1, v2);
|
||||
|
||||
|
||||
//front face
|
||||
u1 = (tx + d + w) / tw; v1 = (ty + d) / th;
|
||||
u2 = (tx + d) / tw; v2 = (ty + d + h) / th;
|
||||
@@ -111,7 +148,7 @@ public class CCModel
|
||||
verts[i++] = new Vertex5(x2, y2, z1, u1, v1);
|
||||
verts[i++] = new Vertex5(x2, y1, z1, u1, v2);
|
||||
verts[i++] = new Vertex5(x1, y1, z1, u2, v2);
|
||||
|
||||
|
||||
//back face
|
||||
u1 = (tx + d*2 + w*2) / tw; v1 = (ty + d) / th;
|
||||
u2 = (tx + d*2 + w) / tw; v2 = (ty + d + h) / th;
|
||||
@@ -119,7 +156,7 @@ public class CCModel
|
||||
verts[i++] = new Vertex5(x1, y1, z2, u1, v2);
|
||||
verts[i++] = new Vertex5(x2, y1, z2, u2, v2);
|
||||
verts[i++] = new Vertex5(x2, y2, z2, u2, v1);
|
||||
|
||||
|
||||
//left face
|
||||
u1 = (tx + d) / tw; v1 = (ty + d) / th;
|
||||
u2 = (tx) / tw; v2 = (ty + d + h) / th;
|
||||
@@ -127,7 +164,7 @@ public class CCModel
|
||||
verts[i++] = new Vertex5(x1, y2, z1, u1, v1);
|
||||
verts[i++] = new Vertex5(x1, y1, z1, u1, v2);
|
||||
verts[i++] = new Vertex5(x1, y1, z2, u2, v2);
|
||||
|
||||
|
||||
//right face
|
||||
u1 = (tx + d*2 + w) / tw; v1 = (ty + d) / th;
|
||||
u2 = (tx + d + w) / tw; v2 = (ty + d + h) / th;
|
||||
@@ -135,7 +172,7 @@ public class CCModel
|
||||
verts[i++] = new Vertex5(x2, y1, z1, u2, v2);
|
||||
verts[i++] = new Vertex5(x2, y2, z1, u2, v1);
|
||||
verts[i++] = new Vertex5(x2, y2, z2, u1, v1);
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -149,7 +186,7 @@ public class CCModel
|
||||
{
|
||||
return generateBlock(i, bounds, 0);
|
||||
}
|
||||
|
||||
|
||||
public CCModel generateBlock(int i, Cuboid6 bounds, int mask)
|
||||
{
|
||||
return generateBlock(i, bounds.min.x, bounds.min.y, bounds.min.z, bounds.max.x, bounds.max.y, bounds.max.z, mask);
|
||||
@@ -175,7 +212,7 @@ public class CCModel
|
||||
public CCModel generateBlock(int i, double x1, double y1, double z1, double x2, double y2, double z2, int mask)
|
||||
{
|
||||
double u1, v1, u2, v2;
|
||||
|
||||
|
||||
if((mask&1) == 0) {//bottom face
|
||||
u1 = x1; v1 = z1;
|
||||
u2 = x2; v2 = z2;
|
||||
@@ -184,7 +221,7 @@ public class CCModel
|
||||
verts[i++] = new Vertex5(x2, y1, z1, u2, v1);
|
||||
verts[i++] = new Vertex5(x2, y1, z2, u2, v2);
|
||||
}
|
||||
|
||||
|
||||
if((mask&2) == 0) {//top face
|
||||
u1 = x1+2; v1 = z1;
|
||||
u2 = x2+2; v2 = z2;
|
||||
@@ -193,7 +230,7 @@ public class CCModel
|
||||
verts[i++] = new Vertex5(x1, y2, z1, u1, v1);
|
||||
verts[i++] = new Vertex5(x1, y2, z2, u1, v2);
|
||||
}
|
||||
|
||||
|
||||
if((mask&4) == 0) {//east face
|
||||
u1 = 1-x1+4; v1 = 1-y2;
|
||||
u2 = 1-x2+4; v2 = 1-y1;
|
||||
@@ -202,7 +239,7 @@ public class CCModel
|
||||
verts[i++] = new Vertex5(x2, y2, z1, u2, v1);
|
||||
verts[i++] = new Vertex5(x2, y1, z1, u2, v2);
|
||||
}
|
||||
|
||||
|
||||
if((mask&8) == 0) {//west face
|
||||
u1 = x1+6; v1 = 1-y2;
|
||||
u2 = x2+6; v2 = 1-y1;
|
||||
@@ -211,7 +248,7 @@ public class CCModel
|
||||
verts[i++] = new Vertex5(x1, y2, z2, u1, v1);
|
||||
verts[i++] = new Vertex5(x1, y1, z2, u1, v2);
|
||||
}
|
||||
|
||||
|
||||
if((mask&0x10) == 0) {//north face
|
||||
u1 = z1+8; v1 = 1-y2;
|
||||
u2 = z2+8; v2 = 1-y1;
|
||||
@@ -220,7 +257,7 @@ public class CCModel
|
||||
verts[i++] = new Vertex5(x1, y2, z1, u1, v1);
|
||||
verts[i++] = new Vertex5(x1, y1, z1, u1, v2);
|
||||
}
|
||||
|
||||
|
||||
if((mask&0x20) == 0) {//south face
|
||||
u1 = 1-z1+10; v1 = 1-y2;
|
||||
u2 = 1-z2+10; v2 = 1-y1;
|
||||
@@ -229,10 +266,10 @@ public class CCModel
|
||||
verts[i++] = new Vertex5(x2, y2, z2, u2, v1);
|
||||
verts[i++] = new Vertex5(x2, y1, z2, u2, v2);
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CCModel computeNormals()
|
||||
{
|
||||
return computeNormals(0, verts.length);
|
||||
@@ -249,10 +286,8 @@ public class CCModel
|
||||
{
|
||||
if(length%vp != 0 || start%vp != 0)
|
||||
throw new IllegalArgumentException("Cannot generate normals across polygons");
|
||||
|
||||
if(normals == null)
|
||||
normals = new Vector3[verts.length];
|
||||
|
||||
|
||||
Vector3[] normals = getOrAllocate(CCRenderState.normalAttrib);
|
||||
for(int k = 0; k < length; k+=vp)
|
||||
{
|
||||
int i = k + start;
|
||||
@@ -262,44 +297,47 @@ public class CCModel
|
||||
for(int d = 1; d < vp; d++)
|
||||
normals[i+d] = normals[i].copy();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes lighting using the normals and the colour 0xFFFFFF.
|
||||
* Per vert colouring will be added when needed.
|
||||
* Make sure you have generated your normals on the model first.
|
||||
* If you rotate your model after this, the lighting will no longer be valid
|
||||
* @param light The light model to calculate
|
||||
* @return The model
|
||||
*/
|
||||
public CCModel computeLighting(LightModel light)
|
||||
{
|
||||
if(colours == null)
|
||||
setColour(-1);
|
||||
for(int k = 0; k < verts.length; k++)
|
||||
colours[k] = light.apply(colours[k], normals[k]);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CCModel setColour(int c)
|
||||
{
|
||||
if(colours == null)
|
||||
colours = new int[verts.length];
|
||||
for(int k = 0; k < verts.length; k++)
|
||||
colours[k] = c;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning, only use this if you NEED to be identical to MC's light model, it's hideous.
|
||||
* Computes lighting using the normals add a light model
|
||||
* If the model is rotated, the lighting will no longer be valid
|
||||
* @return The model
|
||||
*/
|
||||
public CCRBModel withMCLighting()
|
||||
public CCModel computeLighting(LightModel light)
|
||||
{
|
||||
return new CCRBModel(this);
|
||||
Vector3[] normals = normals();
|
||||
int[] colours = getAttributes(CCRenderState.colourAttrib);
|
||||
if(colours == null) {
|
||||
setColour(-1);
|
||||
colours = getAttributes(CCRenderState.colourAttrib);
|
||||
}
|
||||
for(int k = 0; k < verts.length; k++)
|
||||
colours[k] = light.apply(colours[k], normals[k]);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CCModel setColour(int c)
|
||||
{
|
||||
int[] colours = getOrAllocate(CCRenderState.colourAttrib);
|
||||
Arrays.fill(colours, c);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the minecraft lighting coordinates for use with a LightMatrix
|
||||
* @return The model
|
||||
*/
|
||||
public CCModel computeLightCoords() {
|
||||
LC[] lcs = getOrAllocate(CCRenderState.lightCoordAttrib);
|
||||
Vector3[] normals = normals();
|
||||
for(int i = 0; i < verts.length; i++)
|
||||
lcs[i] = new LC().compute(verts[i].vec, normals[i]);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Averages all normals at the same position to produce a smooth lighting effect.
|
||||
* @return The model
|
||||
@@ -307,6 +345,7 @@ public class CCModel
|
||||
public CCModel smoothNormals()
|
||||
{
|
||||
ArrayList<PositionNormalEntry> map = new ArrayList<PositionNormalEntry>();
|
||||
Vector3[] normals = normals();
|
||||
nextvert: for(int k = 0; k < verts.length; k++)
|
||||
{
|
||||
Vector3 vec = verts[k].vec;
|
||||
@@ -316,24 +355,24 @@ public class CCModel
|
||||
e.addNormal(normals[k]);
|
||||
continue nextvert;
|
||||
}
|
||||
|
||||
|
||||
map.add(new PositionNormalEntry(vec).addNormal(normals[k]));
|
||||
}
|
||||
|
||||
|
||||
for(PositionNormalEntry e : map)
|
||||
{
|
||||
if(e.normals.size() <= 1)
|
||||
continue;
|
||||
|
||||
|
||||
Vector3 new_n = new Vector3();
|
||||
for(Vector3 n : e.normals)
|
||||
new_n.add(n);
|
||||
|
||||
|
||||
new_n.normalize();
|
||||
for(Vector3 n : e.normals)
|
||||
n.set(new_n);
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -341,134 +380,93 @@ public class CCModel
|
||||
{
|
||||
for(int k = 0; k < verts.length; k++)
|
||||
verts[k].apply(t);
|
||||
|
||||
|
||||
Vector3[] normals = normals();
|
||||
if(normals != null)
|
||||
for(int k = 0; k < normals.length; k++)
|
||||
t.applyN(normals[k]);
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CCModel apply(IUVTransformation uvt)
|
||||
public CCModel apply(UVTransformation uvt)
|
||||
{
|
||||
for(int k = 0; k < verts.length; k++)
|
||||
verts[k].apply(uvt);
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CCModel expand(int extraVerts)
|
||||
{
|
||||
int newLen = verts.length+extraVerts;
|
||||
verts = Arrays.copyOf(verts, newLen);
|
||||
if(normals != null)
|
||||
normals = Arrays.copyOf(normals, newLen);
|
||||
if(colours != null)
|
||||
colours = Arrays.copyOf(colours, newLen);
|
||||
for(int i = 0; i < attributes.size(); i++)
|
||||
if(attributes.get(i) != null)
|
||||
attributes.set(i, CCRenderState.copyOf((CCRenderState.VertexAttribute)CCRenderState.getAttribute(i), attributes.get(i), newLen));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public void render()
|
||||
{
|
||||
render(0, verts.length, null, null, null);
|
||||
}
|
||||
|
||||
|
||||
public void render(double x, double y, double z, double u, double v)
|
||||
{
|
||||
render(new Translation(new Vector3(x, y, z)), new UVTranslation(u, v));
|
||||
render(new Vector3(x, y, z).translation(), new UVTranslation(u, v));
|
||||
}
|
||||
|
||||
public void render(double x, double y, double z, IUVTransformation u)
|
||||
public void render(double x, double y, double z, UVTransformation u)
|
||||
{
|
||||
render(new Translation(new Vector3(x, y, z)), u);
|
||||
render(new Vector3(x, y, z).translation(), u);
|
||||
}
|
||||
|
||||
public void render(Transformation t, double u, double v)
|
||||
{
|
||||
render(t, new UVTranslation(u, v));
|
||||
}
|
||||
|
||||
public void render(Transformation t, IUVTransformation u)
|
||||
|
||||
public void render(CCRenderState.IVertexOperation... ops)
|
||||
{
|
||||
render(t, u, ColourModifier.instance);
|
||||
}
|
||||
|
||||
public void render(Transformation t, IUVTransformation u, IVertexModifier m)
|
||||
{
|
||||
render(0, verts.length, t, u, m);
|
||||
render(0, verts.length, ops);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders vertices start through start+length-1 of the model
|
||||
* @param start The first vertex to render
|
||||
* @param length The number of vertices to render
|
||||
* @param t The transformation to apply to the mat
|
||||
* @param u The u texture offset
|
||||
* @param v The v texture offset
|
||||
* @param start The first vertex index to render
|
||||
* @param end The vertex index to render until
|
||||
* @param ops Operations to apply
|
||||
*/
|
||||
public void render(int start, int length, Transformation t, IUVTransformation u, IVertexModifier m)
|
||||
public void render(int start, int end, CCRenderState.IVertexOperation... ops)
|
||||
{
|
||||
boolean drawNormal = CCRenderState.useNormals() && normals != null;
|
||||
boolean computeNormal = drawNormal || m != null && m.needsNormals();
|
||||
Vector3 normal = new Vector3();
|
||||
Vertex5 vert;
|
||||
Vector3 vec = new Vector3();
|
||||
UV uv = new UV();
|
||||
Tessellator tess = Tessellator.instance;
|
||||
for(int k = 0; k < length; k++)
|
||||
{
|
||||
int i = start+k;
|
||||
if(computeNormal)
|
||||
{
|
||||
if(t != null)
|
||||
t.applyN(normal.set(normals[i]));
|
||||
else
|
||||
normal = normals[i];
|
||||
|
||||
if(drawNormal)
|
||||
tess.setNormal((float)normal.x, (float)normal.y, (float)normal.z);
|
||||
}
|
||||
|
||||
vert = verts[i];
|
||||
if(t != null)
|
||||
t.apply(vec.set(vert.vec));
|
||||
else
|
||||
vec = vert.vec;
|
||||
|
||||
if(u != null)
|
||||
u.transform(uv.set(vert.uv));
|
||||
else
|
||||
uv = vert.uv;
|
||||
|
||||
if(m != null)
|
||||
m.applyModifiers(this, tess, vec, uv, normal, i);
|
||||
|
||||
tess.addVertexWithUV(vec.x, vec.y, vec.z, uv.u, uv.v);
|
||||
}
|
||||
CCRenderState.setPipeline(this, start, end, ops);
|
||||
CCRenderState.render();
|
||||
}
|
||||
|
||||
|
||||
public static CCModel quadModel(int numVerts)
|
||||
{
|
||||
return newModel(7, numVerts);
|
||||
}
|
||||
|
||||
|
||||
public static CCModel triModel(int numVerts)
|
||||
{
|
||||
return newModel(4, numVerts);
|
||||
}
|
||||
|
||||
|
||||
public static CCModel newModel(int vertexMode, int numVerts)
|
||||
{
|
||||
CCModel model = newModel(vertexMode);
|
||||
model.verts = new Vertex5[numVerts];
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
public static CCModel newModel(int vertexMode)
|
||||
{
|
||||
return new CCModel(vertexMode);
|
||||
}
|
||||
|
||||
|
||||
public static double[] parseDoubles(String s, String token)
|
||||
{
|
||||
String[] as = s.split(token);
|
||||
@@ -482,7 +480,7 @@ public class CCModel
|
||||
{
|
||||
if(!b) throw new IllegalArgumentException(err);
|
||||
}
|
||||
|
||||
|
||||
public static void assertMatch(Matcher m, String s)
|
||||
{
|
||||
m.reset(s);
|
||||
@@ -497,7 +495,7 @@ public class CCModel
|
||||
public static final Matcher uvwMatcher = uvwPattern.matcher("");
|
||||
public static final Matcher normalMatcher = normalPattern.matcher("");
|
||||
public static final Matcher polyMatcher = polyPattern.matcher("");
|
||||
|
||||
|
||||
/**
|
||||
* Parses vertices, texture coords, normals and polygons from a WaveFront Obj file
|
||||
* @param input An input stream to a obj file
|
||||
@@ -511,14 +509,14 @@ public class CCModel
|
||||
if(coordSystem == null)
|
||||
coordSystem = new RedundantTransformation();
|
||||
int vp = vertexMode == 7 ? 4 : 3;
|
||||
|
||||
|
||||
HashMap<String, CCModel> modelMap = new HashMap<String, CCModel>();
|
||||
ArrayList<Vector3> verts = new ArrayList<Vector3>();
|
||||
ArrayList<Vector3> uvs = new ArrayList<Vector3>();
|
||||
ArrayList<Vector3> normals = new ArrayList<Vector3>();
|
||||
ArrayList<int[]> polys = new ArrayList<int[]>();
|
||||
String modelName = "unnamed";
|
||||
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
|
||||
|
||||
String line;
|
||||
@@ -527,7 +525,7 @@ public class CCModel
|
||||
line = line.replaceAll("\\s+", " ").trim();
|
||||
if(line.startsWith("#") || line.length() == 0)
|
||||
continue;
|
||||
|
||||
|
||||
if(line.startsWith("v "))
|
||||
{
|
||||
assertMatch(vertMatcher, line);
|
||||
@@ -584,13 +582,13 @@ public class CCModel
|
||||
modelName = line.substring(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!polys.isEmpty())
|
||||
modelMap.put(modelName, createModel(verts, uvs, normals, vertexMode, polys));
|
||||
|
||||
|
||||
return modelMap;
|
||||
}
|
||||
|
||||
|
||||
public static void triangulate(List<int[]> polys, int[][] polyVerts)
|
||||
{
|
||||
for(int i = 2; i < polyVerts.length; i++)
|
||||
@@ -600,7 +598,7 @@ public class CCModel
|
||||
polys.add(polyVerts[i-1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void quadulate(List<int[]> polys, int[][] polyVerts)
|
||||
{
|
||||
if(polyVerts.length == 4)
|
||||
@@ -624,7 +622,7 @@ public class CCModel
|
||||
|
||||
/**
|
||||
* Parses vertices, texture coords, normals and polygons from a WaveFront Obj file
|
||||
* @param s The name of the obj resource
|
||||
* @param res The resource for the obj file
|
||||
* @return A map of group names to models
|
||||
*/
|
||||
public static Map<String, CCModel> parseObjModels(ResourceLocation res)
|
||||
@@ -642,7 +640,7 @@ public class CCModel
|
||||
try
|
||||
{
|
||||
return parseObjModels(
|
||||
Minecraft.getMinecraft().getResourceManager().getResource(res).getInputStream(),
|
||||
Minecraft.getMinecraft().getResourceManager().getResource(res).getInputStream(),
|
||||
4, coordSystem);
|
||||
}
|
||||
catch(IOException e)
|
||||
@@ -650,10 +648,10 @@ public class CCModel
|
||||
throw new RuntimeException("failed to load model: "+res, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses vertices, texture coords, normals and polygons from a WaveFront Obj file
|
||||
* @param s The name of the obj resource
|
||||
* @param res The resource for the obj file
|
||||
* @param vertexMode The vertex mode to create the model for (GL_TRIANGLES or GL_QUADS)
|
||||
* @param coordSystem The cooridnate system transformation to apply
|
||||
* @return A map of group names to models
|
||||
@@ -663,7 +661,7 @@ public class CCModel
|
||||
try
|
||||
{
|
||||
return parseObjModels(
|
||||
Minecraft.getMinecraft().getResourceManager().getResource(res).getInputStream(),
|
||||
Minecraft.getMinecraft().getResourceManager().getResource(res).getInputStream(),
|
||||
vertexMode, coordSystem);
|
||||
}
|
||||
catch(Exception e)
|
||||
@@ -677,12 +675,12 @@ public class CCModel
|
||||
int vp = vertexMode == 7 ? 4 : 3;
|
||||
if(polys.size() < vp || polys.size()%vp != 0)
|
||||
throw new IllegalArgumentException("Invalid number of vertices for model: "+polys.size());
|
||||
|
||||
|
||||
boolean hasNormals = polys.get(0)[2] > 0;
|
||||
CCModel model = CCModel.newModel(vertexMode, polys.size());
|
||||
if(hasNormals)
|
||||
model.normals = new Vector3[polys.size()];
|
||||
|
||||
model.getOrAllocate(CCRenderState.normalAttrib);
|
||||
|
||||
for(int i = 0; i < polys.size(); i++)
|
||||
{
|
||||
int[] ai = polys.get(i);
|
||||
@@ -690,12 +688,12 @@ public class CCModel
|
||||
Vector3 uv = ai[1] <= 0 ? new Vector3() : uvs.get(ai[1]-1).copy();
|
||||
if(ai[2] > 0 != hasNormals)
|
||||
throw new IllegalArgumentException("Normals are an all or nothing deal here.");
|
||||
|
||||
|
||||
model.verts[i] = new Vertex5(vert, uv.x, uv.y);
|
||||
if(hasNormals)
|
||||
model.normals[i] = normals.get(ai[2]-1).copy();
|
||||
model.normals()[i] = normals.get(ai[2]-1).copy();
|
||||
}
|
||||
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -726,7 +724,7 @@ public class CCModel
|
||||
int vStart = verts.size();
|
||||
int uStart = uvs.size();
|
||||
int nStart = normals.size();
|
||||
boolean hasNormals = m.normals != null;
|
||||
boolean hasNormals = m.normals() != null;
|
||||
polys.clear();
|
||||
|
||||
for(int i = 0; i < m.verts.length; i++) {
|
||||
@@ -734,7 +732,7 @@ public class CCModel
|
||||
ia[0] = addIndex(verts, m.verts[i].vec);
|
||||
ia[1] = addIndex(uvs, m.verts[i].uv);
|
||||
if(hasNormals)
|
||||
ia[2] = addIndex(normals, m.normals[i]);
|
||||
ia[2] = addIndex(normals, m.normals()[i]);
|
||||
polys.add(ia);
|
||||
}
|
||||
|
||||
@@ -788,7 +786,7 @@ public class CCModel
|
||||
{
|
||||
uv.add(verts[k+i].uv);
|
||||
}
|
||||
uv.mul(1D/vp);
|
||||
uv.multiply(1D/vp);
|
||||
for(int i = 0; i < vp; i++)
|
||||
{
|
||||
Vertex5 vert = verts[k+i];
|
||||
@@ -798,7 +796,7 @@ public class CCModel
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param side1 The side of this model
|
||||
* @param side2 The side of the new model
|
||||
@@ -811,30 +809,18 @@ public class CCModel
|
||||
copy(this, 0, model, 0, model.verts.length);
|
||||
return model.apply(new TransformationList(sideRotations[side1].inverse(), sideRotations[side2]).at(point));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copies length vertices and normals
|
||||
*/
|
||||
public static void copy(CCModel src, int srcpos, CCModel dest, int destpos, int length)
|
||||
public static void copy(CCModel src, int srcpos, CCModel dst, int destpos, int length)
|
||||
{
|
||||
for(int k = 0; k < length; k++)
|
||||
dest.verts[destpos+k] = src.verts[srcpos+k].copy();
|
||||
|
||||
if(src.normals != null)
|
||||
{
|
||||
if(dest.normals == null)
|
||||
dest.normals = new Vector3[dest.verts.length];
|
||||
dst.verts[destpos+k] = src.verts[srcpos+k].copy();
|
||||
|
||||
for(int k = 0; k < length; k++)
|
||||
dest.normals[destpos+k] = src.normals[srcpos+k].copy();
|
||||
}
|
||||
|
||||
if(src.colours != null)
|
||||
{
|
||||
if(dest.colours == null)
|
||||
dest.colours = new int[dest.verts.length];
|
||||
System.arraycopy(src.colours, srcpos, dest.colours, destpos, length);
|
||||
}
|
||||
for(int i = 0; i < src.attributes.size(); i++)
|
||||
if(src.attributes.get(i) != null)
|
||||
CCRenderState.arrayCopy(src.attributes.get(i), srcpos, dst.getOrAllocate(CCRenderState.getAttribute(i)), destpos, length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -849,11 +835,11 @@ public class CCModel
|
||||
{
|
||||
if(s == side)
|
||||
continue;
|
||||
|
||||
|
||||
models[s] = models[side].sidedCopy(side, s, point);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate models rotated to the other 3 horizontal of the block
|
||||
* @param models An array of 4 models
|
||||
@@ -870,12 +856,12 @@ public class CCModel
|
||||
models[s] = models[side].sidedCopy(side, s, point);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public CCModel backfacedCopy()
|
||||
{
|
||||
return generateBackface(this, 0, copy(), 0, verts.length);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates copies of faces with clockwise vertices
|
||||
* @return The model
|
||||
@@ -885,7 +871,7 @@ public class CCModel
|
||||
int vp = src.vp;
|
||||
if(srcpos%vp != 0 || destpos%vp != 0 || length%vp != 0)
|
||||
throw new IllegalArgumentException("Vertices do not align with polygons");
|
||||
|
||||
|
||||
int[][] o = new int[][]{{0, 0}, {1, vp-1}, {2, vp-2}, {3, vp-3}};
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
@@ -894,10 +880,12 @@ public class CCModel
|
||||
int di = destpos+b+o[d][1];
|
||||
int si = srcpos+b+o[d][0];
|
||||
dst.verts[di] = src.verts[si].copy();
|
||||
if(src.normals != null && src.normals[si] != null)
|
||||
dst.normals[di] = src.normals[si].copy().negate();
|
||||
if(src.colours != null)
|
||||
dst.colours[di] = src.colours[si];
|
||||
for(int a = 0; a < src.attributes.size(); a++)
|
||||
if(src.attributes.get(a) != null)
|
||||
CCRenderState.arrayCopy(src.attributes.get(a), si, dst.getOrAllocate(CCRenderState.getAttribute(a)), di, 1);
|
||||
|
||||
if(dst.normals() != null && dst.normals()[di] != null)
|
||||
dst.normals()[di].negate();
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
@@ -911,15 +899,15 @@ public class CCModel
|
||||
if(verts.length%(6*vp) != 0)
|
||||
throw new IllegalArgumentException("Invalid number of vertices for sided part generation");
|
||||
int length = verts.length/6;
|
||||
|
||||
|
||||
for(int s = 0; s < 6; s++)
|
||||
{
|
||||
if(s == side)
|
||||
continue;
|
||||
|
||||
|
||||
generateSidedPart(side, s, point, length*side, length*s, length);
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -932,7 +920,7 @@ public class CCModel
|
||||
if(verts.length%(4*vp) != 0)
|
||||
throw new IllegalArgumentException("Invalid number of vertices for sided part generation");
|
||||
int length = verts.length/4;
|
||||
|
||||
|
||||
for(int s = 2; s < 6; s++)
|
||||
{
|
||||
if(s == side)
|
||||
@@ -940,7 +928,7 @@ public class CCModel
|
||||
|
||||
generateSidedPart(side, s, point, length*(side-2), length*(s-2), length);
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -962,13 +950,14 @@ public class CCModel
|
||||
verts[destpos+k] = verts[srcpos+k].copy();
|
||||
verts[destpos+k].vec.apply(t);
|
||||
}
|
||||
|
||||
|
||||
Vector3[] normals = normals();
|
||||
if(normals != null)
|
||||
for(int k = 0; k < length; k++) {
|
||||
normals[destpos+k] = normals[srcpos+k].copy();
|
||||
t.applyN(normals[destpos+k]);
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -976,7 +965,7 @@ public class CCModel
|
||||
{
|
||||
if(models.isEmpty())
|
||||
return null;
|
||||
|
||||
|
||||
int numVerts = 0;
|
||||
int vertexMode = -1;
|
||||
for(CCModel model : models)
|
||||
@@ -985,10 +974,10 @@ public class CCModel
|
||||
vertexMode = model.vertexMode;
|
||||
if(vertexMode != model.vertexMode)
|
||||
throw new IllegalArgumentException("Cannot combine models with different vertex modes");
|
||||
|
||||
|
||||
numVerts+=model.verts.length;
|
||||
}
|
||||
|
||||
|
||||
CCModel c_model = newModel(vertexMode, numVerts);
|
||||
int i = 0;
|
||||
for(CCModel model : models)
|
||||
@@ -996,7 +985,7 @@ public class CCModel
|
||||
copy(model, 0, c_model, i, model.verts.length);
|
||||
i+=model.verts.length;
|
||||
}
|
||||
|
||||
|
||||
return c_model;
|
||||
}
|
||||
|
||||
@@ -1013,7 +1002,7 @@ public class CCModel
|
||||
copy(this, 0, model, 0, verts.length);
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The average of all vertices, for bones.
|
||||
*/
|
||||
@@ -1025,13 +1014,13 @@ public class CCModel
|
||||
v.multiply(1/(double)verts.length);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
public CCModel zOffset(Cuboid6 offsets)
|
||||
{
|
||||
for(int k = 0; k < verts.length; k++)
|
||||
{
|
||||
Vertex5 vert = verts[k];
|
||||
Vector3 normal = normals[k];
|
||||
Vector3 normal = normals()[k];
|
||||
switch(findSide(normal))
|
||||
{
|
||||
case 0:
|
||||
@@ -1056,7 +1045,7 @@ public class CCModel
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public static int findSide(Vector3 normal)
|
||||
{
|
||||
if(normal.y <=-0.99) return 0;
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import codechicken.lib.render.CCRenderState.IVertexOperation;
|
||||
import codechicken.lib.render.CCRenderState.VertexAttribute;
|
||||
|
||||
public class CCRenderPipeline
|
||||
{
|
||||
public class PipelineBuilder
|
||||
{
|
||||
public PipelineBuilder add(IVertexOperation op) {
|
||||
ops.add(op);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PipelineBuilder add(IVertexOperation... ops) {
|
||||
for(int i = 0; i < ops.length; i++)
|
||||
CCRenderPipeline.this.ops.add(ops[i]);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void build() {
|
||||
rebuild();
|
||||
}
|
||||
|
||||
public void render() {
|
||||
rebuild();
|
||||
CCRenderState.render();
|
||||
}
|
||||
}
|
||||
|
||||
private class PipelineNode
|
||||
{
|
||||
public ArrayList<PipelineNode> deps = new ArrayList<PipelineNode>();
|
||||
public IVertexOperation op;
|
||||
|
||||
public void add() {
|
||||
if(op == null)
|
||||
return;
|
||||
|
||||
for(int i = 0; i < deps.size(); i++)
|
||||
deps.get(i).add();
|
||||
deps.clear();
|
||||
sorted.add(op);
|
||||
op = null;
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<VertexAttribute> attribs = new ArrayList<VertexAttribute>();
|
||||
private ArrayList<IVertexOperation> ops = new ArrayList<IVertexOperation>();
|
||||
private ArrayList<PipelineNode> nodes = new ArrayList<PipelineNode>();
|
||||
private ArrayList<IVertexOperation> sorted = new ArrayList<IVertexOperation>();
|
||||
private PipelineNode loading;
|
||||
private PipelineBuilder builder = new PipelineBuilder();
|
||||
|
||||
public void setPipeline(IVertexOperation... ops) {
|
||||
this.ops.clear();
|
||||
for(int i = 0; i < ops.length; i++)
|
||||
this.ops.add(ops[i]);
|
||||
rebuild();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
ops.clear();
|
||||
unbuild();
|
||||
}
|
||||
|
||||
private void unbuild() {
|
||||
for(int i = 0; i < attribs.size(); i++)
|
||||
attribs.get(i).active = false;
|
||||
attribs.clear();
|
||||
sorted.clear();
|
||||
}
|
||||
|
||||
public void rebuild() {
|
||||
if(ops.isEmpty() || CCRenderState.model == null)
|
||||
return;
|
||||
|
||||
//ensure enough nodes for all ops
|
||||
while(nodes.size() < CCRenderState.operationCount())
|
||||
nodes.add(new PipelineNode());
|
||||
unbuild();
|
||||
|
||||
if(CCRenderState.useNormals)
|
||||
addAttribute(CCRenderState.normalAttrib);
|
||||
if(CCRenderState.baseColour != -1 || CCRenderState.alphaOverride >= 0)
|
||||
addAttribute(CCRenderState.colourAttrib);
|
||||
else if(CCRenderState.hasColour)
|
||||
CCRenderState.setColour(-1);
|
||||
|
||||
for(int i = 0; i < ops.size(); i++) {
|
||||
IVertexOperation op = ops.get(i);
|
||||
loading = nodes.get(op.operationID());
|
||||
boolean loaded = op.load();
|
||||
if(loaded)
|
||||
loading.op = op;
|
||||
|
||||
if(op instanceof VertexAttribute)
|
||||
if(loaded)
|
||||
attribs.add((VertexAttribute)op);
|
||||
else
|
||||
((VertexAttribute)op).active = false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < nodes.size(); i++)
|
||||
nodes.get(i).add();
|
||||
}
|
||||
|
||||
public void addRequirement(int opRef) {
|
||||
loading.deps.add(nodes.get(opRef));
|
||||
}
|
||||
|
||||
public void addDependency(VertexAttribute attrib) {
|
||||
loading.deps.add(nodes.get(attrib.operationID()));
|
||||
addAttribute(attrib);
|
||||
}
|
||||
|
||||
public void addAttribute(VertexAttribute attrib) {
|
||||
if(!attrib.active) {
|
||||
ops.add(attrib);
|
||||
attrib.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void operate() {
|
||||
for(int i = 0; i < sorted.size(); i++)
|
||||
sorted.get(i).operate();
|
||||
}
|
||||
|
||||
public PipelineBuilder builder() {
|
||||
ops.clear();
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -1,147 +1,383 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import codechicken.lib.colour.ColourRGBA;
|
||||
import net.minecraft.block.Block;
|
||||
import codechicken.lib.lighting.LC;
|
||||
import codechicken.lib.lighting.LightMatrix;
|
||||
import codechicken.lib.util.Copyable;
|
||||
import codechicken.lib.vec.Rotation;
|
||||
import codechicken.lib.vec.Transformation;
|
||||
import codechicken.lib.vec.Vector3;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The core of the CodeChickenLib render system.
|
||||
* Rendering operations are written to avoid object allocations by reusing static variables.
|
||||
*/
|
||||
public class CCRenderState
|
||||
{
|
||||
private static boolean useNormals;
|
||||
private static boolean hasBrightness;
|
||||
private static int brightness;
|
||||
private static boolean useModelColours;
|
||||
private static int colour;
|
||||
private static boolean hasColour;
|
||||
private static int alpha;
|
||||
private static boolean alphaOverride;
|
||||
|
||||
public static void useNormals(boolean b)
|
||||
{
|
||||
useNormals = b;
|
||||
}
|
||||
|
||||
public static boolean useNormals()
|
||||
{
|
||||
return useNormals;
|
||||
}
|
||||
|
||||
public static void useModelColours(boolean b)
|
||||
{
|
||||
useModelColours = b;
|
||||
{
|
||||
private static int nextOperationIndex;
|
||||
|
||||
public static int registerOperation() {
|
||||
return nextOperationIndex++;
|
||||
}
|
||||
|
||||
public static boolean useModelColours()
|
||||
{
|
||||
return useModelColours;
|
||||
}
|
||||
|
||||
public static void setAlpha(int a)
|
||||
{
|
||||
alpha = a;
|
||||
alphaOverride = true;
|
||||
}
|
||||
|
||||
public static void clearAlphaOverride()
|
||||
{
|
||||
alphaOverride = false;
|
||||
}
|
||||
|
||||
public static void vertexColour(int c)
|
||||
{
|
||||
if(alphaOverride)
|
||||
setColour(c&0xFFFFFF00|alpha);
|
||||
else
|
||||
setColour(c);
|
||||
public static int operationCount() {
|
||||
return nextOperationIndex;
|
||||
}
|
||||
|
||||
public static void vertexColour(int r, int g, int b, int a)
|
||||
/**
|
||||
* Represents an operation to be run for each vertex that operates on and modifies the current state
|
||||
*/
|
||||
public static interface IVertexOperation
|
||||
{
|
||||
if(alphaOverride)
|
||||
Tessellator.instance.setColorRGBA(r, g, b, alpha);
|
||||
else
|
||||
Tessellator.instance.setColorRGBA(r, g, b, a);
|
||||
}
|
||||
|
||||
public static void setBrightness(IBlockAccess world, int x, int y, int z)
|
||||
{
|
||||
Block block = Block.blocksList[world.getBlockId(x, y, z)];
|
||||
setBrightness(block == null ? world.getLightBrightnessForSkyBlocks(x, y, z, 0) : block.getMixedBrightnessForBlock(world, x, y, z));
|
||||
setColour(0xFFFFFFFF);
|
||||
/**
|
||||
* Load any required references and add dependencies to the pipeline based on the current model (may be null)
|
||||
* Return false if this operation is redundant in the pipeline with the given model
|
||||
*/
|
||||
public boolean load();
|
||||
|
||||
/**
|
||||
* Perform the operation on the current render state
|
||||
*/
|
||||
public void operate();
|
||||
|
||||
/**
|
||||
* Get the unique id representing this type of operation. Duplicate operation IDs within the pipeline may have unexpected results.
|
||||
* ID shoulld be obtained from CCRenderState.registerOperation() and stored in a static variable
|
||||
*/
|
||||
public int operationID();
|
||||
}
|
||||
|
||||
public static void setBrightness(int b)
|
||||
{
|
||||
hasBrightness = true;
|
||||
Tessellator.instance.setBrightness(brightness = b);
|
||||
}
|
||||
|
||||
public static void setColourOpaque(int c)
|
||||
{
|
||||
setColour(c << 8 | 0xFF);
|
||||
}
|
||||
|
||||
//RGBA
|
||||
public static void setColour(int c)
|
||||
{
|
||||
hasColour = true;
|
||||
colour = c;
|
||||
Tessellator.instance.setColorRGBA(colour >> 24 & 0xFF, colour >> 16 & 0xFF, colour >> 8 & 0xFF, colour & 0xFF);
|
||||
}
|
||||
|
||||
public static void changeTexture(String texture)
|
||||
{
|
||||
changeTexture(new ResourceLocation(texture));
|
||||
}
|
||||
|
||||
public static void changeTexture(ResourceLocation texture)
|
||||
{
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
|
||||
private static ArrayList<VertexAttribute<?>> vertexAttributes = new ArrayList<VertexAttribute<?>>();
|
||||
private static int registerVertexAttribute(VertexAttribute<?> attr) {
|
||||
vertexAttributes.add(attr);
|
||||
return vertexAttributes.size()-1;
|
||||
}
|
||||
|
||||
public static void apply()
|
||||
public static VertexAttribute<?> getAttribute(int index) {
|
||||
return vertexAttributes.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Management class for a vertex attrute such as colour, normal etc
|
||||
* This class should handle the loading of the attrute from an array provided by IVertexSource.getAttributes or the computation of this attrute from others
|
||||
* @param <T> The array type for this attrute eg. int[], Vector3[]
|
||||
*/
|
||||
public static abstract class VertexAttribute<T> implements IVertexOperation
|
||||
{
|
||||
public final int attributeIndex = registerVertexAttribute(this);
|
||||
private final int operationIndex = registerOperation();
|
||||
/**
|
||||
* Set to true when the attrute is part of the pipeline. Should only be managed by CCRenderState when constructing the pipeline
|
||||
*/
|
||||
public boolean active = false;
|
||||
|
||||
/**
|
||||
* Construct a new array for storage of vertex attrutes in a model
|
||||
*/
|
||||
public abstract T newArray(int length);
|
||||
|
||||
@Override
|
||||
public int operationID() {
|
||||
return operationIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public static void arrayCopy(Object src, int srcPos, Object dst, int destPos, int length) {
|
||||
System.arraycopy(src, srcPos, dst, destPos, length);
|
||||
if(dst instanceof Copyable[]) {
|
||||
Object[] oa = (Object[])dst;
|
||||
Copyable<Object>[] c = (Copyable[])dst;
|
||||
for(int i = destPos; i < destPos+length; i++)
|
||||
if(c[i] != null)
|
||||
oa[i] = c[i].copy();
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T copyOf(VertexAttribute<T> attr, T src, int length) {
|
||||
T dst = attr.newArray(length);
|
||||
arrayCopy(src, 0, dst, 0, length);
|
||||
return dst;
|
||||
}
|
||||
|
||||
public static interface IVertexSource
|
||||
{
|
||||
public Vertex5[] getVertices();
|
||||
|
||||
/**
|
||||
* Gets an array of vertex attrutes
|
||||
* @param attr The vertex attrute to get
|
||||
* @param <T> The attrute array type
|
||||
* @return An array, or null if not computed
|
||||
*/
|
||||
public <T> T getAttributes(VertexAttribute<T> attr);
|
||||
|
||||
/**
|
||||
* @return True if the specified attrute is provided by this model, either by returning an array from getAttributes or by setting the state in prepareVertex
|
||||
*/
|
||||
public boolean hasAttribute(VertexAttribute<?> attr);
|
||||
|
||||
/**
|
||||
* Callback to set CCRenderState for a vertex before the pipeline runs
|
||||
*/
|
||||
public void prepareVertex();
|
||||
}
|
||||
|
||||
public static VertexAttribute<Vector3[]> normalAttrib = new VertexAttribute<Vector3[]>() {
|
||||
private Vector3[] normalRef;
|
||||
|
||||
@Override
|
||||
public Vector3[] newArray(int length) {
|
||||
return new Vector3[length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean load() {
|
||||
normalRef = model.getAttributes(this);
|
||||
if(model.hasAttribute(this))
|
||||
return normalRef != null;
|
||||
|
||||
if(model.hasAttribute(sideAttrib)) {
|
||||
pipeline.addDependency(sideAttrib);
|
||||
return true;
|
||||
}
|
||||
throw new IllegalStateException("Normals requested but neither normal or side attrutes are provided by the model");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate() {
|
||||
if(normalRef != null)
|
||||
setNormal(normalRef[vertexIndex]);
|
||||
else
|
||||
setNormal(Rotation.axes[side]);
|
||||
}
|
||||
};
|
||||
public static VertexAttribute<int[]> colourAttrib = new VertexAttribute<int[]>() {
|
||||
private int[] colourRef;
|
||||
|
||||
@Override
|
||||
public int[] newArray(int length) {
|
||||
return new int[length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean load() {
|
||||
colourRef = model.getAttributes(this);
|
||||
return colourRef != null || !model.hasAttribute(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate() {
|
||||
if(colourRef != null)
|
||||
setColour(ColourRGBA.multiply(baseColour, colourRef[vertexIndex]));
|
||||
else
|
||||
setColour(baseColour);
|
||||
}
|
||||
};
|
||||
public static VertexAttribute<int[]> sideAttrib = new VertexAttribute<int[]>() {
|
||||
private int[] sideRef;
|
||||
|
||||
@Override
|
||||
public int[] newArray(int length) {
|
||||
return new int[length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean load() {
|
||||
sideRef = model.getAttributes(this);
|
||||
if(model.hasAttribute(this))
|
||||
return sideRef != null;
|
||||
|
||||
pipeline.addDependency(normalAttrib);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate() {
|
||||
if(sideRef != null)
|
||||
side = sideRef[vertexIndex];
|
||||
else
|
||||
side = CCModel.findSide(normal);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Uses the position of the lightmatrix to compute LC if not provided
|
||||
*/
|
||||
public static VertexAttribute<LC[]> lightCoordAttrib = new VertexAttribute<LC[]>() {
|
||||
private LC[] lcRef;
|
||||
private Vector3 vec = new Vector3();//for computation
|
||||
private Vector3 pos = new Vector3();
|
||||
|
||||
@Override
|
||||
public LC[] newArray(int length) {
|
||||
return new LC[length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean load() {
|
||||
lcRef = model.getAttributes(this);
|
||||
if(model.hasAttribute(this))
|
||||
return lcRef != null;
|
||||
|
||||
pos.set(lightMatrix.pos.x, lightMatrix.pos.y, lightMatrix.pos.z);
|
||||
pipeline.addDependency(sideAttrib);
|
||||
pipeline.addRequirement(Transformation.operationIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate() {
|
||||
if(lcRef != null)
|
||||
lc.set(lcRef[vertexIndex]);
|
||||
else
|
||||
lc.compute(vec.set(vert.vec).sub(pos), side);
|
||||
}
|
||||
};
|
||||
|
||||
//pipeline state
|
||||
public static IVertexSource model;
|
||||
public static int firstVertexIndex;
|
||||
public static int lastVertexIndex;
|
||||
public static int vertexIndex;
|
||||
public static CCRenderPipeline pipeline = new CCRenderPipeline();
|
||||
|
||||
//context
|
||||
public static int baseColour;
|
||||
public static int alphaOverride;
|
||||
public static boolean useNormals;
|
||||
public static LightMatrix lightMatrix = new LightMatrix();
|
||||
|
||||
//vertex outputs
|
||||
public static Vertex5 vert = new Vertex5();
|
||||
public static boolean hasNormal;
|
||||
public static Vector3 normal = new Vector3();
|
||||
public static boolean hasColour;
|
||||
public static int colour;
|
||||
public static boolean hasBrightness;
|
||||
public static int brightness;
|
||||
|
||||
//attrute storage
|
||||
public static int side;
|
||||
public static LC lc = new LC();
|
||||
|
||||
public static void reset() {
|
||||
model = null;
|
||||
pipeline.reset();
|
||||
hasNormal = hasColour = hasBrightness = false;
|
||||
baseColour = alphaOverride = -1;
|
||||
}
|
||||
|
||||
public static void setPipeline(IVertexOperation... ops) {
|
||||
pipeline.setPipeline(ops);
|
||||
}
|
||||
|
||||
public static void setPipeline(IVertexSource model, int start, int end, IVertexOperation... ops) {
|
||||
pipeline.reset();
|
||||
setModel(model, start, end);
|
||||
pipeline.setPipeline(ops);
|
||||
}
|
||||
|
||||
public static void bindModel(IVertexSource model) {
|
||||
if(CCRenderState.model != model) {
|
||||
CCRenderState.model = model;
|
||||
pipeline.rebuild();
|
||||
}
|
||||
}
|
||||
|
||||
public static void setModel(IVertexSource source) {
|
||||
setModel(source, 0, source.getVertices().length);
|
||||
}
|
||||
|
||||
public static void setModel(IVertexSource source, int start, int end) {
|
||||
bindModel(source);
|
||||
firstVertexIndex = start;
|
||||
lastVertexIndex = end;
|
||||
}
|
||||
|
||||
public static void render(IVertexOperation... ops) {
|
||||
setPipeline(ops);
|
||||
render();
|
||||
}
|
||||
|
||||
public static void render() {
|
||||
Vertex5[] verts = model.getVertices();
|
||||
for(vertexIndex = firstVertexIndex; vertexIndex < lastVertexIndex; vertexIndex++) {
|
||||
model.prepareVertex();
|
||||
vert.set(verts[vertexIndex]);
|
||||
runPipeline();
|
||||
writeVert();
|
||||
}
|
||||
}
|
||||
|
||||
public static void runPipeline() {
|
||||
pipeline.operate();
|
||||
}
|
||||
|
||||
public static void writeVert() {
|
||||
if(hasNormal)
|
||||
Tessellator.instance.setNormal((float)normal.x, (float)normal.y, (float)normal.z);
|
||||
if(hasColour)
|
||||
Tessellator.instance.setColorRGBA(colour>>>24, colour>>16 & 0xFF, colour>>8 & 0xFF, alphaOverride >= 0 ? alphaOverride : colour & 0xFF);
|
||||
if(hasBrightness)
|
||||
Tessellator.instance.setBrightness(brightness);
|
||||
if(hasColour)
|
||||
Tessellator.instance.setColorRGBA(colour >> 24 & 0xFF, colour >> 16 & 0xFF, colour >> 8 & 0xFF, colour & 0xFF);
|
||||
Tessellator.instance.addVertexWithUV(vert.vec.x, vert.vec.y, vert.vec.z, vert.uv.u, vert.uv.v);
|
||||
}
|
||||
|
||||
public static void reset()
|
||||
{
|
||||
hasBrightness = false;
|
||||
useModelColours = false;
|
||||
hasColour = false;
|
||||
alphaOverride = false;
|
||||
useNormals = false;
|
||||
public static void setNormal(double x, double y, double z) {
|
||||
hasNormal = true;
|
||||
normal.set(x, y, z);
|
||||
}
|
||||
|
||||
public static void startDrawing(int i)
|
||||
{
|
||||
Tessellator.instance.startDrawing(i);
|
||||
apply();
|
||||
public static void setNormal(Vector3 n) {
|
||||
hasNormal = true;
|
||||
normal.set(n);
|
||||
}
|
||||
|
||||
public static void draw()
|
||||
{
|
||||
Tessellator.instance.draw();
|
||||
public static void setColour(int c) {
|
||||
hasColour = true;
|
||||
colour = c;
|
||||
}
|
||||
|
||||
public static void pullLightmap()
|
||||
{
|
||||
public static void setBrightness(int b) {
|
||||
hasBrightness = true;
|
||||
brightness = b;
|
||||
}
|
||||
|
||||
public static void setBrightness(IBlockAccess world, int x, int y, int z) {
|
||||
setBrightness(world.getBlock(x, y, z).getMixedBrightnessForBlock(world, x, y, z));
|
||||
}
|
||||
|
||||
public static void pullLightmap() {
|
||||
setBrightness((int)OpenGlHelper.lastBrightnessY << 16 | (int)OpenGlHelper.lastBrightnessX);
|
||||
}
|
||||
|
||||
public static void applyBrightnessTexCoords()
|
||||
{
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, brightness&0xFFFF, brightness>>>16);
|
||||
public static void changeTexture(String texture) {
|
||||
changeTexture(new ResourceLocation(texture));
|
||||
}
|
||||
|
||||
public static void glColour()
|
||||
{
|
||||
new ColourRGBA(colour).glColour();
|
||||
public static void changeTexture(ResourceLocation texture) {
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
|
||||
}
|
||||
|
||||
public static void startDrawing() {
|
||||
startDrawing(7);
|
||||
}
|
||||
|
||||
private static void startDrawing(int mode) {
|
||||
Tessellator.instance.startDrawing(mode);
|
||||
if(hasColour)
|
||||
Tessellator.instance.setColorRGBA(colour>>>24, colour>>16 & 0xFF, colour>>8 & 0xFF, alphaOverride >= 0 ? alphaOverride : colour & 0xFF);
|
||||
if(hasBrightness)
|
||||
Tessellator.instance.setBrightness(brightness);
|
||||
}
|
||||
|
||||
public static void draw() {
|
||||
Tessellator.instance.draw();
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import codechicken.lib.vec.Vector3;
|
||||
|
||||
public class ColourModifier implements IVertexModifier
|
||||
{
|
||||
public static final ColourModifier instance = new ColourModifier();
|
||||
|
||||
@Override
|
||||
public void applyModifiers(CCModel m, Tessellator tess, Vector3 vec, UV uv, Vector3 normal, int i)
|
||||
{
|
||||
if(CCRenderState.useModelColours() && m != null && m.colours != null)
|
||||
CCRenderState.vertexColour(m.colours[i]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsNormals()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,39 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import codechicken.lib.colour.Colour;
|
||||
import codechicken.lib.colour.ColourRGBA;
|
||||
import codechicken.lib.vec.Vector3;
|
||||
|
||||
public class ColourMultiplier implements IVertexModifier
|
||||
public class ColourMultiplier implements CCRenderState.IVertexOperation
|
||||
{
|
||||
public Colour colour;
|
||||
|
||||
public ColourMultiplier(Colour colour)
|
||||
{
|
||||
private static ColourMultiplier instance = new ColourMultiplier(-1);
|
||||
|
||||
public static ColourMultiplier instance(int colour) {
|
||||
instance.colour = colour;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static final int operationIndex = CCRenderState.registerOperation();
|
||||
public int colour;
|
||||
|
||||
public ColourMultiplier(int colour) {
|
||||
this.colour = colour;
|
||||
}
|
||||
|
||||
public ColourMultiplier(int colour)
|
||||
{
|
||||
this(new ColourRGBA(colour));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void applyModifiers(CCModel m, Tessellator tess, Vector3 vec, UV uv, Vector3 normal, int i)
|
||||
{
|
||||
if(CCRenderState.useModelColours() && m != null && m.colours != null)
|
||||
CCRenderState.vertexColour(new ColourRGBA(m.colours[i]).multiply(colour).rgba());
|
||||
public boolean load() {
|
||||
if(colour == -1)
|
||||
return false;
|
||||
|
||||
CCRenderState.pipeline.addDependency(CCRenderState.colourAttrib);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsNormals()
|
||||
{
|
||||
return false;
|
||||
public void operate() {
|
||||
CCRenderState.setColour(ColourRGBA.multiply(CCRenderState.colour, colour));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int operationID() {
|
||||
return operationIndex;
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,12 @@ import codechicken.lib.vec.Vector3;
|
||||
import net.minecraft.client.particle.EffectRenderer;
|
||||
import net.minecraft.client.particle.EntityFX;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.util.Icon;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class EntityDigIconFX extends EntityFX
|
||||
{
|
||||
public EntityDigIconFX(World world, double x, double y, double z, double dx, double dy, double dz, Icon icon)
|
||||
public EntityDigIconFX(World world, double x, double y, double z, double dx, double dy, double dz, IIcon icon)
|
||||
{
|
||||
super(world, x, y, z, dx, dy, dz);
|
||||
particleIcon = icon;
|
||||
@@ -72,7 +72,7 @@ public class EntityDigIconFX extends EntityFX
|
||||
par1Tessellator.addVertexWithUV(f11 + par3 * f10 - par6 * f10, f12 - par4 * f10, f13 + par5 * f10 - par7 * f10, f7, f9);
|
||||
}
|
||||
|
||||
public static void addBlockHitEffects(World world, Cuboid6 bounds, int side, Icon icon, EffectRenderer effectRenderer)
|
||||
public static void addBlockHitEffects(World world, Cuboid6 bounds, int side, IIcon icon, EffectRenderer effectRenderer)
|
||||
{
|
||||
float border = 0.1F;
|
||||
Vector3 diff = bounds.max.copy().subtract(bounds.min).add(-2*border);
|
||||
@@ -99,7 +99,7 @@ public class EntityDigIconFX extends EntityFX
|
||||
.multiplyVelocity(0.2F).multipleParticleScaleBy(0.6F));
|
||||
}
|
||||
|
||||
public static void addBlockDestroyEffects(World world, Cuboid6 bounds, Icon[] icons, EffectRenderer effectRenderer)
|
||||
public static void addBlockDestroyEffects(World world, Cuboid6 bounds, IIcon[] icons, EffectRenderer effectRenderer)
|
||||
{
|
||||
Vector3 diff = bounds.max.copy().subtract(bounds.min);
|
||||
Vector3 center = bounds.min.copy().add(bounds.max).multiply(0.5);
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
public interface IUVTransformation
|
||||
{
|
||||
public void transform(UV texcoord);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import codechicken.lib.vec.Vector3;
|
||||
|
||||
public interface IVertexModifier
|
||||
{
|
||||
public void applyModifiers(CCModel m, Tessellator tess, Vector3 vec, UV uv, Vector3 normal, int i);
|
||||
|
||||
public boolean needsNormals();
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import net.minecraft.util.Icon;
|
||||
|
||||
public class IconTransformation implements IUVTransformation
|
||||
{
|
||||
public Icon icon;
|
||||
|
||||
public IconTransformation(Icon icon)
|
||||
{
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(UV texcoord)
|
||||
{
|
||||
texcoord.u = icon.getInterpolatedU(texcoord.u%2*16);
|
||||
texcoord.v = icon.getInterpolatedV(texcoord.v%2*16);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import net.minecraft.util.Icon;
|
||||
|
||||
/**
|
||||
* Icon index is specified as (int)u>>1
|
||||
*/
|
||||
public class MultiIconTransformation implements IUVTransformation
|
||||
{
|
||||
public Icon[] icons;
|
||||
|
||||
public MultiIconTransformation(Icon... icons)
|
||||
{
|
||||
this.icons = icons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(UV texcoord)
|
||||
{
|
||||
int i = (int)texcoord.u>>1;
|
||||
Icon icon = icons[i%icons.length];
|
||||
texcoord.u = icon.getInterpolatedU(texcoord.u%2*16);
|
||||
texcoord.v = icon.getInterpolatedV(texcoord.v%2*16);
|
||||
}
|
||||
|
||||
public static CCModel setIconIndex(CCModel m, int index)
|
||||
{
|
||||
return setIconIndex(m, 0, m.verts.length, index);
|
||||
}
|
||||
|
||||
public static CCModel setIconIndex(CCModel m, int start, int end, int index)
|
||||
{
|
||||
for(int k = start; k < end; k++)
|
||||
{
|
||||
UV uv = m.verts[k].uv;
|
||||
uv.u = uv.u%2+index*2;
|
||||
uv.v %= 2;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.ResourceManager;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class PlaceholderTexture extends TextureAtlasSprite
|
||||
@@ -12,7 +12,7 @@ public class PlaceholderTexture extends TextureAtlasSprite
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean load(ResourceManager manager, ResourceLocation location)
|
||||
public boolean load(IResourceManager manager, ResourceLocation location)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import codechicken.lib.render.uv.UV;
|
||||
import codechicken.lib.render.uv.UVScale;
|
||||
import codechicken.lib.vec.*;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.IconRegister;
|
||||
import net.minecraft.util.Icon;
|
||||
import net.minecraft.client.renderer.texture.IIconRegister;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
@@ -638,7 +640,7 @@ public class QBImporter
|
||||
return map.get(key).m;
|
||||
}
|
||||
|
||||
public Icon getIcon(String key, IconRegister r, String iconName) {
|
||||
public IIcon getIcon(String key, IIconRegister r, String iconName) {
|
||||
int img = map.get(key).img;
|
||||
if(icons[img] != null && !iconName.equals(icons[img]))
|
||||
throw new IllegalArgumentException("Attempted to get a previously registered icon by a different name: "+icons[img]+", "+iconName);
|
||||
|
||||
@@ -3,6 +3,8 @@ package codechicken.lib.render;
|
||||
import static net.minecraftforge.client.IItemRenderer.ItemRenderType.ENTITY;
|
||||
import static net.minecraftforge.client.IItemRenderer.ItemRendererHelper.BLOCK_3D;
|
||||
|
||||
import codechicken.lib.render.uv.UV;
|
||||
import codechicken.lib.render.uv.UVTransformation;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.vec.Cuboid6;
|
||||
@@ -10,7 +12,7 @@ import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.lib.vec.Transformation;
|
||||
import codechicken.lib.vec.Rotation;
|
||||
import codechicken.lib.vec.Vector3;
|
||||
import net.minecraft.util.Icon;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
@@ -48,7 +50,7 @@ public class RenderUtils
|
||||
entityItem.hoverStart = 0;
|
||||
}
|
||||
|
||||
public static void renderFluidQuad(Vector3 point1, Vector3 point2, Vector3 point3, Vector3 point4, Icon icon, double res)
|
||||
public static void renderFluidQuad(Vector3 point1, Vector3 point2, Vector3 point3, Vector3 point4, IIcon icon, double res)
|
||||
{
|
||||
renderFluidQuad(point2, vectors[0].set(point4).subtract(point1), vectors[1].set(point1).subtract(point2), icon, res);
|
||||
}
|
||||
@@ -60,7 +62,7 @@ public class RenderUtils
|
||||
* @param high The left side of the quad
|
||||
* @param res Units per icon
|
||||
*/
|
||||
public static void renderFluidQuad(Vector3 base, Vector3 wide, Vector3 high, Icon icon, double res)
|
||||
public static void renderFluidQuad(Vector3 base, Vector3 wide, Vector3 high, IIcon icon, double res)
|
||||
{
|
||||
Tessellator t = Tessellator.instance;
|
||||
|
||||
@@ -141,7 +143,7 @@ public class RenderUtils
|
||||
var2.draw();
|
||||
}
|
||||
|
||||
public static void renderFluidCuboid(Cuboid6 bound, Icon tex, double res)
|
||||
public static void renderFluidCuboid(Cuboid6 bound, IIcon tex, double res)
|
||||
{
|
||||
renderFluidQuad(//bottom
|
||||
new Vector3(bound.min.x, bound.min.y, bound.min.z),
|
||||
@@ -236,7 +238,7 @@ public class RenderUtils
|
||||
* @param stack The fluid stack to render
|
||||
* @return The icon of the fluid
|
||||
*/
|
||||
public static Icon prepareFluidRender(FluidStack stack, int alpha)
|
||||
public static IIcon prepareFluidRender(FluidStack stack, int alpha)
|
||||
{
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
@@ -283,8 +285,8 @@ public class RenderUtils
|
||||
else
|
||||
bound.max.y = bound.min.y+(bound.max.y-bound.min.y)*density;
|
||||
|
||||
Icon tex = prepareFluidRender(stack, alpha);
|
||||
CCRenderState.startDrawing(7);
|
||||
IIcon tex = prepareFluidRender(stack, alpha);
|
||||
CCRenderState.startDrawing();
|
||||
renderFluidCuboid(bound, tex, res);
|
||||
CCRenderState.draw();
|
||||
postFluidRender();
|
||||
@@ -305,8 +307,8 @@ public class RenderUtils
|
||||
rect.h = height;
|
||||
}
|
||||
|
||||
Icon tex = prepareFluidRender(stack, alpha);
|
||||
CCRenderState.startDrawing(7);
|
||||
IIcon tex = prepareFluidRender(stack, alpha);
|
||||
CCRenderState.startDrawing();
|
||||
renderFluidQuad(
|
||||
new Vector3(rect.x, rect.y+rect.h, 0),
|
||||
new Vector3(rect.w,0, 0),
|
||||
@@ -333,9 +335,9 @@ public class RenderUtils
|
||||
boolean is3D = customRenderer != null && customRenderer.shouldUseRenderHelper(ENTITY, item, BLOCK_3D);
|
||||
|
||||
boolean larger = false;
|
||||
if (item.getItem() instanceof ItemBlock && RenderBlocks.renderItemIn3d(Block.blocksList[item.itemID].getRenderType()))
|
||||
if (item.getItem() instanceof ItemBlock && RenderBlocks.renderItemIn3d(Block.getBlockFromItem(item.getItem()).getRenderType()))
|
||||
{
|
||||
int renderType = Block.blocksList[item.itemID].getRenderType();
|
||||
int renderType = Block.getBlockFromItem(item.getItem()).getRenderType();
|
||||
larger = !(renderType == 1 || renderType == 19 || renderType == 12 || renderType == 2);
|
||||
}
|
||||
else if(is3D)
|
||||
@@ -351,137 +353,9 @@ public class RenderUtils
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
|
||||
entityItem.setEntityItemStack(item);
|
||||
uniformRenderItem.doRenderItem(entityItem, 0, larger ? 0.09 : 0.06, 0, 0, (float)(spin*9/Math.PI));
|
||||
uniformRenderItem.doRender(entityItem, 0, larger ? 0.09 : 0.06, 0, 0, (float)(spin*9/Math.PI));
|
||||
|
||||
if(larger)
|
||||
GL11.glScaled(d1, d1, d1);
|
||||
}
|
||||
|
||||
private static Vertex5[] face = new Vertex5[]{new Vertex5(), new Vertex5(), new Vertex5(), new Vertex5()};
|
||||
public static void renderBlock(Cuboid6 c, int sideMask, IFaceRenderer r)
|
||||
{
|
||||
double x1 = c.min.x;
|
||||
double x2 = c.max.x;
|
||||
double y1 = c.min.y;
|
||||
double y2 = c.max.y;
|
||||
double z1 = c.min.z;
|
||||
double z2 = c.max.z;
|
||||
double u1 = 0;
|
||||
double u2 = 0;
|
||||
double v1 = 0;
|
||||
double v2 = 0;
|
||||
|
||||
if((sideMask&1) == 0)
|
||||
{
|
||||
u1 = x1; v1 = z1;
|
||||
u2 = x2; v2 = z2;
|
||||
face[0].set(x1, y1, z2, u1, v2);
|
||||
face[1].set(x1, y1, z1, u1, v1);
|
||||
face[2].set(x2, y1, z1, u2, v1);
|
||||
face[3].set(x2, y1, z2, u2, v2);
|
||||
r.renderFace(face, c.min.y > 0 ? 6 : 0);
|
||||
}
|
||||
|
||||
if((sideMask&2) == 0)
|
||||
{
|
||||
u1 = x1+2; v1 = z1;
|
||||
u2 = x2+2; v2 = z2;
|
||||
face[0].set(x2, y2, z2, u2, v2);
|
||||
face[1].set(x2, y2, z1, u2, v1);
|
||||
face[2].set(x1, y2, z1, u1, v1);
|
||||
face[3].set(x1, y2, z2, u1, v2);
|
||||
r.renderFace(face, c.max.y < 1 ? 7 : 1);
|
||||
}
|
||||
|
||||
if((sideMask&4) == 0)
|
||||
{
|
||||
u1 = 1-x1+4; v1 = 1-y2;
|
||||
u2 = 1-x2+4; v2 = 1-y1;
|
||||
face[0].set(x1, y1, z1, u1, v2);
|
||||
face[1].set(x1, y2, z1, u1, v1);
|
||||
face[2].set(x2, y2, z1, u2, v1);
|
||||
face[3].set(x2, y1, z1, u2, v2);
|
||||
r.renderFace(face, c.min.z > 0 ? 8 : 2);
|
||||
}
|
||||
|
||||
if((sideMask&8) == 0)
|
||||
{
|
||||
u1 = x1+6; v1 = 1-y2;
|
||||
u2 = x2+6; v2 = 1-y1;
|
||||
face[0].set(x2, y1, z2, u2, v2);
|
||||
face[1].set(x2, y2, z2, u2, v1);
|
||||
face[2].set(x1, y2, z2, u1, v1);
|
||||
face[3].set(x1, y1, z2, u1, v2);
|
||||
r.renderFace(face, c.max.z < 1 ? 9 : 3);
|
||||
}
|
||||
|
||||
if((sideMask&0x10) == 0)
|
||||
{
|
||||
u1 = z1+8; v1 = 1-y2;
|
||||
u2 = z2+8; v2 = 1-y1;
|
||||
face[0].set(x1, y1, z2, u2, v2);
|
||||
face[1].set(x1, y2, z2, u2, v1);
|
||||
face[2].set(x1, y2, z1, u1, v1);
|
||||
face[3].set(x1, y1, z1, u1, v2);
|
||||
r.renderFace(face, c.min.x > 0 ? 10 : 4);
|
||||
}
|
||||
|
||||
if((sideMask&0x20) == 0)
|
||||
{
|
||||
u1 = 1-z1+10; v1 = 1-y2;
|
||||
u2 = 1-z2+10; v2 = 1-y1;
|
||||
face[0].set(x2, y1, z1, u1, v2);
|
||||
face[1].set(x2, y2, z1, u1, v1);
|
||||
face[2].set(x2, y2, z2, u2, v1);
|
||||
face[3].set(x2, y1, z2, u2, v2);
|
||||
r.renderFace(face, c.max.x < 1 ? 11 : 5);
|
||||
}
|
||||
}
|
||||
|
||||
public static void renderBlock(Cuboid6 bounds, int sideMask, final Transformation t, final IUVTransformation u, final IVertexModifier m)
|
||||
{
|
||||
renderBlock(bounds, sideMask, new IFaceRenderer(){
|
||||
boolean drawNormal = CCRenderState.useNormals();
|
||||
boolean computeNormal = drawNormal || m != null && m.needsNormals();
|
||||
Vector3 normal = new Vector3();
|
||||
Vertex5 vert;
|
||||
Vector3 vec = new Vector3();
|
||||
UV uv = new UV();
|
||||
|
||||
@Override
|
||||
public void renderFace(Vertex5[] face, int side)
|
||||
{
|
||||
Tessellator tess = Tessellator.instance;
|
||||
for(int i = 0; i < face.length; i++)
|
||||
{
|
||||
if(computeNormal)
|
||||
{
|
||||
if(t != null)
|
||||
t.applyN(normal.set(Rotation.axes[side%6]));
|
||||
else
|
||||
normal = Rotation.axes[side%6];
|
||||
|
||||
if(drawNormal)
|
||||
tess.setNormal((float)normal.x, (float)normal.y, (float)normal.z);
|
||||
}
|
||||
|
||||
vert = face[i];
|
||||
if(t != null)
|
||||
t.apply(vec.set(vert.vec));
|
||||
else
|
||||
vec = vert.vec;
|
||||
|
||||
if(u != null)
|
||||
u.transform(uv.set(vert.uv));
|
||||
else
|
||||
uv = vert.uv;
|
||||
|
||||
if(m != null)
|
||||
m.applyModifiers(null, tess, vec, uv, normal, i);
|
||||
|
||||
tess.addVertexWithUV(vec.x, vec.y, vec.z, uv.u, uv.v);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,19 @@ package codechicken.lib.render;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import codechicken.lib.render.TextureUtils.IIconRegister;
|
||||
import codechicken.lib.render.TextureUtils.IIconSelfRegister;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
import net.minecraft.client.renderer.texture.IconRegister;
|
||||
import net.minecraft.client.renderer.texture.IIconRegister;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.util.Icon;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class SpriteSheetManager
|
||||
{
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static class SpriteSheet implements IIconRegister
|
||||
public static class SpriteSheet implements IIconSelfRegister
|
||||
{
|
||||
private int tilesX;
|
||||
private int tilesY;
|
||||
@@ -42,7 +42,7 @@ public class SpriteSheetManager
|
||||
setupSprite(i);
|
||||
}
|
||||
|
||||
public void registerIcons(IconRegister register)
|
||||
public void registerIcons(IIconRegister register)
|
||||
{
|
||||
TextureMap textureMap = (TextureMap)register;
|
||||
|
||||
@@ -79,9 +79,9 @@ public class SpriteSheetManager
|
||||
spriteHeight = texture.height/tilesY;
|
||||
}
|
||||
|
||||
public Icon getSprite(int index)
|
||||
public IIcon getSprite(int index)
|
||||
{
|
||||
Icon i = sprites[index];
|
||||
IIcon i = sprites[index];
|
||||
if(i == null)
|
||||
throw new IllegalArgumentException("Sprite at index: "+index+" from texture file "+resource+" was not preloaded.");
|
||||
return i;
|
||||
|
||||
@@ -13,55 +13,47 @@ public class TextureFX
|
||||
public int tileSizeSquare = 256;
|
||||
public int tileSizeMask = 15;
|
||||
public int tileSizeSquareMask = 255;
|
||||
|
||||
|
||||
public boolean anaglyphEnabled;
|
||||
public TextureSpecial texture;
|
||||
|
||||
public TextureFX(int spriteIndex, SpriteSheet sheet)
|
||||
{
|
||||
public TextureFX(int spriteIndex, SpriteSheet sheet) {
|
||||
texture = sheet.bindTextureFX(spriteIndex, this);
|
||||
}
|
||||
|
||||
public TextureFX(int size, String name)
|
||||
{
|
||||
|
||||
public TextureFX(int size, String name) {
|
||||
texture = new TextureSpecial(name).blank(size).selfRegister().addTextureFX(this);
|
||||
}
|
||||
|
||||
public TextureFX setAtlas(int index)
|
||||
{
|
||||
|
||||
public TextureFX setAtlas(int index) {
|
||||
texture.atlasIndex = index;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setup()
|
||||
{
|
||||
public void setup() {
|
||||
imageData = new int[tileSizeSquare];
|
||||
}
|
||||
|
||||
public void onTextureDimensionsUpdate(int width, int height)
|
||||
{
|
||||
if(width != height)
|
||||
throw new IllegalArgumentException("Non-Square textureFX not supported ("+width+":"+height+")");
|
||||
|
||||
|
||||
public void onTextureDimensionsUpdate(int width, int height) {
|
||||
if (width != height)
|
||||
throw new IllegalArgumentException("Non-Square textureFX not supported (" + width + ":" + height + ")");
|
||||
|
||||
tileSizeBase = width;
|
||||
tileSizeSquare = tileSizeBase * tileSizeBase;
|
||||
tileSizeMask = tileSizeBase - 1;
|
||||
tileSizeSquareMask = tileSizeSquare - 1;
|
||||
setup();
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
|
||||
public void update() {
|
||||
anaglyphEnabled = Minecraft.getMinecraft().gameSettings.anaglyph;
|
||||
onTick();
|
||||
}
|
||||
|
||||
public void onTick()
|
||||
{
|
||||
public void onTick() {
|
||||
}
|
||||
|
||||
public boolean changed()
|
||||
{
|
||||
|
||||
public boolean changed() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,150 +1,148 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import codechicken.lib.render.SpriteSheetManager.SpriteSheet;
|
||||
import codechicken.lib.render.TextureUtils.IIconRegister;
|
||||
import codechicken.lib.render.TextureUtils.IIconSelfRegister;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.client.renderer.texture.IconRegister;
|
||||
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.renderer.texture.TextureUtil;
|
||||
import net.minecraft.client.resources.ResourceManager;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class TextureSpecial extends TextureAtlasSprite implements IIconRegister
|
||||
{
|
||||
public class TextureSpecial extends TextureAtlasSprite implements IIconSelfRegister {
|
||||
//sprite sheet fields
|
||||
private int spriteIndex;
|
||||
private SpriteSheet spriteSheet;
|
||||
|
||||
|
||||
//textureFX fields
|
||||
private TextureFX textureFX;
|
||||
|
||||
private int blankSize = -1;
|
||||
|
||||
private int blankSize = -1;
|
||||
private ArrayList<TextureDataHolder> baseTextures;
|
||||
|
||||
|
||||
private boolean selfRegister;
|
||||
public int atlasIndex;
|
||||
|
||||
protected TextureSpecial(String par1)
|
||||
{
|
||||
|
||||
protected TextureSpecial(String par1) {
|
||||
super(par1);
|
||||
}
|
||||
|
||||
public TextureSpecial addTexture(TextureDataHolder t)
|
||||
{
|
||||
if(baseTextures == null)
|
||||
|
||||
public TextureSpecial addTexture(TextureDataHolder t) {
|
||||
if (baseTextures == null)
|
||||
baseTextures = new ArrayList<TextureDataHolder>();
|
||||
baseTextures.add(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextureSpecial baseFromSheet(SpriteSheet spriteSheet, int spriteIndex)
|
||||
{
|
||||
|
||||
public TextureSpecial baseFromSheet(SpriteSheet spriteSheet, int spriteIndex) {
|
||||
this.spriteSheet = spriteSheet;
|
||||
this.spriteIndex = spriteIndex;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextureSpecial addTextureFX(TextureFX fx)
|
||||
{
|
||||
|
||||
public TextureSpecial addTextureFX(TextureFX fx) {
|
||||
textureFX = fx;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initSprite(int sheetWidth, int sheetHeight, int originX, int originY, boolean rotated)
|
||||
{
|
||||
public void initSprite(int sheetWidth, int sheetHeight, int originX, int originY, boolean rotated) {
|
||||
super.initSprite(sheetWidth, sheetHeight, originX, originY, rotated);
|
||||
if(textureFX != null)
|
||||
if (textureFX != null)
|
||||
textureFX.onTextureDimensionsUpdate(width, height);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateAnimation()
|
||||
{
|
||||
if(textureFX != null)
|
||||
{
|
||||
public void updateAnimation() {
|
||||
if (textureFX != null) {
|
||||
textureFX.update();
|
||||
if(textureFX.changed())
|
||||
TextureUtil.uploadTextureSub(textureFX.imageData, width, height, originX, originY, false, false);
|
||||
if (textureFX.changed())
|
||||
TextureUtil.uploadTextureSub(0, textureFX.imageData, width, height, originX, originY, false, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean load(ResourceManager manager, ResourceLocation location)
|
||||
{
|
||||
if(baseTextures != null)
|
||||
{
|
||||
for(TextureDataHolder tex : baseTextures)
|
||||
{
|
||||
framesTextureData.add(tex.data);
|
||||
public boolean hasCustomLoader(IResourceManager manager, ResourceLocation location) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addFrame(int[] data) {
|
||||
GameSettings settings = Minecraft.getMinecraft().gameSettings;
|
||||
BufferedImage[] images = new BufferedImage[settings.mipmapLevels+1];
|
||||
images[0] = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
images[0].setRGB(0, 0, width, height, data, 0, width);
|
||||
|
||||
super.loadSprite(images, null, settings.anisotropicFiltering > 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean load(IResourceManager manager, ResourceLocation location) {
|
||||
if (baseTextures != null) {
|
||||
for (TextureDataHolder tex : baseTextures) {
|
||||
width = tex.width;
|
||||
height = tex.height;
|
||||
addFrame(tex.data);
|
||||
}
|
||||
}
|
||||
|
||||
if(spriteSheet != null)
|
||||
{
|
||||
|
||||
if (spriteSheet != null) {
|
||||
TextureDataHolder tex = spriteSheet.createSprite(spriteIndex);
|
||||
width = tex.width;
|
||||
height = tex.height;
|
||||
framesTextureData.add(tex.data);
|
||||
addFrame(tex.data);
|
||||
}
|
||||
|
||||
if(blankSize > 0)
|
||||
{
|
||||
|
||||
if (blankSize > 0) {
|
||||
width = height = blankSize;
|
||||
framesTextureData.add(new int[blankSize*blankSize]);
|
||||
addFrame(new int[blankSize * blankSize]);
|
||||
}
|
||||
|
||||
if(framesTextureData.isEmpty())
|
||||
throw new RuntimeException("No base frame for texture: "+getIconName());
|
||||
|
||||
return true;
|
||||
|
||||
if (framesTextureData.isEmpty())
|
||||
throw new RuntimeException("No base frame for texture: " + getIconName());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasAnimationMetadata()
|
||||
{
|
||||
public boolean hasAnimationMetadata() {
|
||||
return textureFX != null || super.hasAnimationMetadata();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getFrameCount()
|
||||
{
|
||||
if(textureFX != null)
|
||||
public int getFrameCount() {
|
||||
if (textureFX != null)
|
||||
return 1;
|
||||
|
||||
|
||||
return super.getFrameCount();
|
||||
}
|
||||
|
||||
public TextureSpecial blank(int size)
|
||||
{
|
||||
public TextureSpecial blank(int size) {
|
||||
blankSize = size;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextureSpecial selfRegister()
|
||||
{
|
||||
|
||||
public TextureSpecial selfRegister() {
|
||||
selfRegister = true;
|
||||
TextureUtils.addIconRegistrar(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void registerIcons(IconRegister register)
|
||||
{
|
||||
if(selfRegister)
|
||||
((TextureMap)register).setTextureEntry(getIconName(), this);
|
||||
public void registerIcons(IIconRegister register) {
|
||||
if (selfRegister)
|
||||
((TextureMap) register).setTextureEntry(getIconName(), this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int atlasIndex()
|
||||
{
|
||||
public int atlasIndex() {
|
||||
return atlasIndex;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import java.util.ArrayList;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
|
||||
@@ -15,138 +16,118 @@ import codechicken.lib.colour.ColourARGB;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.renderer.texture.IconRegister;
|
||||
import net.minecraft.client.renderer.texture.IIconRegister;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.util.Icon;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.ForgeSubscribe;
|
||||
|
||||
public class TextureUtils
|
||||
{
|
||||
public static interface IIconRegister
|
||||
{
|
||||
public static interface IIconSelfRegister
|
||||
{
|
||||
public void registerIcons(IconRegister register);
|
||||
public void registerIcons(IIconRegister register);
|
||||
|
||||
public int atlasIndex();
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
|
||||
static {
|
||||
MinecraftForge.EVENT_BUS.register(new TextureUtils());
|
||||
}
|
||||
|
||||
private static ArrayList<IIconRegister> iconRegistrars = new ArrayList<TextureUtils.IIconRegister>();
|
||||
|
||||
public static void addIconRegistrar(IIconRegister registrar)
|
||||
{
|
||||
|
||||
private static ArrayList<IIconSelfRegister> iconRegistrars = new ArrayList<TextureUtils.IIconSelfRegister>();
|
||||
|
||||
public static void addIconRegistrar(IIconSelfRegister registrar) {
|
||||
iconRegistrars.add(registrar);
|
||||
}
|
||||
|
||||
@ForgeSubscribe
|
||||
public void textureLoad(TextureStitchEvent.Pre event)
|
||||
{
|
||||
for(IIconRegister reg : iconRegistrars)
|
||||
if(reg.atlasIndex() == event.map.textureType)
|
||||
|
||||
@SubscribeEvent
|
||||
public void textureLoad(TextureStitchEvent.Pre event) {
|
||||
for (IIconSelfRegister reg : iconRegistrars)
|
||||
if (reg.atlasIndex() == event.map.getTextureType())
|
||||
reg.registerIcons(event.map);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return an array of ARGB pixel data
|
||||
*/
|
||||
public static int[] loadTextureData(ResourceLocation resource)
|
||||
{
|
||||
public static int[] loadTextureData(ResourceLocation resource) {
|
||||
return loadTexture(resource).data;
|
||||
}
|
||||
|
||||
public static Colour[] loadTextureColours(ResourceLocation resource)
|
||||
{
|
||||
public static Colour[] loadTextureColours(ResourceLocation resource) {
|
||||
int[] idata = loadTextureData(resource);
|
||||
Colour[] data = new Colour[idata.length];
|
||||
for(int i = 0; i < data.length; i++)
|
||||
for (int i = 0; i < data.length; i++)
|
||||
data[i] = new ColourARGB(idata[i]);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static InputStream getTextureResource(ResourceLocation textureFile) throws IOException
|
||||
{
|
||||
|
||||
public static InputStream getTextureResource(ResourceLocation textureFile) throws IOException {
|
||||
return Minecraft.getMinecraft().getResourceManager().getResource(textureFile).getInputStream();
|
||||
}
|
||||
|
||||
public static BufferedImage loadBufferedImage(ResourceLocation textureFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
public static BufferedImage loadBufferedImage(ResourceLocation textureFile) {
|
||||
try {
|
||||
return loadBufferedImage(getTextureResource(textureFile));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
System.err.println("Failed to load texture file: "+textureFile);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Failed to load texture file: " + textureFile);
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BufferedImage loadBufferedImage(InputStream in) throws IOException
|
||||
{
|
||||
public static BufferedImage loadBufferedImage(InputStream in) throws IOException {
|
||||
BufferedImage img = ImageIO.read(in);
|
||||
in.close();
|
||||
return img;
|
||||
}
|
||||
|
||||
public static TextureManager engine()
|
||||
{
|
||||
public static TextureManager engine() {
|
||||
return Minecraft.getMinecraft().renderEngine;
|
||||
}
|
||||
|
||||
public static void copySubImg(int[] fromTex, int fromWidth, int fromX, int fromY, int width, int height, int[] toTex, int toWidth, int toX, int toY)
|
||||
{
|
||||
for(int y = 0; y < height; y++)
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
int fp = (y+fromY)*fromWidth+x+fromX;
|
||||
int tp = (y+toX)*toWidth+x+toX;
|
||||
public static void copySubImg(int[] fromTex, int fromWidth, int fromX, int fromY, int width, int height, int[] toTex, int toWidth, int toX, int toY) {
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++) {
|
||||
int fp = (y + fromY) * fromWidth + x + fromX;
|
||||
int tp = (y + toX) * toWidth + x + toX;
|
||||
|
||||
toTex[tp] = fromTex[fp];
|
||||
}
|
||||
}
|
||||
|
||||
public static void bindAtlas(int atlasIndex)
|
||||
{
|
||||
public static void bindAtlas(int atlasIndex) {
|
||||
engine().bindTexture(atlasIndex == 0 ? TextureMap.locationBlocksTexture : TextureMap.locationItemsTexture);
|
||||
}
|
||||
|
||||
public static Icon getBlankIcon(int size, IconRegister iconRegister)
|
||||
{
|
||||
TextureMap textureMap = (TextureMap)iconRegister;
|
||||
String s = "blank_"+size;
|
||||
if(textureMap.getTextureExtry(s) == null)
|
||||
{
|
||||
|
||||
public static IIcon getBlankIcon(int size, IIconRegister iconRegister) {
|
||||
TextureMap textureMap = (TextureMap) iconRegister;
|
||||
String s = "blank_" + size;
|
||||
if (textureMap.getTextureExtry(s) == null) {
|
||||
TextureSpecial icon = new TextureSpecial(s).blank(size);
|
||||
textureMap.setTextureEntry(s, icon);
|
||||
}
|
||||
return iconRegister.registerIcon(s);
|
||||
}
|
||||
|
||||
public static TextureSpecial getTextureSpecial(IconRegister iconRegister, String name)
|
||||
{
|
||||
|
||||
public static TextureSpecial getTextureSpecial(IIconRegister iconRegister, String name) {
|
||||
TextureMap textureMap = (TextureMap) iconRegister;
|
||||
Icon entry = textureMap.getTextureExtry(name);
|
||||
if(entry != null)
|
||||
throw new IllegalStateException("Texture: "+name+" is already registered");
|
||||
|
||||
IIcon entry = textureMap.getTextureExtry(name);
|
||||
if (entry != null)
|
||||
throw new IllegalStateException("Texture: " + name + " is already registered");
|
||||
|
||||
TextureSpecial icon = new TextureSpecial(name);
|
||||
textureMap.setTextureEntry(name, icon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
public static void prepareTexture(int target, int texture, int min_mag_filter, int wrap)
|
||||
{
|
||||
public static void prepareTexture(int target, int texture, int min_mag_filter, int wrap) {
|
||||
GL11.glBindTexture(target, texture);
|
||||
GL11.glTexParameteri(target, GL11.GL_TEXTURE_MIN_FILTER, min_mag_filter);
|
||||
GL11.glTexParameteri(target, GL11.GL_TEXTURE_MAG_FILTER, min_mag_filter);
|
||||
switch(target)
|
||||
{
|
||||
switch (target) {
|
||||
case GL12.GL_TEXTURE_3D:
|
||||
GL11.glTexParameteri(target, GL12.GL_TEXTURE_WRAP_R, wrap);
|
||||
case GL11.GL_TEXTURE_2D:
|
||||
@@ -156,32 +137,28 @@ public class TextureUtils
|
||||
}
|
||||
}
|
||||
|
||||
public static TextureDataHolder loadTexture(ResourceLocation resource)
|
||||
{
|
||||
public static TextureDataHolder loadTexture(ResourceLocation resource) {
|
||||
BufferedImage img = loadBufferedImage(resource);
|
||||
if(img == null)
|
||||
throw new RuntimeException("Texture not found: "+resource);
|
||||
if (img == null)
|
||||
throw new RuntimeException("Texture not found: " + resource);
|
||||
return new TextureDataHolder(img);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses an empty placeholder texture to tell if the map has been reloaded since the last call to refresh texture and the texture with name needs to be reacquired to be valid
|
||||
*/
|
||||
public static boolean refreshTexture(TextureMap map, String name)
|
||||
{
|
||||
if(map.getTextureExtry(name) == null)
|
||||
{
|
||||
public static boolean refreshTexture(TextureMap map, String name) {
|
||||
if (map.getTextureExtry(name) == null) {
|
||||
map.setTextureEntry(name, new PlaceholderTexture(name));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Icon safeIcon(Icon icon)
|
||||
{
|
||||
if(icon == null)
|
||||
icon = ((TextureMap)Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.locationBlocksTexture)).getAtlasSprite("missingno");
|
||||
|
||||
public static IIcon safeIcon(IIcon icon) {
|
||||
if (icon == null)
|
||||
icon = ((TextureMap) Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.locationBlocksTexture)).getAtlasSprite("missingno");
|
||||
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
public class UV
|
||||
{
|
||||
public double u;
|
||||
public double v;
|
||||
|
||||
public UV()
|
||||
{
|
||||
}
|
||||
|
||||
public UV(double u, double v)
|
||||
{
|
||||
this.u = u;
|
||||
this.v = v;
|
||||
}
|
||||
|
||||
public UV(UV uv)
|
||||
{
|
||||
this(uv.u, uv.v);
|
||||
}
|
||||
|
||||
public UV set(double u, double v)
|
||||
{
|
||||
this.u = u;
|
||||
this.v = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UV set(UV uv)
|
||||
{
|
||||
u = uv.u;
|
||||
v = uv.v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UV copy()
|
||||
{
|
||||
return new UV(this);
|
||||
}
|
||||
|
||||
public UV add(UV uv)
|
||||
{
|
||||
u+=uv.u;
|
||||
v+=uv.v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UV mul(double d)
|
||||
{
|
||||
u*=d;
|
||||
v*=d;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
MathContext cont = new MathContext(4, RoundingMode.HALF_UP);
|
||||
return "UV("+new BigDecimal(u, cont)+", "+new BigDecimal(v, cont)+")";
|
||||
}
|
||||
|
||||
public UV apply(IUVTransformation transform)
|
||||
{
|
||||
transform.transform(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(!(o instanceof UV))
|
||||
return false;
|
||||
UV uv = (UV)o;
|
||||
return u == uv.u && v == uv.v;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
public class UVScale implements IUVTransformation
|
||||
{
|
||||
double su;
|
||||
double sv;
|
||||
|
||||
public UVScale(double scaleu, double scalev)
|
||||
{
|
||||
su = scaleu;
|
||||
sv = scalev;
|
||||
}
|
||||
|
||||
public UVScale(double d)
|
||||
{
|
||||
this(d, d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(UV uv)
|
||||
{
|
||||
uv.u*=su;
|
||||
uv.v*=sv;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package codechicken.lib.render;
|
||||
|
||||
public class UVTranslation implements IUVTransformation
|
||||
{
|
||||
public double du;
|
||||
public double dv;
|
||||
|
||||
public UVTranslation(double u, double v)
|
||||
{
|
||||
du = u;
|
||||
dv = v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(UV texcoord)
|
||||
{
|
||||
texcoord.u+=du;
|
||||
texcoord.v+=dv;
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,13 @@ import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import codechicken.lib.render.uv.UV;
|
||||
import codechicken.lib.render.uv.UVTransformation;
|
||||
import codechicken.lib.util.Copyable;
|
||||
import codechicken.lib.vec.Transformation;
|
||||
import codechicken.lib.vec.Vector3;
|
||||
|
||||
public class Vertex5
|
||||
public class Vertex5 implements Copyable<Vertex5>
|
||||
{
|
||||
public Vector3 vec;
|
||||
public UV uv;
|
||||
@@ -32,7 +35,7 @@ public class Vertex5
|
||||
{
|
||||
this(new Vector3(x, y, z), new UV(u, v));
|
||||
}
|
||||
|
||||
|
||||
public Vertex5 set(double x, double y, double z, double u, double v)
|
||||
{
|
||||
vec.set(x, y, z);
|
||||
@@ -40,6 +43,19 @@ public class Vertex5
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vertex5 set(double x, double y, double z, double u, double v, int tex)
|
||||
{
|
||||
vec.set(x, y, z);
|
||||
uv.set(u, v, tex);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vertex5 set(Vertex5 vert) {
|
||||
vec.set(vert.vec);
|
||||
uv.set(vert.uv);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vertex5(Vertex5 vertex5)
|
||||
{
|
||||
this(vertex5.vec.copy(), vertex5.uv.copy());
|
||||
@@ -62,7 +78,7 @@ public class Vertex5
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vertex5 apply(IUVTransformation t)
|
||||
public Vertex5 apply(UVTransformation t)
|
||||
{
|
||||
uv.apply(t);
|
||||
return this;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package codechicken.lib.render.uv;
|
||||
|
||||
import codechicken.lib.vec.IrreversibleTransformationException;
|
||||
import net.minecraft.util.IIcon;
|
||||
|
||||
public class IconTransformation extends UVTransformation {
|
||||
public IIcon icon;
|
||||
|
||||
public IconTransformation(IIcon icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(UV uv) {
|
||||
uv.u = icon.getInterpolatedU(uv.u * 16);
|
||||
uv.v = icon.getInterpolatedV(uv.v * 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UVTransformation inverse() {
|
||||
throw new IrreversibleTransformationException(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package codechicken.lib.render.uv;
|
||||
|
||||
import codechicken.lib.vec.IrreversibleTransformationException;
|
||||
import net.minecraft.util.IIcon;
|
||||
|
||||
public class MultiIconTransformation extends UVTransformation {
|
||||
public IIcon[] icons;
|
||||
|
||||
public MultiIconTransformation(IIcon... icons) {
|
||||
this.icons = icons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(UV uv) {
|
||||
IIcon icon = icons[uv.tex % icons.length];
|
||||
uv.u = icon.getInterpolatedU(uv.u * 16);
|
||||
uv.v = icon.getInterpolatedV(uv.v * 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UVTransformation inverse() {
|
||||
throw new IrreversibleTransformationException(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package codechicken.lib.render.uv;
|
||||
|
||||
import codechicken.lib.util.Copyable;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
public class UV implements Copyable<UV> {
|
||||
public double u;
|
||||
public double v;
|
||||
public int tex;
|
||||
|
||||
public UV() {
|
||||
}
|
||||
|
||||
public UV(double u, double v) {
|
||||
this(u, v, 0);
|
||||
}
|
||||
|
||||
public UV(double u, double v, int tex) {
|
||||
this.u = u;
|
||||
this.v = v;
|
||||
this.tex = tex;
|
||||
}
|
||||
|
||||
public UV(UV uv) {
|
||||
this(uv.u, uv.v, uv.tex);
|
||||
}
|
||||
|
||||
public UV set(double u, double v, int tex) {
|
||||
this.u = u;
|
||||
this.v = v;
|
||||
this.tex = tex;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UV set(double u, double v) {
|
||||
return set(u, v, tex);
|
||||
}
|
||||
|
||||
public UV set(UV uv) {
|
||||
return set(uv.u, uv.v, uv.tex);
|
||||
}
|
||||
|
||||
public UV copy() {
|
||||
return new UV(this);
|
||||
}
|
||||
|
||||
public UV add(UV uv) {
|
||||
u += uv.u;
|
||||
v += uv.v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UV multiply(double d) {
|
||||
u *= d;
|
||||
v *= d;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
MathContext cont = new MathContext(4, RoundingMode.HALF_UP);
|
||||
return "UV(" + new BigDecimal(u, cont) + ", " + new BigDecimal(v, cont) + ")";
|
||||
}
|
||||
|
||||
public UV apply(UVTransformation t) {
|
||||
t.apply(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof UV))
|
||||
return false;
|
||||
UV uv = (UV) o;
|
||||
return u == uv.u && v == uv.v;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package codechicken.lib.render.uv;
|
||||
|
||||
import codechicken.lib.math.MathHelper;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
public class UVRotation extends UVTransformation
|
||||
{
|
||||
public double angle;
|
||||
|
||||
/**
|
||||
* @param angle The angle to rotate counterclockwise in radians
|
||||
*/
|
||||
public UVRotation(double angle) {
|
||||
this.angle = angle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(UV uv) {
|
||||
double c = MathHelper.cos(angle);
|
||||
double s = MathHelper.sin(angle);
|
||||
double u2 = c*uv.u + s*uv.v;
|
||||
uv.v = - s*uv.u + c*uv.v;
|
||||
uv.u = u2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UVTransformation inverse() {
|
||||
return new UVRotation(-angle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UVTransformation merge(UVTransformation next) {
|
||||
if(next instanceof UVRotation)
|
||||
return new UVRotation(angle+((UVRotation)next).angle);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRedundant() {
|
||||
return MathHelper.between(-1E-5, angle, 1E-5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
MathContext cont = new MathContext(4, RoundingMode.HALF_UP);
|
||||
return "UVRotation(" + new BigDecimal(angle, cont) + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package codechicken.lib.render.uv;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
public class UVScale extends UVTransformation {
|
||||
double su;
|
||||
double sv;
|
||||
|
||||
public UVScale(double scaleu, double scalev) {
|
||||
su = scaleu;
|
||||
sv = scalev;
|
||||
}
|
||||
|
||||
public UVScale(double d) {
|
||||
this(d, d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(UV uv) {
|
||||
uv.u *= su;
|
||||
uv.v *= sv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UVTransformation inverse() {
|
||||
return new UVScale(1 / su, 1 / sv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
MathContext cont = new MathContext(4, RoundingMode.HALF_UP);
|
||||
return "UVScale(" + new BigDecimal(su, cont) + ", " + new BigDecimal(sv, cont) + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package codechicken.lib.render.uv;
|
||||
|
||||
import codechicken.lib.render.CCRenderState;
|
||||
import codechicken.lib.vec.ITransformation;
|
||||
|
||||
/**
|
||||
* Abstract supertype for any UV transformation
|
||||
*/
|
||||
public abstract class UVTransformation extends ITransformation<UV, UVTransformation> implements CCRenderState.IVertexOperation
|
||||
{
|
||||
public static final int operationIndex = CCRenderState.registerOperation();
|
||||
|
||||
public UVTransformation at(UV point) {
|
||||
return new UVTransformationList(new UVTranslation(-point.u, -point.v), this, new UVTranslation(point.u, point.v));
|
||||
}
|
||||
|
||||
public UVTransformationList with(UVTransformation t) {
|
||||
return new UVTransformationList(this, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean load() {
|
||||
return !isRedundant();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate() {
|
||||
apply(CCRenderState.vert.uv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int operationID() {
|
||||
return operationIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
package codechicken.lib.render.uv;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class UVTransformationList extends UVTransformation
|
||||
{
|
||||
private ArrayList<UVTransformation> transformations = new ArrayList<UVTransformation>();
|
||||
|
||||
public UVTransformationList(UVTransformation... transforms)
|
||||
{
|
||||
for(UVTransformation t : transforms)
|
||||
if(t instanceof UVTransformationList)
|
||||
transformations.addAll(((UVTransformationList)t).transformations);
|
||||
else
|
||||
transformations.add(t);
|
||||
|
||||
compact();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(UV uv)
|
||||
{
|
||||
for(int i = 0; i < transformations.size(); i++)
|
||||
transformations.get(i).apply(uv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UVTransformationList with(UVTransformation t)
|
||||
{
|
||||
if(t.isRedundant())
|
||||
return this;
|
||||
|
||||
if(t instanceof UVTransformationList)
|
||||
transformations.addAll(((UVTransformationList)t).transformations);
|
||||
else
|
||||
transformations.add(t);
|
||||
|
||||
compact();
|
||||
return this;
|
||||
}
|
||||
|
||||
public UVTransformationList prepend(UVTransformation t)
|
||||
{
|
||||
if(t.isRedundant())
|
||||
return this;
|
||||
|
||||
if(t instanceof UVTransformationList)
|
||||
transformations.addAll(0, ((UVTransformationList)t).transformations);
|
||||
else
|
||||
transformations.add(0, t);
|
||||
|
||||
compact();
|
||||
return this;
|
||||
}
|
||||
|
||||
private void compact() {
|
||||
ArrayList<UVTransformation> newList = new ArrayList<UVTransformation>(transformations.size());
|
||||
Iterator<UVTransformation> iterator = transformations.iterator();
|
||||
UVTransformation prev = null;
|
||||
while(iterator.hasNext()) {
|
||||
UVTransformation t = iterator.next();
|
||||
if(t.isRedundant())
|
||||
continue;
|
||||
|
||||
if(prev != null) {
|
||||
UVTransformation m = prev.merge(t);
|
||||
if(m == null)
|
||||
newList.add(prev);
|
||||
else if(m.isRedundant())
|
||||
t = null;
|
||||
else
|
||||
t = m;
|
||||
}
|
||||
prev = t;
|
||||
}
|
||||
if(prev != null)
|
||||
newList.add(prev);
|
||||
|
||||
if(newList.size() < transformations.size())
|
||||
transformations = newList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRedundant() {
|
||||
return transformations.size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UVTransformation inverse()
|
||||
{
|
||||
UVTransformationList rev = new UVTransformationList();
|
||||
for(int i = transformations.size()-1; i >= 0; i--)
|
||||
rev.with(transformations.get(i).inverse());
|
||||
return rev;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String s = "";
|
||||
for(UVTransformation t : transformations)
|
||||
s+="\n"+t.toString();
|
||||
return s.trim();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package codechicken.lib.render.uv;
|
||||
|
||||
import codechicken.lib.math.MathHelper;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
public class UVTranslation extends UVTransformation {
|
||||
public double du;
|
||||
public double dv;
|
||||
|
||||
public UVTranslation(double u, double v) {
|
||||
du = u;
|
||||
dv = v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(UV uv) {
|
||||
uv.u += du;
|
||||
uv.v += dv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UVTransformation at(UV point) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UVTransformation inverse() {
|
||||
return new UVTranslation(-du, -dv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UVTransformation merge(UVTransformation next) {
|
||||
if (next instanceof UVTranslation) {
|
||||
UVTranslation t = (UVTranslation)next;
|
||||
return new UVTranslation(du+t.du, dv+t.dv);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRedundant() {
|
||||
return MathHelper.between(-1E-5, du, 1E-5) && MathHelper.between(-1E-5, dv, 1E-5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
MathContext cont = new MathContext(4, RoundingMode.HALF_UP);
|
||||
return "UVTranslation(" + new BigDecimal(du, cont) + ", " + new BigDecimal(dv, cont) + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package codechicken.lib.util;
|
||||
|
||||
public interface Copyable<T> {
|
||||
public T copy();
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package codechicken.lib.vec;
|
||||
|
||||
import codechicken.lib.util.Copyable;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import codechicken.lib.math.MathHelper;
|
||||
|
||||
public class BlockCoord implements Comparable<BlockCoord>
|
||||
public class BlockCoord implements Comparable<BlockCoord>, Copyable<BlockCoord>
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
|
||||
@@ -4,10 +4,11 @@ import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import codechicken.lib.util.Copyable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
|
||||
public class Cuboid6
|
||||
public class Cuboid6 implements Copyable<Cuboid6>
|
||||
{
|
||||
public static Cuboid6 full = new Cuboid6(0, 0, 0, 1, 1, 1);
|
||||
|
||||
@@ -47,7 +48,23 @@ public class Cuboid6
|
||||
{
|
||||
return new Cuboid6(this);
|
||||
}
|
||||
|
||||
|
||||
public Cuboid6 set(Cuboid6 c) {
|
||||
return set(c.min, c.max);
|
||||
}
|
||||
|
||||
public Cuboid6 set(Vector3 min, Vector3 max) {
|
||||
this.min.set(min);
|
||||
this.max.set(max);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Cuboid6 set(double minx, double miny, double minz, double maxx, double maxy, double maxz) {
|
||||
min.set(minx, miny, minz);
|
||||
max.set(maxx, maxy, maxz);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Cuboid6 add(Vector3 vec)
|
||||
{
|
||||
min.add(vec);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package codechicken.lib.vec;
|
||||
|
||||
import codechicken.lib.util.Copyable;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class CuboidCoord implements Iterable<BlockCoord>
|
||||
public class CuboidCoord implements Iterable<BlockCoord>, Copyable<CuboidCoord>
|
||||
{
|
||||
public BlockCoord min;
|
||||
public BlockCoord max;
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package codechicken.lib.vec;
|
||||
|
||||
/**
|
||||
* Abstract supertype for any VectorN transformation
|
||||
* @param <Vector> The vector type
|
||||
* @param <Transformation> The transformation type
|
||||
*/
|
||||
public abstract class ITransformation<Vector, Transformation extends ITransformation>
|
||||
{
|
||||
/**
|
||||
* Applies this transformation to vec
|
||||
*/
|
||||
public abstract void apply(Vector vec);
|
||||
|
||||
/**
|
||||
* @param point The point to apply this transformation around
|
||||
* @return Wraps this transformation in a translation to point and then back from point
|
||||
*/
|
||||
public abstract Transformation at(Vector point);
|
||||
|
||||
/**
|
||||
* Creates a TransformationList composed of this transformation followed by t
|
||||
* If this is a TransformationList, the transformation will be appended and this returned
|
||||
*/
|
||||
public abstract Transformation with(Transformation t);
|
||||
|
||||
/**
|
||||
* Returns a simplified transformation that performs this, followed by next. If such a transformation does not exist, returns null
|
||||
*/
|
||||
public Transformation merge(Transformation next) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this transformation is redundant, eg. Scale(1, 1, 1), Translation(0, 0, 0) or Rotation(0, a, b, c)
|
||||
*/
|
||||
public boolean isRedundant() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract Transformation inverse();
|
||||
|
||||
/**
|
||||
* Scala ++ operator
|
||||
*/
|
||||
public Transformation $plus$plus(Transformation t) {
|
||||
return with(t);
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@ package codechicken.lib.vec;
|
||||
@SuppressWarnings("serial")
|
||||
public class IrreversibleTransformationException extends RuntimeException
|
||||
{
|
||||
public Transformation t;
|
||||
public ITransformation t;
|
||||
|
||||
public IrreversibleTransformationException(Transformation t)
|
||||
public IrreversibleTransformationException(ITransformation t)
|
||||
{
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
@@ -7,12 +7,13 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.DoubleBuffer;
|
||||
|
||||
import codechicken.lib.util.Copyable;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class Matrix4 extends Transformation
|
||||
public class Matrix4 extends Transformation implements Copyable<Matrix4>
|
||||
{
|
||||
private static DoubleBuffer glBuf = ByteBuffer.allocateDirect(16*8).order(ByteOrder.nativeOrder()).asDoubleBuffer();
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import codechicken.lib.math.MathHelper;
|
||||
import codechicken.lib.util.Copyable;
|
||||
|
||||
public class Quat
|
||||
public class Quat implements Copyable<Quat>
|
||||
{
|
||||
public double x;
|
||||
public double y;
|
||||
public double z;
|
||||
public double s;
|
||||
public static final double SQRT2 = Math.sqrt(2D);
|
||||
|
||||
public Quat()
|
||||
{
|
||||
|
||||
@@ -139,7 +139,7 @@ public class Rotation extends Transformation
|
||||
{
|
||||
Vector3 axis = Rotation.axes[rotateSide(side^1, r)];
|
||||
double d = look.scalarProject(axis);
|
||||
if(max > d)//TODO wrong way round
|
||||
if(d > max)
|
||||
{
|
||||
max = d;
|
||||
maxr = r;
|
||||
|
||||
@@ -9,72 +9,62 @@ import org.lwjgl.opengl.GL11;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class Scale extends Transformation
|
||||
{
|
||||
private Vector3 factor;
|
||||
|
||||
public Scale(Vector3 factor)
|
||||
{
|
||||
public class Scale extends Transformation {
|
||||
public Vector3 factor;
|
||||
|
||||
public Scale(Vector3 factor) {
|
||||
this.factor = factor;
|
||||
}
|
||||
|
||||
public Scale(double factor)
|
||||
{
|
||||
public Scale(double factor) {
|
||||
this(new Vector3(factor, factor, factor));
|
||||
}
|
||||
|
||||
public Scale(double x, double y, double z)
|
||||
{
|
||||
|
||||
public Scale(double x, double y, double z) {
|
||||
this(new Vector3(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Vector3 vec)
|
||||
{
|
||||
public void apply(Vector3 vec) {
|
||||
vec.multiply(factor);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void applyN(Vector3 normal)
|
||||
{
|
||||
public void applyN(Vector3 normal) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void apply(Matrix4 mat)
|
||||
{
|
||||
public void apply(Matrix4 mat) {
|
||||
mat.scale(factor);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void glApply()
|
||||
{
|
||||
public void glApply() {
|
||||
GL11.glScaled(factor.x, factor.y, factor.z);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Transformation inverse()
|
||||
{
|
||||
return new Scale(1/factor.x, 1/factor.y, 1/factor.z);
|
||||
public Transformation inverse() {
|
||||
return new Scale(1 / factor.x, 1 / factor.y, 1 / factor.z);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Transformation merge(Transformation next) {
|
||||
if(next instanceof Scale)
|
||||
if (next instanceof Scale)
|
||||
return new Scale(factor.copy().multiply(((Scale) next).factor));
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRedundant() {
|
||||
return factor.equalsT(Vector3.one);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
public String toString() {
|
||||
MathContext cont = new MathContext(4, RoundingMode.HALF_UP);
|
||||
return "Scale("+new BigDecimal(factor.x, cont)+", "+new BigDecimal(factor.y, cont)+", "+new BigDecimal(factor.z, cont)+")";
|
||||
return "Scale(" + new BigDecimal(factor.x, cont) + ", " + new BigDecimal(factor.y, cont) + ", " + new BigDecimal(factor.z, cont) + ")";
|
||||
}
|
||||
}
|
||||
@@ -1,72 +1,54 @@
|
||||
package codechicken.lib.vec;
|
||||
|
||||
import codechicken.lib.render.CCRenderState;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* Interface for any 3D vector transformation
|
||||
* Abstract supertype for any 3D vector transformation
|
||||
*/
|
||||
public abstract class Transformation
|
||||
{
|
||||
/**
|
||||
* Applies this transformation to a position vector
|
||||
* @param vec The vector to transform
|
||||
*/
|
||||
public abstract void apply(Vector3 vec);
|
||||
|
||||
public abstract class Transformation extends ITransformation<Vector3, Transformation> implements CCRenderState.IVertexOperation
|
||||
{
|
||||
public static final int operationIndex = CCRenderState.registerOperation();
|
||||
|
||||
/**
|
||||
* Applies this transformation to a normal (doesn't translate)
|
||||
* @param normal The normal to transform
|
||||
*/
|
||||
public abstract void applyN(Vector3 normal);
|
||||
|
||||
|
||||
/**
|
||||
* Applies this transformation to a matrix as a multiplication on the right hand side.
|
||||
* @param mat The matrix to combine this transformation with
|
||||
*/
|
||||
public abstract void apply(Matrix4 mat);
|
||||
|
||||
/**
|
||||
* @param point The point in OBJECT space to apply this transformation around
|
||||
* @return Wraps this transformation in a translation to point and then back from point
|
||||
*/
|
||||
public Transformation at(Vector3 point)
|
||||
{
|
||||
|
||||
public Transformation at(Vector3 point) {
|
||||
return new TransformationList(new Translation(-point.x, -point.y, -point.z), this, point.translation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a transformation list composed of this transformation followed by t
|
||||
* If this is a TransformationList, the transformation will be appended and this returned
|
||||
*/
|
||||
public TransformationList with(Transformation t)
|
||||
{
|
||||
|
||||
public TransformationList with(Transformation t) {
|
||||
return new TransformationList(this, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a simplified transformation that performs this, followed by next. If such a transformation does not exist, returns null
|
||||
*/
|
||||
public Transformation merge(Transformation next)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this transformation is redundant, eg. Scale(1, 1, 1), Translation(0, 0, 0) or Rotation(0, a, b, c)
|
||||
*/
|
||||
public boolean isRedundant()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public abstract void glApply();
|
||||
|
||||
public abstract Transformation inverse();
|
||||
|
||||
public TransformationList $plus$plus(Transformation t)
|
||||
{
|
||||
return with(t);
|
||||
@Override
|
||||
public boolean load() {
|
||||
CCRenderState.pipeline.addRequirement(CCRenderState.normalAttrib.operationID());
|
||||
return !isRedundant();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate() {
|
||||
apply(CCRenderState.vert.vec);
|
||||
if(CCRenderState.normalAttrib.active)
|
||||
applyN(CCRenderState.normal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int operationID() {
|
||||
return operationIndex;
|
||||
}
|
||||
}
|
||||
@@ -9,73 +9,63 @@ import org.lwjgl.opengl.GL11;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class Translation extends Transformation
|
||||
{
|
||||
private Vector3 vec;
|
||||
|
||||
public Translation(Vector3 vec)
|
||||
{
|
||||
public class Translation extends Transformation {
|
||||
public Vector3 vec;
|
||||
|
||||
public Translation(Vector3 vec) {
|
||||
this.vec = vec;
|
||||
}
|
||||
|
||||
public Translation(double x, double y, double z)
|
||||
{
|
||||
public Translation(double x, double y, double z) {
|
||||
this(new Vector3(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Vector3 vec)
|
||||
{
|
||||
public void apply(Vector3 vec) {
|
||||
vec.add(this.vec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyN(Vector3 normal)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Matrix4 mat)
|
||||
{
|
||||
public void applyN(Vector3 normal) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Matrix4 mat) {
|
||||
mat.translate(vec);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Transformation at(Vector3 point)
|
||||
{
|
||||
public Transformation at(Vector3 point) {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void glApply()
|
||||
{
|
||||
public void glApply() {
|
||||
GL11.glTranslated(vec.x, vec.y, vec.z);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Transformation inverse()
|
||||
{
|
||||
public Transformation inverse() {
|
||||
return new Translation(-vec.x, -vec.y, -vec.z);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Transformation merge(Transformation next) {
|
||||
if(next instanceof Translation)
|
||||
if (next instanceof Translation)
|
||||
return new Translation(vec.copy().add(((Translation) next).vec));
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRedundant() {
|
||||
return vec.equalsT(Vector3.zero);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
public String toString() {
|
||||
MathContext cont = new MathContext(4, RoundingMode.HALF_UP);
|
||||
return "Translation("+new BigDecimal(vec.x, cont)+", "+new BigDecimal(vec.y, cont)+", "+new BigDecimal(vec.z, cont)+")";
|
||||
return "Translation(" + new BigDecimal(vec.x, cont) + ", " + new BigDecimal(vec.y, cont) + ", " + new BigDecimal(vec.z, cont) + ")";
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import codechicken.lib.util.Copyable;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.util.vector.Vector3f;
|
||||
import org.lwjgl.util.vector.Vector4f;
|
||||
@@ -17,7 +18,7 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Vec3;
|
||||
|
||||
public class Vector3
|
||||
public class Vector3 implements Copyable<Vector3>
|
||||
{
|
||||
public static Vector3 zero = new Vector3();
|
||||
public static Vector3 one = new Vector3(1, 1, 1);
|
||||
|
||||
@@ -2,11 +2,11 @@ package codechicken.lib.world;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.ChunkCoordIntPair;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
|
||||
public abstract class ChunkExtension
|
||||
{
|
||||
@@ -42,7 +42,7 @@ public abstract class ChunkExtension
|
||||
public final void sendPacketToPlayers(Packet packet)
|
||||
{
|
||||
for(EntityPlayerMP player : watchedPlayers)
|
||||
player.playerNetServerHandler.sendPacketToPlayer(packet);
|
||||
player.playerNetServerHandler.sendPacket(packet);
|
||||
}
|
||||
|
||||
public final void watchPlayer(EntityPlayerMP player)
|
||||
|
||||
@@ -5,17 +5,16 @@ import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.ITickHandler;
|
||||
import cpw.mods.fml.common.TickType;
|
||||
import cpw.mods.fml.common.registry.TickRegistry;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.EmptyChunk;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.ForgeSubscribe;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.event.world.ChunkDataEvent;
|
||||
import net.minecraftforge.event.world.ChunkEvent;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
@@ -26,7 +25,7 @@ public class WorldExtensionManager
|
||||
{
|
||||
public static class WorldExtensionEventHandler
|
||||
{
|
||||
@ForgeSubscribe
|
||||
@SubscribeEvent
|
||||
public void onChunkDataLoad(ChunkDataEvent.Load event)
|
||||
{
|
||||
if(!worldMap.containsKey(event.world))
|
||||
@@ -38,7 +37,7 @@ public class WorldExtensionManager
|
||||
extension.loadChunkData(event.getChunk(), event.getData());
|
||||
}
|
||||
|
||||
@ForgeSubscribe
|
||||
@SubscribeEvent
|
||||
public void onChunkDataSave(ChunkDataEvent.Save event)
|
||||
{
|
||||
for(WorldExtension extension : worldMap.get(event.world))
|
||||
@@ -48,7 +47,7 @@ public class WorldExtensionManager
|
||||
removeChunk(event.world, event.getChunk());
|
||||
}
|
||||
|
||||
@ForgeSubscribe
|
||||
@SubscribeEvent
|
||||
public void onChunkLoad(ChunkEvent.Load event)
|
||||
{
|
||||
if(!worldMap.containsKey(event.world))
|
||||
@@ -60,7 +59,7 @@ public class WorldExtensionManager
|
||||
extension.loadChunk(event.getChunk());
|
||||
}
|
||||
|
||||
@ForgeSubscribe
|
||||
@SubscribeEvent
|
||||
public void onChunkUnLoad(ChunkEvent.Unload event)
|
||||
{
|
||||
if(event.getChunk() instanceof EmptyChunk)
|
||||
@@ -73,7 +72,7 @@ public class WorldExtensionManager
|
||||
removeChunk(event.world, event.getChunk());
|
||||
}
|
||||
|
||||
@ForgeSubscribe
|
||||
@SubscribeEvent
|
||||
public void onWorldSave(WorldEvent.Save event)
|
||||
{
|
||||
if(worldMap.containsKey(event.world))
|
||||
@@ -81,14 +80,14 @@ public class WorldExtensionManager
|
||||
extension.save();
|
||||
}
|
||||
|
||||
@ForgeSubscribe
|
||||
@SubscribeEvent
|
||||
public void onWorldLoad(WorldEvent.Load event)
|
||||
{
|
||||
if(!worldMap.containsKey(event.world))
|
||||
WorldExtensionManager.onWorldLoad(event.world);
|
||||
}
|
||||
|
||||
@ForgeSubscribe
|
||||
@SubscribeEvent
|
||||
public void onWorldUnLoad(WorldEvent.Unload event)
|
||||
{
|
||||
if(worldMap.containsKey(event.world))//because force closing unloads a world twice
|
||||
@@ -96,7 +95,7 @@ public class WorldExtensionManager
|
||||
extension.unload();
|
||||
}
|
||||
|
||||
@ForgeSubscribe
|
||||
@SubscribeEvent
|
||||
public void onChunkWatch(Watch event)
|
||||
{
|
||||
Chunk chunk = event.player.worldObj.getChunkFromChunkCoords(event.chunk.chunkXPos, event.chunk.chunkZPos);
|
||||
@@ -104,82 +103,34 @@ public class WorldExtensionManager
|
||||
extension.watchChunk(chunk, event.player);
|
||||
}
|
||||
|
||||
@ForgeSubscribe
|
||||
@SubscribeEvent
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onChunkUnWatch(UnWatch event)
|
||||
{
|
||||
Chunk chunk = event.player.worldObj.getChunkFromChunkCoords(event.chunk.chunkXPos, event.chunk.chunkZPos);
|
||||
for(WorldExtension extension : worldMap.get(event.player.worldObj))
|
||||
extension.unwatchChunk(chunk, event.player);
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorldExtensionClientTickHandler implements ITickHandler
|
||||
{
|
||||
@Override
|
||||
public void tickStart(EnumSet<TickType> type, Object... tickData)
|
||||
|
||||
@SubscribeEvent
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void clientTick(TickEvent.ClientTickEvent event)
|
||||
{
|
||||
if(type.contains(TickType.CLIENT))
|
||||
{
|
||||
World world = Minecraft.getMinecraft().theWorld;
|
||||
if(worldMap.containsKey(world))
|
||||
World world = Minecraft.getMinecraft().theWorld;
|
||||
if (worldMap.containsKey(world))
|
||||
if (event.phase == TickEvent.Phase.START)
|
||||
preTick(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tickEnd(EnumSet<TickType> type, Object... tickData)
|
||||
{
|
||||
if(type.contains(TickType.CLIENT))
|
||||
{
|
||||
World world = Minecraft.getMinecraft().theWorld;
|
||||
if(worldMap.containsKey(world))
|
||||
else
|
||||
postTick(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<TickType> ticks()
|
||||
@SubscribeEvent
|
||||
public void clientTick(TickEvent.WorldTickEvent event)
|
||||
{
|
||||
return EnumSet.of(TickType.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel()
|
||||
{
|
||||
return "WorldExtenstions";
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorldExtensionServerTickHandler implements ITickHandler
|
||||
{
|
||||
@Override
|
||||
public void tickStart(EnumSet<TickType> type, Object... tickData)
|
||||
{
|
||||
if(type.contains(TickType.WORLD))
|
||||
{
|
||||
preTick((World)tickData[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tickEnd(EnumSet<TickType> type, Object... tickData)
|
||||
{
|
||||
if(type.contains(TickType.WORLD))
|
||||
{
|
||||
postTick((World)tickData[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<TickType> ticks()
|
||||
{
|
||||
return EnumSet.of(TickType.WORLD, TickType.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel()
|
||||
{
|
||||
return "WorldExtenstions";
|
||||
if(event.phase == TickEvent.Phase.START)
|
||||
preTick(event.world);
|
||||
else
|
||||
postTick(event.world);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,11 +150,7 @@ public class WorldExtensionManager
|
||||
{
|
||||
initialised = true;
|
||||
MinecraftForge.EVENT_BUS.register(new WorldExtensionEventHandler());
|
||||
TickRegistry.registerTickHandler(new WorldExtensionServerTickHandler(), Side.SERVER);
|
||||
if(FMLCommonHandler.instance().getSide().isClient())
|
||||
{
|
||||
TickRegistry.registerTickHandler(new WorldExtensionClientTickHandler(), Side.CLIENT);
|
||||
}
|
||||
FMLCommonHandler.instance().bus().register(new WorldExtensionEventHandler());
|
||||
}
|
||||
|
||||
private static HashMap<World, WorldExtension[]> worldMap = new HashMap<World, WorldExtension[]>();
|
||||
|
||||
Reference in new issue
Block a user