package openmods.stencil;
import openmods.Log;
import openmods.api.IResultListener;
import openmods.asm.MappedType;
import openmods.asm.MethodMatcher;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class FramebufferInjector extends ClassVisitor {
private static final MappedType openGlHelper = MappedType.of("net/minecraft/client/renderer/OpenGlHelper");
private static final MethodMatcher createRenderbufferMatcher;
private final MethodMatcher targetMethod;
private static final Type hookType = Type.getType(FramebufferHooks.class);
private final String className;
private final IResultListener listener;
static {
Type createRenderbufferType = Type.getMethodType(Type.VOID_TYPE, Type.INT_TYPE, Type.INT_TYPE, Type.INT_TYPE, Type.INT_TYPE);
createRenderbufferMatcher = new MethodMatcher(openGlHelper, createRenderbufferType.getDescriptor(), "func_153186_a", "func_153186_a");
}
private class CreateFramebufferInjector extends MethodVisitor {
private final Type ownerType;
private boolean constantFound;
public CreateFramebufferInjector(MethodVisitor mv) {
super(Opcodes.ASM5, mv);
this.ownerType = Type.getObjectType(className);
}
@Override
public void visitLdcInsn(Object cst) {
super.visitLdcInsn(cst);
if ((cst instanceof Number) && ((Number)cst).intValue() == 0x81A6 /* == 33190 == GL14.GL_DEPTH_COMPONENT24 */) {
Log.debug("Found GL constant, replacing method");
constantFound = true;
}
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean intf) {
if (constantFound && opcode == Opcodes.INVOKESTATIC && createRenderbufferMatcher.match(name, desc)) {
Log.debug("Injecting allocate and attach methods");
super.visitMethodInsn(Opcodes.INVOKESTATIC, hookType.getInternalName(), "createRenderbufferStorage", desc, false);
super.visitVarInsn(Opcodes.ALOAD, 0);
Type methodType = Type.getMethodType(Type.VOID_TYPE, ownerType);
super.visitMethodInsn(Opcodes.INVOKESTATIC, hookType.getInternalName(), "attachRenderbuffer", methodType.getDescriptor(), false);
listener.onSuccess();
} else {
super.visitMethodInsn(opcode, owner, name, desc, intf);
}
constantFound = false;
}
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor parent = super.visitMethod(access, name, desc, signature, exceptions);
return targetMethod.match(name, desc)? new CreateFramebufferInjector(parent) : parent;
}
public FramebufferInjector(String rawCls, ClassVisitor cv, IResultListener listener) {
super(Opcodes.ASM5, cv);
this.listener = listener;
this.className = rawCls.replace('.', '/');
Type targetType = Type.getMethodType(Type.VOID_TYPE, Type.INT_TYPE, Type.INT_TYPE);
targetMethod = new MethodMatcher(rawCls, targetType.getDescriptor(), "createFramebuffer", "func_147605_b");
}
}