pick 97420a31d The big reformat of 2020

This commit is contained in:
yueh
2020-06-16 21:41:28 +02:00
parent 5304b3febe
commit 5225ea426b
2252 changed files with 95466 additions and 118582 deletions
@@ -18,112 +18,101 @@
package appeng.thirdparty.codechicken.lib.math;
/**
* @author covers1624
*/
public class InterpHelper
{
public class InterpHelper {
private float[][] posCache = new float[4][2];
private float[] valCache = new float[4];
private float[][] posCache = new float[4][2];
private float[] valCache = new float[4];
private float x0;
private float x1;
private float y0;
private float y1;
private float x0;
private float x1;
private float y0;
private float y1;
private float rX;
private float rY;
private float rX;
private float rY;
private int p00;
private int p10;
private int p11;
private int p01;
private int p00;
private int p10;
private int p11;
private int p01;
/**
* Resets the interp helper with the given quad. Does not care what order the vertices are in.
*/
public void reset( float dx0, float dy0, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3 )
{
/**
* Resets the interp helper with the given quad. Does not care what order the
* vertices are in.
*/
public void reset(float dx0, float dy0, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) {
float[] vec0 = this.posCache[0];
float[] vec1 = this.posCache[1];
float[] vec2 = this.posCache[2];
float[] vec3 = this.posCache[3];
float[] vec0 = this.posCache[0];
float[] vec1 = this.posCache[1];
float[] vec2 = this.posCache[2];
float[] vec3 = this.posCache[3];
vec0[0] = dx0;
vec1[0] = dx1;
vec2[0] = dx2;
vec3[0] = dx3;
vec0[0] = dx0;
vec1[0] = dx1;
vec2[0] = dx2;
vec3[0] = dx3;
vec0[1] = dy0;
vec1[1] = dy1;
vec2[1] = dy2;
vec3[1] = dy3;
}
vec0[1] = dy0;
vec1[1] = dy1;
vec2[1] = dy2;
vec3[1] = dy3;
}
/**
* Call when you are ready to use the InterpHelper.
*/
public void setup()
{
this.p00 = 0;// Bottom Left is always first.
this.x0 = this.posCache[this.p00][0];
this.y0 = this.posCache[this.p00][1];
for( int i = 1; i < 4; i++ )
{
float x = this.posCache[i][0];
float y = this.posCache[i][1];
if( this.y0 == y )
{
this.p10 = i;// Bottom right.
this.x1 = x;
}
else if( this.x0 == x )
{
this.p01 = i;// Top left.
this.y1 = y;
}
else
{
// Top right.
this.p11 = i;
}
}
}
/**
* Call when you are ready to use the InterpHelper.
*/
public void setup() {
this.p00 = 0;// Bottom Left is always first.
this.x0 = this.posCache[this.p00][0];
this.y0 = this.posCache[this.p00][1];
for (int i = 1; i < 4; i++) {
float x = this.posCache[i][0];
float y = this.posCache[i][1];
if (this.y0 == y) {
this.p10 = i;// Bottom right.
this.x1 = x;
} else if (this.x0 == x) {
this.p01 = i;// Top left.
this.y1 = y;
} else {
// Top right.
this.p11 = i;
}
}
}
/**
* Computes the coefficients for the interpolation.
*
* @param x X interp location.
* @param y Y interp location.
*/
public void locate( float x, float y )
{
this.rX = ( x - this.x0 ) / ( this.x1 - this.x0 );
this.rY = ( y - this.y0 ) / ( this.y1 - this.y0 );
}
/**
* Computes the coefficients for the interpolation.
*
* @param x X interp location.
* @param y Y interp location.
*/
public void locate(float x, float y) {
this.rX = (x - this.x0) / (this.x1 - this.x0);
this.rY = (y - this.y0) / (this.y1 - this.y0);
}
/**
* Interpolates using the already computed coefficients.
*
* @param q0 Value at dx0 dy0
* @param q1 Value at dx1 dy1
* @param q2 Value at dx2 dy2
* @param q3 Value at dx3 dy3
*
* @return The result.
*/
public float interpolate( float q0, float q1, float q2, float q3 )
{
this.valCache[0] = q0;
this.valCache[1] = q1;
this.valCache[2] = q2;
this.valCache[3] = q3;
float f0 = ( this.valCache[this.p00] * ( 1 - this.rX ) ) + ( this.valCache[this.p10] * this.rX );
float f1 = ( this.valCache[this.p01] * ( 1 - this.rX ) ) + ( this.valCache[this.p11] * this.rX );
/**
* Interpolates using the already computed coefficients.
*
* @param q0 Value at dx0 dy0
* @param q1 Value at dx1 dy1
* @param q2 Value at dx2 dy2
* @param q3 Value at dx3 dy3
*
* @return The result.
*/
public float interpolate(float q0, float q1, float q2, float q3) {
this.valCache[0] = q0;
this.valCache[1] = q1;
this.valCache[2] = q2;
this.valCache[3] = q3;
float f0 = (this.valCache[this.p00] * (1 - this.rX)) + (this.valCache[this.p10] * this.rX);
float f1 = (this.valCache[this.p01] * (1 - this.rX)) + (this.valCache[this.p11] * this.rX);
return ( f0 * ( 1 - this.rY ) ) + ( f1 * this.rY );
}
return (f0 * (1 - this.rY)) + (f1 * this.rY);
}
}
@@ -18,156 +18,138 @@
package appeng.thirdparty.codechicken.lib.model;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
/**
* A simple VertexFormat cache.
* This caches the existence of attributes and their indexes.
* A simple VertexFormat cache. This caches the existence of attributes and
* their indexes.
*
* @author covers1624
*/
public class CachedFormat
{
public class CachedFormat {
public static final Map<VertexFormat, CachedFormat> formatCache = new ConcurrentHashMap<>();
public static final Map<VertexFormat, CachedFormat> formatCache = new ConcurrentHashMap<>();
/**
* Lookup or create the CachedFormat for a given VertexFormat.
*
* @param format The format to lookup.
*
* @return The CachedFormat.
*/
public static CachedFormat lookup( VertexFormat format )
{
return formatCache.computeIfAbsent( format, CachedFormat::new );
}
/**
* Lookup or create the CachedFormat for a given VertexFormat.
*
* @param format The format to lookup.
*
* @return The CachedFormat.
*/
public static CachedFormat lookup(VertexFormat format) {
return formatCache.computeIfAbsent(format, CachedFormat::new);
}
public VertexFormat format;
public VertexFormat format;
public boolean hasPosition;
public boolean hasNormal;
public boolean hasColor;
public boolean hasUV;
public boolean hasOverlay;
public boolean hasLightMap;
public boolean hasPosition;
public boolean hasNormal;
public boolean hasColor;
public boolean hasUV;
public boolean hasOverlay;
public boolean hasLightMap;
public int positionIndex = -1;
public int normalIndex = -1;
public int colorIndex = -1;
public int uvIndex = -1;
public int overlayIndex = -1;
public int lightMapIndex = -1;
public int positionIndex = -1;
public int normalIndex = -1;
public int colorIndex = -1;
public int uvIndex = -1;
public int overlayIndex = -1;
public int lightMapIndex = -1;
public int elementCount;
public int elementCount;
/**
* Caches the vertex format element indexes for efficiency.
*
* @param format The format.
*/
public CachedFormat( VertexFormat format )
{
this.format = format;
this.elementCount = format.getElements().size();
for( int i = 0; i < this.elementCount; i++ )
{
VertexFormatElement element = format.getElements().get( i );
switch( element.getUsage() )
{
case POSITION:
if( this.hasPosition )
{
throw new IllegalStateException( "Found 2 position elements.." );
}
this.hasPosition = true;
this.positionIndex = i;
break;
case NORMAL:
if( this.hasNormal )
{
throw new IllegalStateException( "Found 2 normal elements.." );
}
this.hasNormal = true;
this.normalIndex = i;
break;
case COLOR:
if( this.hasColor )
{
throw new IllegalStateException( "Found 2 color elements.." );
}
this.hasColor = true;
this.colorIndex = i;
break;
case UV:
switch( element.getIndex() )
{
case 0:
if( hasUV )
{
throw new IllegalStateException( "Found 2 UV elements.." );
}
hasUV = true;
uvIndex = i;
break;
case 1:
if( hasOverlay )
{
throw new IllegalStateException( "Found 2 Overlay elements.." );
}
hasOverlay = true;
overlayIndex = i;
break;
case 2:
if( hasLightMap )
{
throw new IllegalStateException( "Found 2 LightMap elements.." );
}
hasLightMap = true;
lightMapIndex = i;
break;
}
break;
}
}
}
/**
* Caches the vertex format element indexes for efficiency.
*
* @param format The format.
*/
public CachedFormat(VertexFormat format) {
this.format = format;
this.elementCount = format.getElements().size();
for (int i = 0; i < this.elementCount; i++) {
VertexFormatElement element = format.getElements().get(i);
switch (element.getUsage()) {
case POSITION:
if (this.hasPosition) {
throw new IllegalStateException("Found 2 position elements..");
}
this.hasPosition = true;
this.positionIndex = i;
break;
case NORMAL:
if (this.hasNormal) {
throw new IllegalStateException("Found 2 normal elements..");
}
this.hasNormal = true;
this.normalIndex = i;
break;
case COLOR:
if (this.hasColor) {
throw new IllegalStateException("Found 2 color elements..");
}
this.hasColor = true;
this.colorIndex = i;
break;
case UV:
switch (element.getIndex()) {
case 0:
if (hasUV) {
throw new IllegalStateException("Found 2 UV elements..");
}
hasUV = true;
uvIndex = i;
break;
case 1:
if (hasOverlay) {
throw new IllegalStateException("Found 2 Overlay elements..");
}
hasOverlay = true;
overlayIndex = i;
break;
case 2:
if (hasLightMap) {
throw new IllegalStateException("Found 2 LightMap elements..");
}
hasLightMap = true;
lightMapIndex = i;
break;
}
break;
}
}
}
@Override
public boolean equals( Object obj )
{
if( this == obj )
{
return true;
}
if( !( obj instanceof CachedFormat ) )
{
return false;
}
CachedFormat other = (CachedFormat) obj;
return other.elementCount == this.elementCount && //
other.positionIndex == this.positionIndex && //
other.normalIndex == this.normalIndex && //
other.colorIndex == this.colorIndex && //
other.uvIndex == this.uvIndex && //
other.lightMapIndex == this.lightMapIndex;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof CachedFormat)) {
return false;
}
CachedFormat other = (CachedFormat) obj;
return other.elementCount == this.elementCount && //
other.positionIndex == this.positionIndex && //
other.normalIndex == this.normalIndex && //
other.colorIndex == this.colorIndex && //
other.uvIndex == this.uvIndex && //
other.lightMapIndex == this.lightMapIndex;
}
@Override
public int hashCode()
{
int result = 1;
result = 31 * result + this.elementCount;
result = 31 * result + this.positionIndex;
result = 31 * result + this.normalIndex;
result = 31 * result + this.colorIndex;
result = 31 * result + this.uvIndex;
result = 31 * result + this.lightMapIndex;
return result;
}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + this.elementCount;
result = 31 * result + this.positionIndex;
result = 31 * result + this.normalIndex;
result = 31 * result + this.colorIndex;
result = 31 * result + this.uvIndex;
result = 31 * result + this.lightMapIndex;
return result;
}
}
@@ -18,25 +18,21 @@
package appeng.thirdparty.codechicken.lib.model;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
/**
* Marks a standard IVertexConsumer as compatible with {@link Quad}.
*
* @author covers1624
*/
public interface ISmartVertexConsumer extends IVertexConsumer
{
public interface ISmartVertexConsumer extends IVertexConsumer {
/**
* Assumes the data is already completely unpacked.
* You must always copy the data from the quad provided to an internal cache.
* basically:
* this.quad.put(quad);
*
* @param quad The quad to copy data from.
*/
void put( Quad quad );
/**
* Assumes the data is already completely unpacked. You must always copy the
* data from the quad provided to an internal cache. basically:
* this.quad.put(quad);
*
* @param quad The quad to copy data from.
*/
void put(Quad quad);
}
+411 -481
View File
@@ -18,7 +18,6 @@
package appeng.thirdparty.codechicken.lib.model;
import net.minecraft.client.renderer.Vector3f;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
@@ -33,529 +32,460 @@ import net.minecraftforge.client.model.pipeline.LightUtil;
import appeng.thirdparty.codechicken.lib.math.InterpHelper;
/**
* A simple easy to manipulate quad format. Can be reset and then used on a different format.
* A simple easy to manipulate quad format. Can be reset and then used on a
* different format.
*
* @author covers1624
*/
public class Quad implements IVertexProducer, ISmartVertexConsumer
{
public class Quad implements IVertexProducer, ISmartVertexConsumer {
public CachedFormat format;
public CachedFormat format;
public int tintIndex = -1;
public Direction orientation;
public boolean diffuseLighting = true;
public TextureAtlasSprite sprite;
public int tintIndex = -1;
public Direction orientation;
public boolean diffuseLighting = true;
public TextureAtlasSprite sprite;
public Vertex[] vertices = new Vertex[4];
public boolean full;
public Vertex[] vertices = new Vertex[4];
public boolean full;
// Not copied.
private int vertexIndex = 0;
// Cache for normal computation.
private Vector3f v1 = new Vector3f();
private Vector3f v2 = new Vector3f();
private Vector3f t = new Vector3f();
private Vector3f normal = new Vector3f();
// Not copied.
private int vertexIndex = 0;
// Cache for normal computation.
private Vector3f v1 = new Vector3f();
private Vector3f v2 = new Vector3f();
private Vector3f t = new Vector3f();
private Vector3f normal = new Vector3f();
/**
* Use this if you reset the quad each time you use it.
*/
public Quad()
{
}
/**
* Use this if you reset the quad each time you use it.
*/
public Quad() {
}
/**
* use this if you want to initialize the quad with a format.
*
* @param format The format.
*/
public Quad( CachedFormat format )
{
this.format = format;
}
/**
* use this if you want to initialize the quad with a format.
*
* @param format The format.
*/
public Quad(CachedFormat format) {
this.format = format;
}
@Override
public VertexFormat getVertexFormat()
{
return this.format.format;
}
@Override
public VertexFormat getVertexFormat() {
return this.format.format;
}
@Override
public void setQuadTint( int tint )
{
this.tintIndex = tint;
}
@Override
public void setQuadTint(int tint) {
this.tintIndex = tint;
}
@Override
public void setQuadOrientation( Direction orientation )
{
this.orientation = orientation;
}
@Override
public void setQuadOrientation(Direction orientation) {
this.orientation = orientation;
}
@Override
public void setApplyDiffuseLighting( boolean diffuse )
{
this.diffuseLighting = diffuse;
}
@Override
public void setApplyDiffuseLighting(boolean diffuse) {
this.diffuseLighting = diffuse;
}
@Override
public void setTexture( TextureAtlasSprite texture )
{
this.sprite = texture;
}
@Override
public void setTexture(TextureAtlasSprite texture) {
this.sprite = texture;
}
@Override
public void put( int element, float... data )
{
if( this.full )
{
throw new RuntimeException( "Unable to add data when full." );
}
Vertex v = this.vertices[this.vertexIndex];
if( v == null )
{
v = new Vertex( this.format );
this.vertices[this.vertexIndex] = v;
}
System.arraycopy( data, 0, v.raw[element], 0, data.length );
if( element == ( this.format.elementCount - 1 ) )
{
this.vertexIndex++;
if( this.vertexIndex == 4 )
{
this.vertexIndex = 0;
this.full = true;
if( this.orientation == null )
{
this.calculateOrientation( false );
}
}
}
}
@Override
public void put(int element, float... data) {
if (this.full) {
throw new RuntimeException("Unable to add data when full.");
}
Vertex v = this.vertices[this.vertexIndex];
if (v == null) {
v = new Vertex(this.format);
this.vertices[this.vertexIndex] = v;
}
System.arraycopy(data, 0, v.raw[element], 0, data.length);
if (element == (this.format.elementCount - 1)) {
this.vertexIndex++;
if (this.vertexIndex == 4) {
this.vertexIndex = 0;
this.full = true;
if (this.orientation == null) {
this.calculateOrientation(false);
}
}
}
}
@Override
public void put( Quad quad )
{
this.copyFrom( quad );
}
@Override
public void put(Quad quad) {
this.copyFrom(quad);
}
@Override
public void pipe( IVertexConsumer consumer )
{
if( consumer instanceof ISmartVertexConsumer )
{
( (ISmartVertexConsumer) consumer ).put( this );
}
else
{
consumer.setQuadTint( this.tintIndex );
consumer.setQuadOrientation( this.orientation );
consumer.setApplyDiffuseLighting( this.diffuseLighting );
consumer.setTexture( this.sprite );
for( Vertex v : this.vertices )
{
for( int e = 0; e < this.format.elementCount; e++ )
{
consumer.put( e, v.raw[e] );
}
}
}
}
@Override
public void pipe(IVertexConsumer consumer) {
if (consumer instanceof ISmartVertexConsumer) {
((ISmartVertexConsumer) consumer).put(this);
} else {
consumer.setQuadTint(this.tintIndex);
consumer.setQuadOrientation(this.orientation);
consumer.setApplyDiffuseLighting(this.diffuseLighting);
consumer.setTexture(this.sprite);
for (Vertex v : this.vertices) {
for (int e = 0; e < this.format.elementCount; e++) {
consumer.put(e, v.raw[e]);
}
}
}
}
/**
* Used to reset the interpolation values inside the provided helper.
*
* @param helper The helper.
* @param s The axis. side >> 1;
*
* @return The same helper.
*/
public InterpHelper resetInterp( InterpHelper helper, int s )
{
helper.reset( //
this.vertices[0].dx( s ), this.vertices[0].dy( s ), //
this.vertices[1].dx( s ), this.vertices[1].dy( s ), //
this.vertices[2].dx( s ), this.vertices[2].dy( s ), //
this.vertices[3].dx( s ), this.vertices[3].dy( s ) );
return helper;
}
/**
* Used to reset the interpolation values inside the provided helper.
*
* @param helper The helper.
* @param s The axis. side >> 1;
*
* @return The same helper.
*/
public InterpHelper resetInterp(InterpHelper helper, int s) {
helper.reset( //
this.vertices[0].dx(s), this.vertices[0].dy(s), //
this.vertices[1].dx(s), this.vertices[1].dy(s), //
this.vertices[2].dx(s), this.vertices[2].dy(s), //
this.vertices[3].dx(s), this.vertices[3].dy(s));
return helper;
}
/**
* Clamps the Quad inside the box.
*
* @param bb The box.
*/
public void clamp( AxisAlignedBB bb )
{
for( Vertex vertex : this.vertices )
{
float[] vec = vertex.vec;
vec[0] = (float) MathHelper.clamp( vec[0], bb.minX, bb.maxX );
vec[1] = (float) MathHelper.clamp( vec[1], bb.minY, bb.maxY );
vec[2] = (float) MathHelper.clamp( vec[2], bb.minZ, bb.maxZ );
}
this.calculateOrientation( true );
}
/**
* Clamps the Quad inside the box.
*
* @param bb The box.
*/
public void clamp(AxisAlignedBB bb) {
for (Vertex vertex : this.vertices) {
float[] vec = vertex.vec;
vec[0] = (float) MathHelper.clamp(vec[0], bb.minX, bb.maxX);
vec[1] = (float) MathHelper.clamp(vec[1], bb.minY, bb.maxY);
vec[2] = (float) MathHelper.clamp(vec[2], bb.minZ, bb.maxZ);
}
this.calculateOrientation(true);
}
/**
* Re-calculates the Orientation of this quad,
* optionally the normal vector.
*
* @param setNormal If the normal vector should be updated.
*/
public void calculateOrientation( boolean setNormal )
{
this.v1.set( this.vertices[3].vec );
this.t.set( this.vertices[1].vec );
this.v1.sub( this.t );
/**
* Re-calculates the Orientation of this quad, optionally the normal vector.
*
* @param setNormal If the normal vector should be updated.
*/
public void calculateOrientation(boolean setNormal) {
this.v1.set(this.vertices[3].vec);
this.t.set(this.vertices[1].vec);
this.v1.sub(this.t);
this.v2.set( this.vertices[2].vec );
this.t.set( this.vertices[0].vec );
this.v2.sub( this.t );
this.v2.set(this.vertices[2].vec);
this.t.set(this.vertices[0].vec);
this.v2.sub(this.t);
this.normal.set( this.v2.getX(), this.v2.getY(), this.v2.getZ() );
this.normal.cross( this.v1 );
this.normal.normalize();
this.normal.set(this.v2.getX(), this.v2.getY(), this.v2.getZ());
this.normal.cross(this.v1);
this.normal.normalize();
if( this.format.hasNormal && setNormal )
{
for( Vertex vertex : this.vertices )
{
vertex.normal[0] = this.normal.getX();
vertex.normal[1] = this.normal.getY();
vertex.normal[2] = this.normal.getZ();
vertex.normal[3] = 0;
}
}
this.orientation = Direction.getFacingFromVector( this.normal.getX(), this.normal.getY(), this.normal.getZ() );
}
if (this.format.hasNormal && setNormal) {
for (Vertex vertex : this.vertices) {
vertex.normal[0] = this.normal.getX();
vertex.normal[1] = this.normal.getY();
vertex.normal[2] = this.normal.getZ();
vertex.normal[3] = 0;
}
}
this.orientation = Direction.getFacingFromVector(this.normal.getX(), this.normal.getY(), this.normal.getZ());
}
/**
* Used to create a new quad complete copy of this one.
*
* @return The new quad.
*/
public Quad copy()
{
if( !this.full )
{
throw new RuntimeException( "Only copying full quads is supported." );
}
Quad quad = new Quad( this.format );
quad.tintIndex = this.tintIndex;
quad.orientation = this.orientation;
quad.diffuseLighting = this.diffuseLighting;
quad.sprite = this.sprite;
quad.full = true;
for( int i = 0; i < 4; i++ )
{
quad.vertices[i] = this.vertices[i].copy();
}
return quad;
}
/**
* Used to create a new quad complete copy of this one.
*
* @return The new quad.
*/
public Quad copy() {
if (!this.full) {
throw new RuntimeException("Only copying full quads is supported.");
}
Quad quad = new Quad(this.format);
quad.tintIndex = this.tintIndex;
quad.orientation = this.orientation;
quad.diffuseLighting = this.diffuseLighting;
quad.sprite = this.sprite;
quad.full = true;
for (int i = 0; i < 4; i++) {
quad.vertices[i] = this.vertices[i].copy();
}
return quad;
}
/**
* Copies the data inside the given quad to this one. This ignores VertexFormat, please make sure your quads are in
* the same format.
*
* @param quad The Quad to copy from.
*
* @return This quad.
*/
public Quad copyFrom( Quad quad )
{
this.tintIndex = quad.tintIndex;
this.orientation = quad.orientation;
this.diffuseLighting = quad.diffuseLighting;
this.sprite = quad.sprite;
this.full = quad.full;
for( int v = 0; v < 4; v++ )
{
for( int e = 0; e < this.format.elementCount; e++ )
{
System.arraycopy( quad.vertices[v].raw[e], 0, this.vertices[v].raw[e], 0, 4 );
}
}
return this;
}
/**
* Copies the data inside the given quad to this one. This ignores VertexFormat,
* please make sure your quads are in the same format.
*
* @param quad The Quad to copy from.
*
* @return This quad.
*/
public Quad copyFrom(Quad quad) {
this.tintIndex = quad.tintIndex;
this.orientation = quad.orientation;
this.diffuseLighting = quad.diffuseLighting;
this.sprite = quad.sprite;
this.full = quad.full;
for (int v = 0; v < 4; v++) {
for (int e = 0; e < this.format.elementCount; e++) {
System.arraycopy(quad.vertices[v].raw[e], 0, this.vertices[v].raw[e], 0, 4);
}
}
return this;
}
/**
* Reset the quad to the new format.
*
* @param format The new format.
*/
public void reset( CachedFormat format )
{
this.format = format;
this.tintIndex = -1;
this.orientation = null;
this.diffuseLighting = true;
this.sprite = null;
for( int i = 0; i < this.vertices.length; i++ )
{
Vertex v = this.vertices[i];
if( v == null )
{
this.vertices[i] = v = new Vertex( format );
}
v.reset( format );
}
this.vertexIndex = 0;
this.full = false;
}
/**
* Reset the quad to the new format.
*
* @param format The new format.
*/
public void reset(CachedFormat format) {
this.format = format;
this.tintIndex = -1;
this.orientation = null;
this.diffuseLighting = true;
this.sprite = null;
for (int i = 0; i < this.vertices.length; i++) {
Vertex v = this.vertices[i];
if (v == null) {
this.vertices[i] = v = new Vertex(format);
}
v.reset(format);
}
this.vertexIndex = 0;
this.full = false;
}
/**
* Bakes this Quad to a BakedQuad.
*
* @return The BakedQuad.
*/
public BakedQuad bake()
{
if( format.format != DefaultVertexFormats.BLOCK )
{
throw new IllegalStateException( "Unable to bake this quad to the specified format. " + format.format );
}
int[] packedData = new int[this.format.format.getSize()];
for( int v = 0; v < 4; v++ )
{
for( int e = 0; e < this.format.elementCount; e++ )
{
LightUtil.pack( this.vertices[v].raw[e], packedData, this.format.format, v, e );
}
}
return new BakedQuad( packedData, this.tintIndex, this.orientation, this.sprite, this.diffuseLighting );
}
/**
* Bakes this Quad to a BakedQuad.
*
* @return The BakedQuad.
*/
public BakedQuad bake() {
if (format.format != DefaultVertexFormats.BLOCK) {
throw new IllegalStateException("Unable to bake this quad to the specified format. " + format.format);
}
int[] packedData = new int[this.format.format.getSize()];
for (int v = 0; v < 4; v++) {
for (int e = 0; e < this.format.elementCount; e++) {
LightUtil.pack(this.vertices[v].raw[e], packedData, this.format.format, v, e);
}
}
return new BakedQuad(packedData, this.tintIndex, this.orientation, this.sprite, this.diffuseLighting);
}
/**
* A simple vertex format.
*/
public static class Vertex
{
/**
* A simple vertex format.
*/
public static class Vertex {
public CachedFormat format;
public CachedFormat format;
/**
* The raw data.
*/
public float[][] raw;
/**
* The raw data.
*/
public float[][] raw;
// References to the arrays inside raw.
public float[] vec;
public float[] normal;
public float[] color;
public float[] uv;
public float[] overlay;
public float[] lightmap;
// References to the arrays inside raw.
public float[] vec;
public float[] normal;
public float[] color;
public float[] uv;
public float[] overlay;
public float[] lightmap;
/**
* Create a new Vertex.
*
* @param format The format for the vertex.
*/
public Vertex( CachedFormat format )
{
this.format = format;
this.raw = new float[format.elementCount][4];
this.preProcess();
}
/**
* Create a new Vertex.
*
* @param format The format for the vertex.
*/
public Vertex(CachedFormat format) {
this.format = format;
this.raw = new float[format.elementCount][4];
this.preProcess();
}
/**
* Creates a new Vertex using the data inside the other. A copy!
*
* @param other The other.
*/
public Vertex( Vertex other )
{
this.format = other.format;
this.raw = other.raw.clone();
for( int v = 0; v < this.format.elementCount; v++ )
{
this.raw[v] = other.raw[v].clone();
}
this.preProcess();
}
/**
* Creates a new Vertex using the data inside the other. A copy!
*
* @param other The other.
*/
public Vertex(Vertex other) {
this.format = other.format;
this.raw = other.raw.clone();
for (int v = 0; v < this.format.elementCount; v++) {
this.raw[v] = other.raw[v].clone();
}
this.preProcess();
}
/**
* Pulls references to the individual element's arrays inside raw. Modifying the individual element arrays will
* update raw.
*/
public void preProcess()
{
if( this.format.hasPosition )
{
this.vec = this.raw[this.format.positionIndex];
}
if( this.format.hasNormal )
{
this.normal = this.raw[this.format.normalIndex];
}
if( this.format.hasColor )
{
this.color = this.raw[this.format.colorIndex];
}
if( this.format.hasUV )
{
this.uv = this.raw[this.format.uvIndex];
}
if( format.hasOverlay )
{
overlay = raw[format.overlayIndex];
}
if( this.format.hasLightMap )
{
this.lightmap = this.raw[this.format.lightMapIndex];
}
}
/**
* Pulls references to the individual element's arrays inside raw. Modifying the
* individual element arrays will update raw.
*/
public void preProcess() {
if (this.format.hasPosition) {
this.vec = this.raw[this.format.positionIndex];
}
if (this.format.hasNormal) {
this.normal = this.raw[this.format.normalIndex];
}
if (this.format.hasColor) {
this.color = this.raw[this.format.colorIndex];
}
if (this.format.hasUV) {
this.uv = this.raw[this.format.uvIndex];
}
if (format.hasOverlay) {
overlay = raw[format.overlayIndex];
}
if (this.format.hasLightMap) {
this.lightmap = this.raw[this.format.lightMapIndex];
}
}
/**
* Gets the 2d X coord for the given axis.
*
* @param s The axis. side >> 1
*
* @return The x coord.
*/
public float dx( int s )
{
if( s <= 1 )
{
return this.vec[0];
}
else
{
return this.vec[2];
}
}
/**
* Gets the 2d X coord for the given axis.
*
* @param s The axis. side >> 1
*
* @return The x coord.
*/
public float dx(int s) {
if (s <= 1) {
return this.vec[0];
} else {
return this.vec[2];
}
}
/**
* Gets the 2d Y coord for the given axis.
*
* @param s The axis. side >> 1
*
* @return The y coord.
*/
public float dy( int s )
{
if( s > 0 )
{
return this.vec[1];
}
else
{
return this.vec[2];
}
}
/**
* Gets the 2d Y coord for the given axis.
*
* @param s The axis. side >> 1
*
* @return The y coord.
*/
public float dy(int s) {
if (s > 0) {
return this.vec[1];
} else {
return this.vec[2];
}
}
/**
* Interpolates the new color values for this Vertex using the others as a reference.
*
* @param interpHelper The InterpHelper to use.
* @param others The other Vertices to use as a template.
*
* @return The same Vertex.
*/
public Vertex interpColorFrom( InterpHelper interpHelper, Vertex[] others )
{
for( int e = 0; e < 4; e++ )
{
float p1 = others[0].color[e];
float p2 = others[1].color[e];
float p3 = others[2].color[e];
float p4 = others[3].color[e];
// Only interpolate if colors are different.
if( p1 != p2 || p2 != p3 || p3 != p4 )
{
this.color[e] = interpHelper.interpolate( p1, p2, p3, p4 );
}
}
return this;
}
/**
* Interpolates the new color values for this Vertex using the others as a
* reference.
*
* @param interpHelper The InterpHelper to use.
* @param others The other Vertices to use as a template.
*
* @return The same Vertex.
*/
public Vertex interpColorFrom(InterpHelper interpHelper, Vertex[] others) {
for (int e = 0; e < 4; e++) {
float p1 = others[0].color[e];
float p2 = others[1].color[e];
float p3 = others[2].color[e];
float p4 = others[3].color[e];
// Only interpolate if colors are different.
if (p1 != p2 || p2 != p3 || p3 != p4) {
this.color[e] = interpHelper.interpolate(p1, p2, p3, p4);
}
}
return this;
}
/**
* Interpolates the new UV values for this Vertex using the others as a reference.
*
* @param interpHelper The InterpHelper to use.
* @param others The other Vertices to use as a template.
*
* @return The same Vertex.
*/
public Vertex interpUVFrom( InterpHelper interpHelper, Vertex[] others )
{
for( int e = 0; e < 2; e++ )
{
float p1 = others[0].uv[e];
float p2 = others[1].uv[e];
float p3 = others[2].uv[e];
float p4 = others[3].uv[e];
if( p1 != p2 || p2 != p3 || p3 != p4 )
{
this.uv[e] = interpHelper.interpolate( p1, p2, p3, p4 );
}
}
return this;
}
/**
* Interpolates the new UV values for this Vertex using the others as a
* reference.
*
* @param interpHelper The InterpHelper to use.
* @param others The other Vertices to use as a template.
*
* @return The same Vertex.
*/
public Vertex interpUVFrom(InterpHelper interpHelper, Vertex[] others) {
for (int e = 0; e < 2; e++) {
float p1 = others[0].uv[e];
float p2 = others[1].uv[e];
float p3 = others[2].uv[e];
float p4 = others[3].uv[e];
if (p1 != p2 || p2 != p3 || p3 != p4) {
this.uv[e] = interpHelper.interpolate(p1, p2, p3, p4);
}
}
return this;
}
/**
* Interpolates the new LightMap values for this Vertex using the others as a reference.
*
* @param interpHelper The InterpHelper to use.
* @param others The other Vertices to use as a template.
*
* @return The same Vertex.
*/
public Vertex interpLightMapFrom( InterpHelper interpHelper, Vertex[] others )
{
for( int e = 0; e < 2; e++ )
{
float p1 = others[0].lightmap[e];
float p2 = others[1].lightmap[e];
float p3 = others[2].lightmap[e];
float p4 = others[3].lightmap[e];
if( p1 != p2 || p2 != p3 || p3 != p4 )
{
this.lightmap[e] = interpHelper.interpolate( p1, p2, p3, p4 );
}
}
return this;
}
/**
* Interpolates the new LightMap values for this Vertex using the others as a
* reference.
*
* @param interpHelper The InterpHelper to use.
* @param others The other Vertices to use as a template.
*
* @return The same Vertex.
*/
public Vertex interpLightMapFrom(InterpHelper interpHelper, Vertex[] others) {
for (int e = 0; e < 2; e++) {
float p1 = others[0].lightmap[e];
float p2 = others[1].lightmap[e];
float p3 = others[2].lightmap[e];
float p4 = others[3].lightmap[e];
if (p1 != p2 || p2 != p3 || p3 != p4) {
this.lightmap[e] = interpHelper.interpolate(p1, p2, p3, p4);
}
}
return this;
}
/**
* Copies this Vertex to a new one.
*
* @return The new Vertex.
*/
public Vertex copy()
{
return new Vertex( this );
}
/**
* Copies this Vertex to a new one.
*
* @return The new Vertex.
*/
public Vertex copy() {
return new Vertex(this);
}
/**
* Resets the Vertex to a new format. Expands the raw array if needed.
*
* @param format The format to reset to.
*/
public void reset( CachedFormat format )
{
// If the format is different and our raw array is smaller, then expand it.
if( !this.format.equals( format ) && format.elementCount > this.raw.length )
{
this.raw = new float[format.elementCount][4];
}
this.format = format;
/**
* Resets the Vertex to a new format. Expands the raw array if needed.
*
* @param format The format to reset to.
*/
public void reset(CachedFormat format) {
// If the format is different and our raw array is smaller, then expand it.
if (!this.format.equals(format) && format.elementCount > this.raw.length) {
this.raw = new float[format.elementCount][4];
}
this.format = format;
this.vec = null;
this.normal = null;
this.color = null;
this.uv = null;
this.lightmap = null;
this.vec = null;
this.normal = null;
this.color = null;
this.uv = null;
this.lightmap = null;
// for (float[] f : raw) {
// Arrays.fill(f, 0F);
// }
// for (float[] f : raw) {
// Arrays.fill(f, 0F);
// }
this.preProcess();
}
}
this.preProcess();
}
}
}
@@ -18,7 +18,6 @@
package appeng.thirdparty.codechicken.lib.model.pipeline;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Map;
@@ -34,402 +33,369 @@ import appeng.thirdparty.codechicken.lib.model.CachedFormat;
import appeng.thirdparty.codechicken.lib.model.ISmartVertexConsumer;
import appeng.thirdparty.codechicken.lib.model.Quad;
/**
* The BakedPipeline!
* Basically this allows us to efficiently transform a BakedQuad,
* the Pipeline has Elements, each element has a name, state and a transformer,
* you can enable and disable elements easily, you can also grab the underlying
* transformer for the element if you need to set its state before rendering.
* The BakedPipeline! Basically this allows us to efficiently transform a
* BakedQuad, the Pipeline has Elements, each element has a name, state and a
* transformer, you can enable and disable elements easily, you can also grab
* the underlying transformer for the element if you need to set its state
* before rendering.
*
* The BakedPipeline is final once created, you cannot add or remove elements,
* you should not need to add or remove them runtime, enable and disable exist.
*
* You must use the Builder class to construct a BakedPipeline, see {@link #builder}
* You must use the Builder class to construct a BakedPipeline, see
* {@link #builder}
*
* Transformers run on a mutable state inside each transformer, allowing for easy reuse.
* It is recommended to store your pipeline inside a ThreadLocal because 'minecraft'.
* Transformers run on a mutable state inside each transformer, allowing for
* easy reuse. It is recommended to store your pipeline inside a ThreadLocal
* because 'minecraft'.
*
* Each Transformer should be smart enough to expand itself for each newly sized VertexFormat it comes across,
* meaning that the internal states for the transformers can be safely shared across VertexFormats, this reduces
* array creations, and generally makes the system as efficient as it is.
* Each Transformer should be smart enough to expand itself for each newly sized
* VertexFormat it comes across, meaning that the internal states for the
* transformers can be safely shared across VertexFormats, this reduces array
* creations, and generally makes the system as efficient as it is.
*
* To use the system:
* Grab any elements you need to set state data on first, using {@link #getElement(String, Class)}
* transformers should NOT clear their state on pipeline Reset's so set any global data on elements now.
* Assuming you are looping over a set of quads to transform, next you need to {@link #reset} the pipeline,
* Now you should disable / enable any optional elements that are needed, NOTE: Element states are reset when resetting
* the pipeline.
* Now you will need to call {@link #prepare(IVertexConsumer)} on the pipeline, here you will pass your collector,
* usually this is some form of (Unpacked)BakedQuadBuilder, See {@link QuadBuilder} for a simple and fast implementation
* for standard BakedQuads, and {@link UnpackedBakedQuad.Builder} for UnpackedBakedQuads.
* Now final step, simply pipe the quad you want to transform INTO the pipeline 'quad.pipe(pipeline)'
* And that's it! hell, Pipe a pipeline into each other for all i care, the system is efficient enough that there
* would be no performance penalty for doing so.
* To use the system: Grab any elements you need to set state data on first,
* using {@link #getElement(String, Class)} transformers should NOT clear their
* state on pipeline Reset's so set any global data on elements now. Assuming
* you are looping over a set of quads to transform, next you need to
* {@link #reset} the pipeline, Now you should disable / enable any optional
* elements that are needed, NOTE: Element states are reset when resetting the
* pipeline. Now you will need to call {@link #prepare(IVertexConsumer)} on the
* pipeline, here you will pass your collector, usually this is some form of
* (Unpacked)BakedQuadBuilder, See {@link QuadBuilder} for a simple and fast
* implementation for standard BakedQuads, and {@link UnpackedBakedQuad.Builder}
* for UnpackedBakedQuads. Now final step, simply pipe the quad you want to
* transform INTO the pipeline 'quad.pipe(pipeline)' And that's it! hell, Pipe a
* pipeline into each other for all i care, the system is efficient enough that
* there would be no performance penalty for doing so.
*
* @author covers1624
*/
public class BakedPipeline implements ISmartVertexConsumer
{
public class BakedPipeline implements ISmartVertexConsumer {
private PipelineElement[] elements;
private Map<String, PipelineElement> nameLookup;
private IPipelineConsumer first;
private PipelineElement[] elements;
private Map<String, PipelineElement> nameLookup;
private IPipelineConsumer first;
private Quad unpacker = new Quad();
private Quad unpacker = new Quad();
private BakedPipeline( PipelineElement[] elements )
{
this.elements = elements;
this.nameLookup = Arrays.stream( elements ).collect( Collectors.toMap( e -> e.name, e -> e ) );
}
private BakedPipeline(PipelineElement[] elements) {
this.elements = elements;
this.nameLookup = Arrays.stream(elements).collect(Collectors.toMap(e -> e.name, e -> e));
}
/**
* Used to create a BakedPipeline.
*
* @return The builder.
*/
public static Builder builder()
{
return new Builder();
}
/**
* Used to create a BakedPipeline.
*
* @return The builder.
*/
public static Builder builder() {
return new Builder();
}
/**
* Used to reset the pipeline for the next quad.
* MUST be called between quads.
*
* @param format The format.
*/
public void reset( VertexFormat format )
{
this.reset( CachedFormat.lookup( format ) );
}
/**
* Used to reset the pipeline for the next quad. MUST be called between quads.
*
* @param format The format.
*/
public void reset(VertexFormat format) {
this.reset(CachedFormat.lookup(format));
}
/**
* Used to reset the pipeline for the next quad.
* MUST be called between quads.
*
* @param format The format.
*/
public void reset( CachedFormat format )
{
this.unpacker.reset( format );
for( PipelineElement element : this.elements )
{
element.reset( format );
}
this.first = null;
}
/**
* Used to reset the pipeline for the next quad. MUST be called between quads.
*
* @param format The format.
*/
public void reset(CachedFormat format) {
this.unpacker.reset(format);
for (PipelineElement element : this.elements) {
element.reset(format);
}
this.first = null;
}
/**
* Get an element from the pipeline.
*
* @param name The name of the element.
* @param clazz The Class of the element, used to safe cast.
*
* @return The element.
*/
public <T extends IPipelineConsumer> T getElement( String name, Class<T> clazz )
{
PipelineElement element = this.nameLookup.get( name );
if( element != null )
{
if( !clazz.isAssignableFrom( element.consumer.getClass() ) )
{
throw new IllegalArgumentException( "Element with name " + name + " is not assignable from reference class." );
}
return clazz.cast( element.consumer );
}
throw new IllegalArgumentException( "Element with name " + name + " does not exist." );
}
/**
* Get an element from the pipeline.
*
* @param name The name of the element.
* @param clazz The Class of the element, used to safe cast.
*
* @return The element.
*/
public <T extends IPipelineConsumer> T getElement(String name, Class<T> clazz) {
PipelineElement element = this.nameLookup.get(name);
if (element != null) {
if (!clazz.isAssignableFrom(element.consumer.getClass())) {
throw new IllegalArgumentException(
"Element with name " + name + " is not assignable from reference class.");
}
return clazz.cast(element.consumer);
}
throw new IllegalArgumentException("Element with name " + name + " does not exist.");
}
/**
* Used to enable an element on the pipeline with the specified name.
*
* @param name The elements name.
*/
public void enableElement( String name )
{
this.setElementState( name, true );
}
/**
* Used to enable an element on the pipeline with the specified name.
*
* @param name The elements name.
*/
public void enableElement(String name) {
this.setElementState(name, true);
}
/**
* Used to disable an element on the pipeline with the specified name.
*
* @param name The elements name.
*/
public void disableElement( String name )
{
this.setElementState( name, false );
}
/**
* Used to disable an element on the pipeline with the specified name.
*
* @param name The elements name.
*/
public void disableElement(String name) {
this.setElementState(name, false);
}
/**
* Used to set the state of an element on the pipeline.
*
* @param name The name of the element.
* @param enabled The state to set it to.
*/
public void setElementState( String name, boolean enabled )
{
PipelineElement element = this.nameLookup.get( name );
if( element != null )
{
element.isEnabled = enabled;
return;
}
throw new IllegalArgumentException( "Element with name " + name + " does not exist." );
}
/**
* Used to set the state of an element on the pipeline.
*
* @param name The name of the element.
* @param enabled The state to set it to.
*/
public void setElementState(String name, boolean enabled) {
PipelineElement element = this.nameLookup.get(name);
if (element != null) {
element.isEnabled = enabled;
return;
}
throw new IllegalArgumentException("Element with name " + name + " does not exist.");
}
/**
* Call when you are ready to use the pipeline.
* This builds the internal state of the Elements getting things ready to transform.
*
* @param collector The IVertexConsumer that should collect the transformed quad.
*/
public void prepare( IVertexConsumer collector )
{
IPipelineConsumer next = null;
for( PipelineElement element : this.elements )
{
if( element.isEnabled )
{
if( this.first == null )
{
this.first = element.consumer;
}
else
{
next.setParent( element.consumer );
}
next = element.consumer;
}
}
next.setParent( collector );
}
/**
* Call when you are ready to use the pipeline. This builds the internal state
* of the Elements getting things ready to transform.
*
* @param collector The IVertexConsumer that should collect the transformed
* quad.
*/
public void prepare(IVertexConsumer collector) {
IPipelineConsumer next = null;
for (PipelineElement element : this.elements) {
if (element.isEnabled) {
if (this.first == null) {
this.first = element.consumer;
} else {
next.setParent(element.consumer);
}
next = element.consumer;
}
}
next.setParent(collector);
}
@Override
public VertexFormat getVertexFormat()
{
this.check();
return this.first.getVertexFormat();
}
@Override
public VertexFormat getVertexFormat() {
this.check();
return this.first.getVertexFormat();
}
@Override
public void setQuadTint( int tint )
{
this.check();
this.unpacker.setQuadTint( tint );
}
@Override
public void setQuadTint(int tint) {
this.check();
this.unpacker.setQuadTint(tint);
}
@Override
public void setQuadOrientation( Direction orientation )
{
this.check();
this.unpacker.setQuadOrientation( orientation );
}
@Override
public void setQuadOrientation(Direction orientation) {
this.check();
this.unpacker.setQuadOrientation(orientation);
}
@Override
public void setApplyDiffuseLighting( boolean diffuse )
{
this.check();
this.unpacker.setApplyDiffuseLighting( diffuse );
}
@Override
public void setApplyDiffuseLighting(boolean diffuse) {
this.check();
this.unpacker.setApplyDiffuseLighting(diffuse);
}
@Override
public void setTexture( TextureAtlasSprite texture )
{
this.check();
this.unpacker.setTexture( texture );
}
@Override
public void setTexture(TextureAtlasSprite texture) {
this.check();
this.unpacker.setTexture(texture);
}
@Override
public void put( int element, float... data )
{
this.check();
this.unpacker.put( element, data );
if( this.unpacker.full )
{
this.onFull();
}
}
@Override
public void put(int element, float... data) {
this.check();
this.unpacker.put(element, data);
if (this.unpacker.full) {
this.onFull();
}
}
@Override
public void put( Quad quad )
{
this.check();
this.unpacker.put( quad );
}
@Override
public void put(Quad quad) {
this.check();
this.unpacker.put(quad);
}
private void check()
{
if( this.first == null )
{
throw new IllegalStateException( "Pipeline used before prepare was called." );
}
}
private void check() {
if (this.first == null) {
throw new IllegalStateException("Pipeline used before prepare was called.");
}
}
private void onFull()
{
this.first.setInputQuad( this.unpacker );
this.first.put( this.unpacker );
}
private void onFull() {
this.first.setInputQuad(this.unpacker);
this.first.put(this.unpacker);
}
/**
* Internal class, used to hold a PipelineElement's state.
*/
public static class PipelineElement<T extends IPipelineConsumer>
{
/**
* Internal class, used to hold a PipelineElement's state.
*/
public static class PipelineElement<T extends IPipelineConsumer> {
public String name;
public boolean defaultState;
public T consumer;
public boolean isEnabled;
public String name;
public boolean defaultState;
public T consumer;
public boolean isEnabled;
public void reset( CachedFormat format )
{
this.isEnabled = this.defaultState;
this.consumer.setParent( null );
this.consumer.reset( format );
}
}
public void reset(CachedFormat format) {
this.isEnabled = this.defaultState;
this.consumer.setParent(null);
this.consumer.reset(format);
}
}
/**
* The builder associated with the BakedPipeline.
* You must create a BakedPipeline with this,
* once created a pipeline cannot be modified,
* modifying should not be needed as you can enable
* and disable elements with ease.
*/
public static class Builder
{
/**
* The builder associated with the BakedPipeline. You must create a
* BakedPipeline with this, once created a pipeline cannot be modified,
* modifying should not be needed as you can enable and disable elements with
* ease.
*/
public static class Builder {
private LinkedList<PipelineElement> elements = new LinkedList<>();
private LinkedList<PipelineElement> elements = new LinkedList<>();
/**
* Inserts an element to the front of the list, Useful if you have a more complex system
* and each system need to be independent from each other, but this element must be first.
*
* @param name The name to identify this element, used as an identifier when setting state, and retrieving the
* element.
* @param factory The factory used to create the Transformer.
*
* @return The same builder.
*/
public Builder addFirst( String name, IPipelineElementFactory<?> factory )
{
return this.addFirst( name, factory, true );
}
/**
* Inserts an element to the front of the list, Useful if you have a more
* complex system and each system need to be independent from each other, but
* this element must be first.
*
* @param name The name to identify this element, used as an identifier when
* setting state, and retrieving the element.
* @param factory The factory used to create the Transformer.
*
* @return The same builder.
*/
public Builder addFirst(String name, IPipelineElementFactory<?> factory) {
return this.addFirst(name, factory, true);
}
/**
* Inserts an element to the front of the list, Useful if you have a more complex system
* and each system need to be independent from each other, but this element must be first.
*
* @param name The name to identify this element, used as an identifier when setting state, and retrieving the
* element.
* @param factory The factory used to create the Transformer.
* @param defaultState The default state for this element.
*
* @return The same builder.
*/
public Builder addFirst( String name, IPipelineElementFactory<?> factory, boolean defaultState )
{
return this.addFirst( name, factory, defaultState, e ->
{
} );
}
/**
* Inserts an element to the front of the list, Useful if you have a more
* complex system and each system need to be independent from each other, but
* this element must be first.
*
* @param name The name to identify this element, used as an identifier
* when setting state, and retrieving the element.
* @param factory The factory used to create the Transformer.
* @param defaultState The default state for this element.
*
* @return The same builder.
*/
public Builder addFirst(String name, IPipelineElementFactory<?> factory, boolean defaultState) {
return this.addFirst(name, factory, defaultState, e -> {
});
}
/**
* Inserts an element to the front of the list, Useful if you have a more complex system
* and each system need to be independent from each other, but this element must be first.
*
* @param name The name to identify this element, used as an identifier when setting state, and retrieving the
* element.
* @param factory The factory used to create the Transformer.
* @param defaultState The default state for this element.
* @param defaultsSetter A callback used to set any defaults on the transformer.
*
* @return The same builder.
*/
public <T extends IPipelineConsumer> Builder addFirst( String name, IPipelineElementFactory<T> factory, boolean defaultState, Consumer<T> defaultsSetter )
{
PipelineElement<T> element = this.makeElement( name, factory, defaultState );
defaultsSetter.accept( element.consumer );
this.elements.addFirst( element );
return this;
}
/**
* Inserts an element to the front of the list, Useful if you have a more
* complex system and each system need to be independent from each other, but
* this element must be first.
*
* @param name The name to identify this element, used as an
* identifier when setting state, and retrieving the
* element.
* @param factory The factory used to create the Transformer.
* @param defaultState The default state for this element.
* @param defaultsSetter A callback used to set any defaults on the transformer.
*
* @return The same builder.
*/
public <T extends IPipelineConsumer> Builder addFirst(String name, IPipelineElementFactory<T> factory,
boolean defaultState, Consumer<T> defaultsSetter) {
PipelineElement<T> element = this.makeElement(name, factory, defaultState);
defaultsSetter.accept(element.consumer);
this.elements.addFirst(element);
return this;
}
/**
* Adds an element at the end of the transform list, Suitable for 99% of cases.
*
* @param name The name to identify this element, used as an identifier when setting state, and retrieving the
* element.
* @param factory The factory used to create the Transformer.
*
* @return The same builder.
*/
public Builder addElement( String name, IPipelineElementFactory<?> factory )
{
return this.addElement( name, factory, true );
}
/**
* Adds an element at the end of the transform list, Suitable for 99% of cases.
*
* @param name The name to identify this element, used as an identifier when
* setting state, and retrieving the element.
* @param factory The factory used to create the Transformer.
*
* @return The same builder.
*/
public Builder addElement(String name, IPipelineElementFactory<?> factory) {
return this.addElement(name, factory, true);
}
/**
* Adds an element at the end of the transform list, Suitable for 99% of cases.
*
* @param name The name to identify this element, used as an identifier when setting state, and retrieving the
* element.
* @param factory The factory used to create the Transformer.
* @param defaultState The default state for this element.
*
* @return The same builder.
*/
public Builder addElement( String name, IPipelineElementFactory<?> factory, boolean defaultState )
{
return this.addElement( name, factory, defaultState, e ->
{
} );
}
/**
* Adds an element at the end of the transform list, Suitable for 99% of cases.
*
* @param name The name to identify this element, used as an identifier
* when setting state, and retrieving the element.
* @param factory The factory used to create the Transformer.
* @param defaultState The default state for this element.
*
* @return The same builder.
*/
public Builder addElement(String name, IPipelineElementFactory<?> factory, boolean defaultState) {
return this.addElement(name, factory, defaultState, e -> {
});
}
/**
* Adds an element at the end of the transform list, Suitable for 99% of cases.
*
* @param name The name to identify this element, used as an identifier when setting state, and retrieving the
* element.
* @param factory The factory used to create the Transformer.
* @param defaultState The default state for this element.
* @param defaultsSetter A callback used to set any defaults on the transformer.
*
* @return The same builder.
*/
public <T extends IPipelineConsumer> Builder addElement( String name, IPipelineElementFactory<T> factory, boolean defaultState, Consumer<T> defaultsSetter )
{
PipelineElement<T> element = this.makeElement( name, factory, defaultState );
defaultsSetter.accept( element.consumer );
this.elements.add( element );
return this;
}
/**
* Adds an element at the end of the transform list, Suitable for 99% of cases.
*
* @param name The name to identify this element, used as an
* identifier when setting state, and retrieving the
* element.
* @param factory The factory used to create the Transformer.
* @param defaultState The default state for this element.
* @param defaultsSetter A callback used to set any defaults on the transformer.
*
* @return The same builder.
*/
public <T extends IPipelineConsumer> Builder addElement(String name, IPipelineElementFactory<T> factory,
boolean defaultState, Consumer<T> defaultsSetter) {
PipelineElement<T> element = this.makeElement(name, factory, defaultState);
defaultsSetter.accept(element.consumer);
this.elements.add(element);
return this;
}
// Internal method, used to construct the PipelineElement class.
private <T extends IPipelineConsumer> PipelineElement<T> makeElement( String name, IPipelineElementFactory<T> factory, boolean defaultState )
{
if( this.elements.stream().anyMatch( p -> p.name.equals( name ) ) )
{
throw new IllegalArgumentException( "Unable to add element with duplicate name: " + name );
}
PipelineElement<T> element = new PipelineElement<>();
element.name = name;
element.consumer = factory.create();
element.defaultState = defaultState;
return element;
}
// Internal method, used to construct the PipelineElement class.
private <T extends IPipelineConsumer> PipelineElement<T> makeElement(String name,
IPipelineElementFactory<T> factory, boolean defaultState) {
if (this.elements.stream().anyMatch(p -> p.name.equals(name))) {
throw new IllegalArgumentException("Unable to add element with duplicate name: " + name);
}
PipelineElement<T> element = new PipelineElement<>();
element.name = name;
element.consumer = factory.create();
element.defaultState = defaultState;
return element;
}
/**
* Call this once you are finished to build your BakedPipeline!
*
* @return The new Pipeline.
*/
public BakedPipeline build()
{
return new BakedPipeline( this.elements.toArray( new PipelineElement[0] ) );
}
}
/**
* Call this once you are finished to build your BakedPipeline!
*
* @return The new Pipeline.
*/
public BakedPipeline build() {
return new BakedPipeline(this.elements.toArray(new PipelineElement[0]));
}
}
}
@@ -18,7 +18,6 @@
package appeng.thirdparty.codechicken.lib.model.pipeline;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
import appeng.thirdparty.codechicken.lib.model.CachedFormat;
@@ -26,39 +25,36 @@ import appeng.thirdparty.codechicken.lib.model.ISmartVertexConsumer;
import appeng.thirdparty.codechicken.lib.model.Quad;
import appeng.thirdparty.codechicken.lib.model.pipeline.transformers.QuadReInterpolator;
/**
* Anything implementing this may be used in the BakedPipeline.
*
* @author covers1624
*/
public interface IPipelineConsumer extends ISmartVertexConsumer
{
public interface IPipelineConsumer extends ISmartVertexConsumer {
/**
* The quad at the start of the transformation.
* This is useful for obtaining the vertex data before any transformations have been applied,
* such as interpolation, See {@link QuadReInterpolator}.
* When overriding this make sure you call setInputQuad on your parent consumer too.
*
* @param quad The quad.
*/
void setInputQuad( Quad quad );
/**
* The quad at the start of the transformation. This is useful for obtaining the
* vertex data before any transformations have been applied, such as
* interpolation, See {@link QuadReInterpolator}. When overriding this make sure
* you call setInputQuad on your parent consumer too.
*
* @param quad The quad.
*/
void setInputQuad(Quad quad);
/**
* Resets the Consumer to the new format.
* This should resize any internal arrays if needed, ready for the new vertex data.
*
* @param format The format to reset to.
*/
void reset( CachedFormat format );
/**
* Resets the Consumer to the new format. This should resize any internal arrays
* if needed, ready for the new vertex data.
*
* @param format The format to reset to.
*/
void reset(CachedFormat format);
/**
* Sets the parent consumer.
* This consumer may choose to not pipe any data,
* that's fine, but if it does, it MUST pipe the data to the one provided here.
*
* @param parent The parent.
*/
void setParent( IVertexConsumer parent );
/**
* Sets the parent consumer. This consumer may choose to not pipe any data,
* that's fine, but if it does, it MUST pipe the data to the one provided here.
*
* @param parent The parent.
*/
void setParent(IVertexConsumer parent);
}
@@ -18,13 +18,11 @@
package appeng.thirdparty.codechicken.lib.model.pipeline;
/**
* @author covers1624
*/
@FunctionalInterface
public interface IPipelineElementFactory<T extends IPipelineConsumer>
{
public interface IPipelineElementFactory<T extends IPipelineConsumer> {
T create();
T create();
}
@@ -18,7 +18,6 @@
package appeng.thirdparty.codechicken.lib.model.pipeline;
import javax.annotation.OverridingMethodsMustInvokeSuper;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
@@ -30,146 +29,121 @@ import appeng.thirdparty.codechicken.lib.model.CachedFormat;
import appeng.thirdparty.codechicken.lib.model.ISmartVertexConsumer;
import appeng.thirdparty.codechicken.lib.model.Quad;
/**
* Base class for a simple QuadTransformer.
* Operates on BakedQuads.
* Base class for a simple QuadTransformer. Operates on BakedQuads.
* QuadTransformers can be piped into each other at no performance penalty.
*
* @author covers1624
*/
public abstract class QuadTransformer implements IVertexConsumer, ISmartVertexConsumer, IPipelineConsumer
{
public abstract class QuadTransformer implements IVertexConsumer, ISmartVertexConsumer, IPipelineConsumer {
protected CachedFormat format;
protected IVertexConsumer consumer;
protected Quad quad;
protected CachedFormat format;
protected IVertexConsumer consumer;
protected Quad quad;
/**
* Used for the BakedPipeline.
*/
protected QuadTransformer()
{
this.quad = new Quad();
}
/**
* Used for the BakedPipeline.
*/
protected QuadTransformer() {
this.quad = new Quad();
}
public QuadTransformer( IVertexConsumer consumer )
{
this( consumer.getVertexFormat(), consumer );
}
public QuadTransformer(IVertexConsumer consumer) {
this(consumer.getVertexFormat(), consumer);
}
public QuadTransformer( VertexFormat format, IVertexConsumer consumer )
{
this( CachedFormat.lookup( format ), consumer );
}
public QuadTransformer(VertexFormat format, IVertexConsumer consumer) {
this(CachedFormat.lookup(format), consumer);
}
public QuadTransformer( CachedFormat format, IVertexConsumer consumer )
{
this.format = format;
this.consumer = consumer;
this.quad = new Quad( format );
}
public QuadTransformer(CachedFormat format, IVertexConsumer consumer) {
this.format = format;
this.consumer = consumer;
this.quad = new Quad(format);
}
@Override
@OverridingMethodsMustInvokeSuper
public void reset( CachedFormat format )
{
this.format = format;
this.quad.reset( format );
}
@Override
@OverridingMethodsMustInvokeSuper
public void reset(CachedFormat format) {
this.format = format;
this.quad.reset(format);
}
@Override
public void setParent( IVertexConsumer parent )
{
this.consumer = parent;
}
@Override
public void setParent(IVertexConsumer parent) {
this.consumer = parent;
}
@Override
@OverridingMethodsMustInvokeSuper
public void setInputQuad( Quad quad )
{
if( this.consumer instanceof IPipelineConsumer )
{
( (IPipelineConsumer) this.consumer ).setInputQuad( quad );
}
}
@Override
@OverridingMethodsMustInvokeSuper
public void setInputQuad(Quad quad) {
if (this.consumer instanceof IPipelineConsumer) {
((IPipelineConsumer) this.consumer).setInputQuad(quad);
}
}
// @formatter:off
@Override
public VertexFormat getVertexFormat()
{
return this.format.format;
}
// @formatter:off
@Override
public VertexFormat getVertexFormat() {
return this.format.format;
}
@Override
public void setQuadTint( int tint )
{
this.quad.setQuadTint( tint );
}
@Override
public void setQuadTint(int tint) {
this.quad.setQuadTint(tint);
}
@Override
public void setQuadOrientation( Direction orientation )
{
this.quad.setQuadOrientation( orientation );
}
@Override
public void setQuadOrientation(Direction orientation) {
this.quad.setQuadOrientation(orientation);
}
@Override
public void setApplyDiffuseLighting( boolean diffuse )
{
this.quad.setApplyDiffuseLighting( diffuse );
}
@Override
public void setApplyDiffuseLighting(boolean diffuse) {
this.quad.setApplyDiffuseLighting(diffuse);
}
@Override
public void setTexture( TextureAtlasSprite texture )
{
this.quad.setTexture( texture );
}
// @formatter:on
@Override
public void setTexture(TextureAtlasSprite texture) {
this.quad.setTexture(texture);
}
// @formatter:on
@Override
public void put( int element, float... data )
{
this.quad.put( element, data );
if( this.quad.full )
{
this.onFull();
}
}
@Override
public void put(int element, float... data) {
this.quad.put(element, data);
if (this.quad.full) {
this.onFull();
}
}
@Override
public void put( Quad quad )
{
this.quad.put( quad );
this.onFull();
}
@Override
public void put(Quad quad) {
this.quad.put(quad);
this.onFull();
}
/**
* Called to transform the vertices.
*
* @return If the transformer should pipe the quad.
*/
public abstract boolean transform();
/**
* Called to transform the vertices.
*
* @return If the transformer should pipe the quad.
*/
public abstract boolean transform();
public void onFull()
{
if( this.transform() )
{
this.quad.pipe( this.consumer );
}
}
public void onFull() {
if (this.transform()) {
this.quad.pipe(this.consumer);
}
}
// Should be small enough.
private final static double EPSILON = 0.00001;
// Should be small enough.
private final static double EPSILON = 0.00001;
public static boolean epsComp( float a, float b )
{
if( a == b )
{
return true;
}
else
{
return Math.abs( a - b ) < EPSILON;
}
}
public static boolean epsComp(float a, float b) {
if (a == b) {
return true;
} else {
return Math.abs(a - b) < EPSILON;
}
}
}
@@ -18,54 +18,45 @@
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
import appeng.thirdparty.codechicken.lib.model.Quad.Vertex;
import appeng.thirdparty.codechicken.lib.model.pipeline.IPipelineElementFactory;
import appeng.thirdparty.codechicken.lib.model.pipeline.QuadTransformer;
/**
* This transformer simply overrides the alpha of the quad.
* Only operates if the format has color.
* This transformer simply overrides the alpha of the quad. Only operates if the
* format has color.
*
* @author covers1624
*/
public class QuadAlphaOverride extends QuadTransformer
{
public class QuadAlphaOverride extends QuadTransformer {
public static final IPipelineElementFactory<QuadAlphaOverride> FACTORY = QuadAlphaOverride::new;
public static final IPipelineElementFactory<QuadAlphaOverride> FACTORY = QuadAlphaOverride::new;
private float alphaOverride;
private float alphaOverride;
QuadAlphaOverride()
{
super();
}
QuadAlphaOverride() {
super();
}
public QuadAlphaOverride( IVertexConsumer consumer, float alphaOverride )
{
super( consumer );
this.alphaOverride = alphaOverride;
}
public QuadAlphaOverride(IVertexConsumer consumer, float alphaOverride) {
super(consumer);
this.alphaOverride = alphaOverride;
}
public QuadAlphaOverride setAlphaOverride( float alphaOverride )
{
this.alphaOverride = alphaOverride;
return this;
}
public QuadAlphaOverride setAlphaOverride(float alphaOverride) {
this.alphaOverride = alphaOverride;
return this;
}
@Override
public boolean transform()
{
if( this.format.hasColor )
{
for( Vertex v : this.quad.vertices )
{
v.color[3] = this.alphaOverride;
}
}
return true;
}
@Override
public boolean transform() {
if (this.format.hasColor) {
for (Vertex v : this.quad.vertices) {
v.color[3] = this.alphaOverride;
}
}
return true;
}
}
@@ -18,7 +18,6 @@
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
@@ -26,58 +25,53 @@ import appeng.thirdparty.codechicken.lib.model.Quad.Vertex;
import appeng.thirdparty.codechicken.lib.model.pipeline.IPipelineElementFactory;
import appeng.thirdparty.codechicken.lib.model.pipeline.QuadTransformer;
/**
* This transformer simply clamps the vertices inside the provided box.
* You probably want to Re-Interpolate the UV's, Color, and Lmap, see {@link QuadReInterpolator}
* This transformer simply clamps the vertices inside the provided box. You
* probably want to Re-Interpolate the UV's, Color, and Lmap, see
* {@link QuadReInterpolator}
*
* @author covers1624
*/
public class QuadClamper extends QuadTransformer
{
public class QuadClamper extends QuadTransformer {
public static IPipelineElementFactory<QuadClamper> FACTORY = QuadClamper::new;
public static IPipelineElementFactory<QuadClamper> FACTORY = QuadClamper::new;
private AxisAlignedBB clampBounds;
private AxisAlignedBB clampBounds;
QuadClamper()
{
super();
}
QuadClamper() {
super();
}
public QuadClamper( IVertexConsumer parent, AxisAlignedBB bounds )
{
super( parent );
this.clampBounds = bounds;
}
public QuadClamper(IVertexConsumer parent, AxisAlignedBB bounds) {
super(parent);
this.clampBounds = bounds;
}
public void setClampBounds( AxisAlignedBB bounds )
{
this.clampBounds = bounds;
}
public void setClampBounds(AxisAlignedBB bounds) {
this.clampBounds = bounds;
}
@Override
public boolean transform()
{
int s = this.quad.orientation.ordinal() >> 1;
@Override
public boolean transform() {
int s = this.quad.orientation.ordinal() >> 1;
this.quad.clamp( this.clampBounds );
this.quad.clamp(this.clampBounds);
// Check if the quad would be invisible and cull it.
Vertex[] vertices = this.quad.vertices;
float x1 = vertices[0].dx( s );
float x2 = vertices[1].dx( s );
float x3 = vertices[2].dx( s );
float x4 = vertices[3].dx( s );
// Check if the quad would be invisible and cull it.
Vertex[] vertices = this.quad.vertices;
float x1 = vertices[0].dx(s);
float x2 = vertices[1].dx(s);
float x3 = vertices[2].dx(s);
float x4 = vertices[3].dx(s);
float y1 = vertices[0].dy( s );
float y2 = vertices[1].dy( s );
float y3 = vertices[2].dy( s );
float y4 = vertices[3].dy( s );
float y1 = vertices[0].dy(s);
float y2 = vertices[1].dy(s);
float y3 = vertices[2].dy(s);
float y4 = vertices[3].dy(s);
// These comparisons are safe as we are comparing clamped values.
boolean flag1 = x1 == x2 && x2 == x3 && x3 == x4;
boolean flag2 = y1 == y2 && y2 == y3 && y3 == y4;
return !flag1 && !flag2;
}
// These comparisons are safe as we are comparing clamped values.
boolean flag1 = x1 == x2 && x2 == x3 && x3 == x4;
boolean flag2 = y1 == y2 && y2 == y3 && y3 == y4;
return !flag1 && !flag2;
}
}
@@ -18,7 +18,6 @@
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
import static net.minecraft.util.Direction.AxisDirection.NEGATIVE;
import static net.minecraft.util.Direction.AxisDirection.POSITIVE;
@@ -31,189 +30,161 @@ import appeng.thirdparty.codechicken.lib.model.Quad.Vertex;
import appeng.thirdparty.codechicken.lib.model.pipeline.IPipelineElementFactory;
import appeng.thirdparty.codechicken.lib.model.pipeline.QuadTransformer;
/**
* This transformer is a little complicated.
* Basically a Facade / Cover can use this to 'kick' the edges
* in of quads to fix z-Fighting in the corners.
* Use it by specifying the side of the block you are on,
* the bitmask for where the other Facades / Cover's are,
* the bounding box of the facade, NOT the hole piece,
* and the thickness of your Facade / Cover, this is used
* as the kick amount.
* This transformer is a little complicated. Basically a Facade / Cover can use
* this to 'kick' the edges in of quads to fix z-Fighting in the corners. Use it
* by specifying the side of the block you are on, the bitmask for where the
* other Facades / Cover's are, the bounding box of the facade, NOT the hole
* piece, and the thickness of your Facade / Cover, this is used as the kick
* amount.
*
* @author covers1624
*/
public class QuadCornerKicker extends QuadTransformer
{
public class QuadCornerKicker extends QuadTransformer {
// The factory for pipeline creation.
public static final IPipelineElementFactory<QuadCornerKicker> FACTORY = QuadCornerKicker::new;
// The factory for pipeline creation.
public static final IPipelineElementFactory<QuadCornerKicker> FACTORY = QuadCornerKicker::new;
// Simple horizonal lookups.
public static int[][] horizonals = new int[][] {
// Around Y axis, NSWE.
{ 2, 3, 4, 5 }, //
{ 2, 3, 4, 5 }, //
// Simple horizonal lookups.
public static int[][] horizonals = new int[][] {
// Around Y axis, NSWE.
{ 2, 3, 4, 5 }, //
{ 2, 3, 4, 5 }, //
// Around Z axis, DUWE.
{ 0, 1, 4, 5 }, //
{ 0, 1, 4, 5 }, //
// Around Z axis, DUWE.
{ 0, 1, 4, 5 }, //
{ 0, 1, 4, 5 }, //
// Around X axis, DUNS.
{ 0, 1, 2, 3 }, //
{ 0, 1, 2, 3 }
};
// Around X axis, DUNS.
{ 0, 1, 2, 3 }, //
{ 0, 1, 2, 3 } };
private int mySide;
private int facadeMask;
private AxisAlignedBB box;
private double thickness;
private int mySide;
private int facadeMask;
private AxisAlignedBB box;
private double thickness;
QuadCornerKicker()
{
super();
}
QuadCornerKicker() {
super();
}
/**
* Set's the side this Facade / Cover is attached to.
*
* @param side The side.
*/
public void setSide( int side )
{
this.mySide = side;
}
/**
* Set's the side this Facade / Cover is attached to.
*
* @param side The side.
*/
public void setSide(int side) {
this.mySide = side;
}
/**
* Sets the bitmask of Facades / Covers in the blockspace.
* This is as simple as, mask = (1 << side)
*
* @param mask The mask.
*/
public void setFacadeMask( int mask )
{
this.facadeMask = mask;
}
/**
* Sets the bitmask of Facades / Covers in the blockspace. This is as simple as,
* mask = (1 << side)
*
* @param mask The mask.
*/
public void setFacadeMask(int mask) {
this.facadeMask = mask;
}
/**
* Sets the bounding box of the Facade / Cover,
* this should be the full box, not just a piece
* of the hole's 'ring'.
*
* @param box The BoundingBox.
*/
public void setBox( AxisAlignedBB box )
{
this.box = box;
}
/**
* Sets the bounding box of the Facade / Cover, this should be the full box, not
* just a piece of the hole's 'ring'.
*
* @param box The BoundingBox.
*/
public void setBox(AxisAlignedBB box) {
this.box = box;
}
/**
* Sets the amount to kick the vertex in by,
* this is your facades thickness.
*
* @param thickness The thickness.
*/
public void setThickness( double thickness )
{
this.thickness = thickness;
}
/**
* Sets the amount to kick the vertex in by, this is your facades thickness.
*
* @param thickness The thickness.
*/
public void setThickness(double thickness) {
this.thickness = thickness;
}
@Override
public boolean transform()
{
@Override
public boolean transform() {
int side = this.quad.orientation.ordinal();
if( side != this.mySide && side != ( this.mySide ^ 1 ) )
{
for( int hoz : horizonals[this.mySide] )
{
if( side != hoz && side != ( hoz ^ 1 ) )
{
if( ( this.facadeMask & ( 1 << hoz ) ) != 0 )
{
Corner corner = Corner.fromSides( this.mySide ^ 1, side, hoz );
for( Vertex vertex : this.quad.vertices )
{
float x = vertex.vec[0];
float y = vertex.vec[1];
float z = vertex.vec[2];
if( epsComp( x, corner.pX( this.box ) ) && epsComp( y, corner.pY( this.box ) ) && epsComp( z, corner.pZ( this.box ) ) )
{
Vec3i vec = Direction.values()[hoz].getDirectionVec();
x -= vec.getX() * this.thickness;
y -= vec.getY() * this.thickness;
z -= vec.getZ() * this.thickness;
vertex.vec[0] = x;
vertex.vec[1] = y;
vertex.vec[2] = z;
}
}
}
}
}
}
int side = this.quad.orientation.ordinal();
if (side != this.mySide && side != (this.mySide ^ 1)) {
for (int hoz : horizonals[this.mySide]) {
if (side != hoz && side != (hoz ^ 1)) {
if ((this.facadeMask & (1 << hoz)) != 0) {
Corner corner = Corner.fromSides(this.mySide ^ 1, side, hoz);
for (Vertex vertex : this.quad.vertices) {
float x = vertex.vec[0];
float y = vertex.vec[1];
float z = vertex.vec[2];
if (epsComp(x, corner.pX(this.box)) && epsComp(y, corner.pY(this.box))
&& epsComp(z, corner.pZ(this.box))) {
Vec3i vec = Direction.values()[hoz].getDirectionVec();
x -= vec.getX() * this.thickness;
y -= vec.getY() * this.thickness;
z -= vec.getZ() * this.thickness;
vertex.vec[0] = x;
vertex.vec[1] = y;
vertex.vec[2] = z;
}
}
}
}
}
}
return true;
}
return true;
}
public enum Corner
{
public enum Corner {
MIN_X_MIN_Y_MIN_Z( NEGATIVE, NEGATIVE, NEGATIVE ),
MIN_X_MIN_Y_MAX_Z( NEGATIVE, NEGATIVE, POSITIVE ),
MIN_X_MAX_Y_MIN_Z( NEGATIVE, POSITIVE, NEGATIVE ),
MIN_X_MAX_Y_MAX_Z( NEGATIVE, POSITIVE, POSITIVE ),
MIN_X_MIN_Y_MIN_Z(NEGATIVE, NEGATIVE, NEGATIVE), MIN_X_MIN_Y_MAX_Z(NEGATIVE, NEGATIVE, POSITIVE),
MIN_X_MAX_Y_MIN_Z(NEGATIVE, POSITIVE, NEGATIVE), MIN_X_MAX_Y_MAX_Z(NEGATIVE, POSITIVE, POSITIVE),
MAX_X_MIN_Y_MIN_Z( POSITIVE, NEGATIVE, NEGATIVE ),
MAX_X_MIN_Y_MAX_Z( POSITIVE, NEGATIVE, POSITIVE ),
MAX_X_MAX_Y_MIN_Z( POSITIVE, POSITIVE, NEGATIVE ),
MAX_X_MAX_Y_MAX_Z( POSITIVE, POSITIVE, POSITIVE );
MAX_X_MIN_Y_MIN_Z(POSITIVE, NEGATIVE, NEGATIVE), MAX_X_MIN_Y_MAX_Z(POSITIVE, NEGATIVE, POSITIVE),
MAX_X_MAX_Y_MIN_Z(POSITIVE, POSITIVE, NEGATIVE), MAX_X_MAX_Y_MAX_Z(POSITIVE, POSITIVE, POSITIVE);
private AxisDirection xAxis;
private AxisDirection yAxis;
private AxisDirection zAxis;
private AxisDirection xAxis;
private AxisDirection yAxis;
private AxisDirection zAxis;
private static final int[] sideMask = { 0, 2, 0, 1, 0, 4 };
private static final int[] sideMask = { 0, 2, 0, 1, 0, 4 };
Corner( AxisDirection xAxis, AxisDirection yAxis, AxisDirection zAxis )
{
this.xAxis = xAxis;
this.yAxis = yAxis;
this.zAxis = zAxis;
}
Corner(AxisDirection xAxis, AxisDirection yAxis, AxisDirection zAxis) {
this.xAxis = xAxis;
this.yAxis = yAxis;
this.zAxis = zAxis;
}
/**
* Used to find what corner is at the 3 sides.
* This method assumes you pass in the X axis side, Y axis side, and Z axis side,
* it will NOT complain about an invalid side, you will just get garbage data.
* This method also does not care what order the 3 axes are in.
*
* @param sideA Side one.
* @param sideB Side two.
* @param sideC Side three.
*
* @return The corner at the 3 sides.
*/
public static Corner fromSides( int sideA, int sideB, int sideC )
{
// <3 Chicken-Bones.
return values()[sideMask[sideA] | sideMask[sideB] | sideMask[sideC]];
}
/**
* Used to find what corner is at the 3 sides. This method assumes you pass in
* the X axis side, Y axis side, and Z axis side, it will NOT complain about an
* invalid side, you will just get garbage data. This method also does not care
* what order the 3 axes are in.
*
* @param sideA Side one.
* @param sideB Side two.
* @param sideC Side three.
*
* @return The corner at the 3 sides.
*/
public static Corner fromSides(int sideA, int sideB, int sideC) {
// <3 Chicken-Bones.
return values()[sideMask[sideA] | sideMask[sideB] | sideMask[sideC]];
}
public float pX( AxisAlignedBB box )
{
return (float) ( this.xAxis == NEGATIVE ? box.minX : box.maxX );
}
public float pX(AxisAlignedBB box) {
return (float) (this.xAxis == NEGATIVE ? box.minX : box.maxX);
}
public float pY( AxisAlignedBB box )
{
return (float) ( this.yAxis == NEGATIVE ? box.minY : box.maxY );
}
public float pY(AxisAlignedBB box) {
return (float) (this.yAxis == NEGATIVE ? box.minY : box.maxY);
}
public float pZ( AxisAlignedBB box )
{
return (float) ( this.zAxis == NEGATIVE ? box.minZ : box.maxZ );
}
}
public float pZ(AxisAlignedBB box) {
return (float) (this.zAxis == NEGATIVE ? box.minZ : box.maxZ);
}
}
}
@@ -18,7 +18,6 @@
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
import static net.minecraft.util.Direction.AxisDirection.POSITIVE;
import net.minecraft.util.Direction.AxisDirection;
@@ -29,100 +28,85 @@ import appeng.thirdparty.codechicken.lib.model.Quad.Vertex;
import appeng.thirdparty.codechicken.lib.model.pipeline.IPipelineElementFactory;
import appeng.thirdparty.codechicken.lib.model.pipeline.QuadTransformer;
/**
* This transformer strips quads that are on faces.
* Simply set the bounds for the faces, and the strip mask.
* This transformer strips quads that are on faces. Simply set the bounds for
* the faces, and the strip mask.
*
* @author covers1624
*/
public class QuadFaceStripper extends QuadTransformer
{
public class QuadFaceStripper extends QuadTransformer {
public static final IPipelineElementFactory<QuadFaceStripper> FACTORY = QuadFaceStripper::new;
public static final IPipelineElementFactory<QuadFaceStripper> FACTORY = QuadFaceStripper::new;
private AxisAlignedBB bounds;
private int mask;
private AxisAlignedBB bounds;
private int mask;
QuadFaceStripper()
{
super();
}
QuadFaceStripper() {
super();
}
public QuadFaceStripper( IVertexConsumer parent, AxisAlignedBB bounds, int mask )
{
super( parent );
this.bounds = bounds;
this.mask = mask;
}
public QuadFaceStripper(IVertexConsumer parent, AxisAlignedBB bounds, int mask) {
super(parent);
this.bounds = bounds;
this.mask = mask;
}
/**
* The bounds of the faces,
* used as the .. bounds, if all vertices of a quad
* lay on the bounds, it is up for stripping.
*
* @param bounds The bounds.
*/
public void setBounds( AxisAlignedBB bounds )
{
this.bounds = bounds;
}
/**
* The bounds of the faces, used as the .. bounds, if all vertices of a quad lay
* on the bounds, it is up for stripping.
*
* @param bounds The bounds.
*/
public void setBounds(AxisAlignedBB bounds) {
this.bounds = bounds;
}
/**
* The mask to strip edges.
* This is an opt in system,
* the mask is simple 'mask = (1 << side)'.
*
* @param mask The mask.
*/
public void setMask( int mask )
{
this.mask = mask;
}
/**
* The mask to strip edges. This is an opt in system, the mask is simple 'mask =
* (1 << side)'.
*
* @param mask The mask.
*/
public void setMask(int mask) {
this.mask = mask;
}
@Override
public boolean transform()
{
if( this.mask == 0 )
{
return true;// No mask, nothing changes.
}
// If the bit for this quad is set, then check if we should strip.
if( ( this.mask & ( 1 << this.quad.orientation.ordinal() ) ) != 0 )
{
AxisDirection dir = this.quad.orientation.getAxisDirection();
Vertex[] vertices = this.quad.vertices;
switch( this.quad.orientation.getAxis() )
{
case X:
{
float bound = (float) ( dir == POSITIVE ? this.bounds.maxX : this.bounds.minX );
float x1 = vertices[0].vec[0];
float x2 = vertices[1].vec[0];
float x3 = vertices[2].vec[0];
float x4 = vertices[3].vec[0];
return x1 != x2 || x2 != x3 || x3 != x4 || x4 != bound;
}
case Y:
{
float bound = (float) ( dir == POSITIVE ? this.bounds.maxY : this.bounds.minY );
float y1 = vertices[0].vec[1];
float y2 = vertices[1].vec[1];
float y3 = vertices[2].vec[1];
float y4 = vertices[3].vec[1];
return y1 != y2 || y2 != y3 || y3 != y4 || y4 != bound;
}
case Z:
{
float bound = (float) ( dir == POSITIVE ? this.bounds.maxZ : this.bounds.minZ );
float z1 = vertices[0].vec[2];
float z2 = vertices[1].vec[2];
float z3 = vertices[2].vec[2];
float z4 = vertices[3].vec[2];
return z1 != z2 || z2 != z3 || z3 != z4 || z4 != bound;
}
}
}
return true;
}
@Override
public boolean transform() {
if (this.mask == 0) {
return true;// No mask, nothing changes.
}
// If the bit for this quad is set, then check if we should strip.
if ((this.mask & (1 << this.quad.orientation.ordinal())) != 0) {
AxisDirection dir = this.quad.orientation.getAxisDirection();
Vertex[] vertices = this.quad.vertices;
switch (this.quad.orientation.getAxis()) {
case X: {
float bound = (float) (dir == POSITIVE ? this.bounds.maxX : this.bounds.minX);
float x1 = vertices[0].vec[0];
float x2 = vertices[1].vec[0];
float x3 = vertices[2].vec[0];
float x4 = vertices[3].vec[0];
return x1 != x2 || x2 != x3 || x3 != x4 || x4 != bound;
}
case Y: {
float bound = (float) (dir == POSITIVE ? this.bounds.maxY : this.bounds.minY);
float y1 = vertices[0].vec[1];
float y2 = vertices[1].vec[1];
float y3 = vertices[2].vec[1];
float y4 = vertices[3].vec[1];
return y1 != y2 || y2 != y3 || y3 != y4 || y4 != bound;
}
case Z: {
float bound = (float) (dir == POSITIVE ? this.bounds.maxZ : this.bounds.minZ);
float z1 = vertices[0].vec[2];
float z2 = vertices[1].vec[2];
float z3 = vertices[2].vec[2];
float z4 = vertices[3].vec[2];
return z1 != z2 || z2 != z3 || z3 != z4 || z4 != bound;
}
}
}
return true;
}
}
@@ -18,7 +18,6 @@
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.Vector4f;
import net.minecraft.util.Direction;
@@ -28,67 +27,58 @@ import appeng.thirdparty.codechicken.lib.model.Quad;
import appeng.thirdparty.codechicken.lib.model.pipeline.IPipelineElementFactory;
import appeng.thirdparty.codechicken.lib.model.pipeline.QuadTransformer;
/**
* Created by covers1624 on 2/6/20.
*/
public class QuadMatrixTransformer extends QuadTransformer
{
public static IPipelineElementFactory<QuadMatrixTransformer> FACTORY = QuadMatrixTransformer::new;
private static final Matrix4f identity;
public class QuadMatrixTransformer extends QuadTransformer {
public static IPipelineElementFactory<QuadMatrixTransformer> FACTORY = QuadMatrixTransformer::new;
private static final Matrix4f identity;
static
{
identity = new Matrix4f();
identity.setIdentity();
}
static {
identity = new Matrix4f();
identity.setIdentity();
}
private final Vector4f storage = new Vector4f();
private Matrix4f matrix;
private boolean identityMatrix;
private final Vector4f storage = new Vector4f();
private Matrix4f matrix;
private boolean identityMatrix;
QuadMatrixTransformer()
{
super();
}
QuadMatrixTransformer() {
super();
}
public QuadMatrixTransformer( IVertexConsumer parent, Matrix4f matrix )
{
super( parent );
this.matrix = matrix;
this.identityMatrix = matrix.equals( identity );
}
public QuadMatrixTransformer(IVertexConsumer parent, Matrix4f matrix) {
super(parent);
this.matrix = matrix;
this.identityMatrix = matrix.equals(identity);
}
public void setMatrix( Matrix4f matrix )
{
this.matrix = matrix;
this.identityMatrix = matrix.equals( identity );
}
public void setMatrix(Matrix4f matrix) {
this.matrix = matrix;
this.identityMatrix = matrix.equals(identity);
}
@Override
public boolean transform()
{
if( identityMatrix )
{
return true;
}
for( Quad.Vertex vertex : this.quad.vertices )
{
storage.set( vertex.vec[0], vertex.vec[1], vertex.vec[2], 1 );
storage.transform( matrix );
vertex.vec[0] = storage.getX();
vertex.vec[1] = storage.getY();
vertex.vec[2] = storage.getZ();
@Override
public boolean transform() {
if (identityMatrix) {
return true;
}
for (Quad.Vertex vertex : this.quad.vertices) {
storage.set(vertex.vec[0], vertex.vec[1], vertex.vec[2], 1);
storage.transform(matrix);
vertex.vec[0] = storage.getX();
vertex.vec[1] = storage.getY();
vertex.vec[2] = storage.getZ();
storage.set( vertex.normal[0], vertex.normal[1], vertex.normal[2], 0 );
storage.transform( matrix );
storage.normalize();
vertex.normal[0] = storage.getX();
vertex.normal[1] = storage.getY();
vertex.normal[2] = storage.getZ();
}
Quad.Vertex v0 = quad.vertices[0];
quad.orientation = Direction.getFacingFromVector( v0.normal[0], v0.normal[1], v0.normal[2] );
return true;
}
storage.set(vertex.normal[0], vertex.normal[1], vertex.normal[2], 0);
storage.transform(matrix);
storage.normalize();
vertex.normal[0] = storage.getX();
vertex.normal[1] = storage.getY();
vertex.normal[2] = storage.getZ();
}
Quad.Vertex v0 = quad.vertices[0];
quad.orientation = Direction.getFacingFromVector(v0.normal[0], v0.normal[1], v0.normal[2]);
return true;
}
}
@@ -18,7 +18,6 @@
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
import appeng.thirdparty.codechicken.lib.math.InterpHelper;
import appeng.thirdparty.codechicken.lib.model.CachedFormat;
import appeng.thirdparty.codechicken.lib.model.Quad;
@@ -26,67 +25,56 @@ import appeng.thirdparty.codechicken.lib.model.Quad.Vertex;
import appeng.thirdparty.codechicken.lib.model.pipeline.IPipelineElementFactory;
import appeng.thirdparty.codechicken.lib.model.pipeline.QuadTransformer;
/**
* This transformer Re-Interpolates the Color, UV's and LightMaps.
* Use this after all transformations that translate vertices in the pipeline.
* This transformer Re-Interpolates the Color, UV's and LightMaps. Use this
* after all transformations that translate vertices in the pipeline.
*
* This Transformation can only be used in the BakedPipeline.
*
* @author covers1624
*/
public class QuadReInterpolator extends QuadTransformer
{
public class QuadReInterpolator extends QuadTransformer {
public static final IPipelineElementFactory<QuadReInterpolator> FACTORY = QuadReInterpolator::new;
public static final IPipelineElementFactory<QuadReInterpolator> FACTORY = QuadReInterpolator::new;
private Quad interpCache = new Quad();
private InterpHelper interpHelper = new InterpHelper();
private Quad interpCache = new Quad();
private InterpHelper interpHelper = new InterpHelper();
QuadReInterpolator()
{
super();
}
QuadReInterpolator() {
super();
}
@Override
public void reset( CachedFormat format )
{
super.reset( format );
this.interpCache.reset( format );
}
@Override
public void reset(CachedFormat format) {
super.reset(format);
this.interpCache.reset(format);
}
@Override
public void setInputQuad( Quad quad )
{
super.setInputQuad( quad );
quad.resetInterp( this.interpHelper, quad.orientation.ordinal() >> 1 );
}
@Override
public void setInputQuad(Quad quad) {
super.setInputQuad(quad);
quad.resetInterp(this.interpHelper, quad.orientation.ordinal() >> 1);
}
@Override
public boolean transform()
{
int s = this.quad.orientation.ordinal() >> 1;
if( this.format.hasColor || this.format.hasUV || this.format.hasLightMap )
{
this.interpCache.copyFrom( this.quad );
this.interpHelper.setup();
for( Vertex v : this.quad.vertices )
{
this.interpHelper.locate( v.dx( s ), v.dy( s ) );
if( this.format.hasColor )
{
v.interpColorFrom( this.interpHelper, this.interpCache.vertices );
}
if( this.format.hasUV )
{
v.interpUVFrom( this.interpHelper, this.interpCache.vertices );
}
if( this.format.hasLightMap )
{
v.interpLightMapFrom( this.interpHelper, this.interpCache.vertices );
}
}
}
return true;
}
@Override
public boolean transform() {
int s = this.quad.orientation.ordinal() >> 1;
if (this.format.hasColor || this.format.hasUV || this.format.hasLightMap) {
this.interpCache.copyFrom(this.quad);
this.interpHelper.setup();
for (Vertex v : this.quad.vertices) {
this.interpHelper.locate(v.dx(s), v.dy(s));
if (this.format.hasColor) {
v.interpColorFrom(this.interpHelper, this.interpCache.vertices);
}
if (this.format.hasUV) {
v.interpUVFrom(this.interpHelper, this.interpCache.vertices);
}
if (this.format.hasLightMap) {
v.interpLightMapFrom(this.interpHelper, this.interpCache.vertices);
}
}
}
return true;
}
}
@@ -18,61 +18,52 @@
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
import appeng.thirdparty.codechicken.lib.model.Quad.Vertex;
import appeng.thirdparty.codechicken.lib.model.pipeline.IPipelineElementFactory;
import appeng.thirdparty.codechicken.lib.model.pipeline.QuadTransformer;
/**
* This transformer tints quads..
* Feed it the output of BlockColors.colorMultiplier.
* This transformer tints quads.. Feed it the output of
* BlockColors.colorMultiplier.
*
* @author covers1624
*/
public class QuadTinter extends QuadTransformer
{
public class QuadTinter extends QuadTransformer {
public static final IPipelineElementFactory<QuadTinter> FACTORY = QuadTinter::new;
public static final IPipelineElementFactory<QuadTinter> FACTORY = QuadTinter::new;
private int tint;
private int tint;
QuadTinter()
{
super();
}
QuadTinter() {
super();
}
public QuadTinter( IVertexConsumer consumer, int tint )
{
super( consumer );
this.tint = tint;
}
public QuadTinter(IVertexConsumer consumer, int tint) {
super(consumer);
this.tint = tint;
}
public QuadTinter setTint( int tint )
{
this.tint = tint;
return this;
}
public QuadTinter setTint(int tint) {
this.tint = tint;
return this;
}
@Override
public boolean transform()
{
// Nuke tintIndex.
this.quad.tintIndex = -1;
if( this.format.hasColor )
{
float r = ( this.tint >> 0x10 & 0xFF ) / 255F;
float g = ( this.tint >> 0x08 & 0xFF ) / 255F;
float b = ( this.tint & 0xFF ) / 255F;
for( Vertex v : this.quad.vertices )
{
v.color[0] *= r;
v.color[1] *= g;
v.color[2] *= b;
}
}
return true;
}
@Override
public boolean transform() {
// Nuke tintIndex.
this.quad.tintIndex = -1;
if (this.format.hasColor) {
float r = (this.tint >> 0x10 & 0xFF) / 255F;
float g = (this.tint >> 0x08 & 0xFF) / 255F;
float b = (this.tint & 0xFF) / 255F;
for (Vertex v : this.quad.vertices) {
v.color[0] *= r;
v.color[1] *= g;
v.color[2] *= b;
}
}
return true;
}
}