Skip to content

Instantly share code, notes, and snippets.

@tterrag1098
Last active February 9, 2016 01:49
Show Gist options
  • Save tterrag1098/d013780e7d9c3d0f8a06 to your computer and use it in GitHub Desktop.
Save tterrag1098/d013780e7d9c3d0f8a06 to your computer and use it in GitHub Desktop.
package team.chisel.client.render;
import java.awt.geom.Rectangle2D;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nullable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.Value;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import net.minecraft.client.renderer.vertex.VertexFormatElement.EnumUsage;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.util.vector.Vector;
import org.lwjgl.util.vector.Vector2f;
import org.lwjgl.util.vector.Vector3f;
import com.google.common.base.Optional;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.MultimapBuilder;
@ToString(of = { "verts", "uvs" })
public class Quad {
@Value
public static class Vertex {
Vector3f pos;
Vector2f uvs;
}
@RequiredArgsConstructor
public static class UVs {
private static final TextureAtlasSprite BASE = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(TextureMap.LOCATION_MISSING_TEXTURE.toString());
private static final float BASE_WIDTH = BASE.getMaxU() - BASE.getMinU(), BASE_HEIGHT = BASE.getMaxV() - BASE.getMinV();
@Getter
private final TextureAtlasSprite sprite;
@Getter
final float minU, minV, maxU, maxV;
private UVs(Vector2f... data) {
this(BASE, data);
}
private UVs(TextureAtlasSprite sprite, Vector2f... data) {
this.sprite = sprite;
float minU = Float.MAX_VALUE;
float minV = Float.MAX_VALUE;
float maxU = 0, maxV = 0;
for (Vector2f v : data) {
minU = Math.min(minU, v.x);
minV = Math.min(minV, v.y);
maxU = Math.max(maxU, v.x);
maxV = Math.max(maxV, v.y);
}
this.minU = minU;
this.minV = minV;
this.maxU = maxU;
this.maxV = maxV;
}
public UVs transform(TextureAtlasSprite other) {
float scaleU = BASE_WIDTH / (other.getMaxU() - other.getMinU());
float scaleV = BASE_HEIGHT / (other.getMaxV() - other.getMinV());
float startU = (minU - BASE.getMinU()) * scaleU;
float startV = (minV - BASE.getMinV()) * scaleV;
float endU = (BASE.getMaxU() - maxU) * scaleU;
float endV = (BASE.getMaxV() - maxV) * scaleV;
return new UVs(other, startU + other.getMinU(), startV + other.getMinV(), other.getMaxU() - endU, other.getMaxV() - endV);
}
public UVs normalize() {
return new UVs(sprite, normalize(sprite.getMinU(), sprite.getMaxU(), this.minU), normalize(sprite.getMinV(), sprite.getMaxV(), this.minV), normalize(sprite.getMinU(), sprite.getMaxU(), this.maxU),
normalize(sprite.getMinV(), sprite.getMaxV(), this.maxV));
}
private float normalize(float min, float max, float x) {
return (x - min) / (max - min);
}
}
private final Vector3f[] verts;
@Getter
private final UVs uvs;
private final Builder builder;
private Quad(Vector3f[] verts, Vector2f[] uvs, Builder builder) {
this.verts = verts;
this.uvs = new UVs(uvs);
this.builder = builder;
}
public void compute() {
}
public Quad[] subdivide(int count) {
List<Quad> rects = Lists.newArrayList();
Pair<Quad, Optional<Quad>> firstDivide = divide(this, false);
rects.add(firstDivide.getLeft());
if (firstDivide.getRight().isPresent()) {
Quad split = firstDivide.getRight().get();
rects.add(split);
Pair<Quad, Optional<Quad>> secondDivide = divide(split, true);
rects.add(secondDivide.getLeft());
if (secondDivide.getRight().isPresent()) {
rects.add(secondDivide.getRight().get());
}
}
return rects.toArray(new Quad[rects.size()]);
}
@Nullable
private Pair<Quad, Optional<Quad>> divide(Quad quad, boolean vertical) {
float min, max;
UVs uvs = quad.getUvs().normalize();
if (vertical) {
min = uvs.minV;
max = uvs.maxV;
} else {
min = uvs.minU;
max = uvs.maxU;
}
if (min < 0.5 && max > 0.5) {
UVs first = new UVs(uvs.getSprite(), uvs.minU, uvs.minV, vertical ? uvs.maxU : 0.5f, vertical ? 0.5f : uvs.maxV);
UVs second = new UVs(uvs.getSprite(), vertical ? uvs.minU : 0.5f, vertical ? 0.5f : uvs.minV, uvs.maxU, uvs.maxV);
} else {
return Pair.of(quad, Optional.absent());
}
}
public static Quad from(BakedQuad baked, VertexFormat fmt) {
Builder b = new Builder(fmt);
baked.pipe(b);
return b.build();
}
@RequiredArgsConstructor
public static class Builder implements IVertexConsumer {
@Getter
private final VertexFormat vertexFormat;
@Setter
private int quadTint;
@Setter
private EnumFacing quadOrientation;
@Override
public void setQuadColored() {}
private ListMultimap<VertexFormatElement.EnumUsage, float[]> data = MultimapBuilder.enumKeys(EnumUsage.class).arrayListValues().build();
@Override
public void put(int element, float... data) {
if (element == 2) {
System.out.println(Arrays.toString(data));
}
float[] copy = new float[data.length];
System.arraycopy(data, 0, copy, 0, data.length);
this.data.put(vertexFormat.getElement(element).getUsage(), copy);
}
public Quad build() {
Vector3f[] verts = fromData(data.get(EnumUsage.POSITION), 3);
Vector2f[] uvs = fromData(data.get(EnumUsage.UV), 2);
return new Quad(verts, uvs, this);
}
@SuppressWarnings("unchecked")
private <T extends Vector> T[] fromData(List<float[]> data, int size) {
Vector[] ret = size == 2 ? new Vector2f[data.size()] : new Vector3f[data.size()];
for (int i = 0; i < data.size(); i++) {
ret[i] = size == 2 ? new Vector2f(data.get(i)[0], data.get(i)[1]) : new Vector3f(data.get(i)[0], data.get(i)[1], data.get(i)[2]);
}
return (T[]) ret;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment