2019-01-01 01:10:18 +00:00
|
|
|
/*
|
|
|
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
|
|
|
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
|
|
|
* Send enquiries to dratcliffe@gmail.com
|
|
|
|
*/
|
|
|
|
|
2017-11-21 00:18:03 +00:00
|
|
|
package dan200.computercraft.client.render;
|
|
|
|
|
Update CC: Tweaked to 1.13
Look, I originally had this split into several commits, but lots of
other cleanups got mixed in. I then backported some of the cleanups to
1.12, did other tidy ups there, and eventually the web of merges was
unreadable.
Yes, this is a horrible mess, but it's still nicer than it was. Anyway,
changes:
- Flatten everything. For instance, there are now three instances of
BlockComputer, two BlockTurtle, ItemPocketComputer. There's also no
more BlockPeripheral (thank heavens) - there's separate block classes
for each peripheral type.
- Remove pretty much all legacy code. As we're breaking world
compatibility anyway, we can remove all the code to load worlds from
1.4 days.
- The command system is largely rewriten to take advantage of 1.13's
new system. It's very fancy!
- WidgetTerminal now uses Minecraft's "GUI listener" system.
- BREAKING CHANGE: All the codes in keys.lua are different, due to the
move to LWJGL 3. Hopefully this won't have too much of an impact.
I don't want to map to the old key codes on the Java side, as there
always ends up being small but slight inconsistencies. IMO it's
better to make a clean break - people should be using keys rather
than hard coding the constants anyway.
- commands.list now allows fetching sub-commands. The ROM has already
been updated to allow fancy usage such as commands.time.set("noon").
- Turtles, modems and cables can be waterlogged.
2019-04-02 12:27:27 +00:00
|
|
|
import net.minecraft.client.renderer.model.BakedQuad;
|
2017-11-21 00:18:03 +00:00
|
|
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|
|
|
import net.minecraft.client.renderer.vertex.VertexFormat;
|
|
|
|
import net.minecraft.util.EnumFacing;
|
|
|
|
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
|
|
|
|
import net.minecraftforge.client.model.pipeline.LightUtil;
|
|
|
|
import net.minecraftforge.client.model.pipeline.VertexTransformer;
|
|
|
|
import net.minecraftforge.common.model.TRSRTransformation;
|
|
|
|
|
|
|
|
import javax.annotation.Nonnull;
|
|
|
|
import javax.vecmath.Matrix4f;
|
|
|
|
import javax.vecmath.Point3f;
|
|
|
|
import javax.vecmath.Vector3f;
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Transforms vertices of a model, remaining aware of winding order, and rearranging
|
|
|
|
* vertices if needed.
|
|
|
|
*/
|
|
|
|
public final class ModelTransformer
|
|
|
|
{
|
|
|
|
private static final Matrix4f identity;
|
|
|
|
|
|
|
|
static
|
|
|
|
{
|
|
|
|
identity = new Matrix4f();
|
|
|
|
identity.setIdentity();
|
|
|
|
}
|
|
|
|
|
|
|
|
private ModelTransformer()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void transformQuadsTo( List<BakedQuad> output, List<BakedQuad> input, Matrix4f transform )
|
|
|
|
{
|
|
|
|
if( transform == null || transform.equals( identity ) )
|
|
|
|
{
|
|
|
|
output.addAll( input );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Matrix4f normalMatrix = new Matrix4f( transform );
|
|
|
|
normalMatrix.invert();
|
|
|
|
normalMatrix.transpose();
|
|
|
|
|
|
|
|
for( BakedQuad quad : input ) output.add( doTransformQuad( quad, transform, normalMatrix ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static BakedQuad transformQuad( BakedQuad input, Matrix4f transform )
|
|
|
|
{
|
|
|
|
if( transform == null || transform.equals( identity ) ) return input;
|
|
|
|
|
|
|
|
Matrix4f normalMatrix = new Matrix4f( transform );
|
|
|
|
normalMatrix.invert();
|
|
|
|
normalMatrix.transpose();
|
|
|
|
return doTransformQuad( input, transform, normalMatrix );
|
|
|
|
}
|
|
|
|
|
|
|
|
private static BakedQuad doTransformQuad( BakedQuad input, Matrix4f positionMatrix, Matrix4f normalMatrix )
|
|
|
|
{
|
|
|
|
|
|
|
|
BakedQuadBuilder builder = new BakedQuadBuilder( input.getFormat() );
|
|
|
|
NormalAwareTransformer transformer = new NormalAwareTransformer( builder, positionMatrix, normalMatrix );
|
|
|
|
input.pipe( transformer );
|
|
|
|
|
|
|
|
if( transformer.areNormalsInverted() )
|
|
|
|
{
|
|
|
|
builder.swap( 1, 3 );
|
|
|
|
transformer.areNormalsInverted();
|
|
|
|
}
|
|
|
|
|
|
|
|
return builder.build();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A vertex transformer that tracks whether the normals have been inverted and so the vertices
|
|
|
|
* should be reordered so backface culling works as expected.
|
|
|
|
*/
|
|
|
|
private static class NormalAwareTransformer extends VertexTransformer
|
|
|
|
{
|
|
|
|
private final Matrix4f positionMatrix;
|
|
|
|
private final Matrix4f normalMatrix;
|
|
|
|
|
|
|
|
private int vertexIndex = 0, elementIndex = 0;
|
2018-12-23 17:46:58 +00:00
|
|
|
private final Point3f[] before = new Point3f[4];
|
|
|
|
private final Point3f[] after = new Point3f[4];
|
2017-11-21 00:18:03 +00:00
|
|
|
|
|
|
|
public NormalAwareTransformer( IVertexConsumer parent, Matrix4f positionMatrix, Matrix4f normalMatrix )
|
|
|
|
{
|
|
|
|
super( parent );
|
|
|
|
this.positionMatrix = positionMatrix;
|
|
|
|
this.normalMatrix = normalMatrix;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2018-12-29 16:42:02 +00:00
|
|
|
public void setQuadOrientation( @Nonnull EnumFacing orientation )
|
2017-11-21 00:18:03 +00:00
|
|
|
{
|
|
|
|
super.setQuadOrientation( orientation == null ? orientation : TRSRTransformation.rotate( positionMatrix, orientation ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void put( int element, @Nonnull float... data )
|
|
|
|
{
|
|
|
|
switch( getVertexFormat().getElement( element ).getUsage() )
|
|
|
|
{
|
|
|
|
case POSITION:
|
|
|
|
{
|
|
|
|
Point3f vec = new Point3f( data );
|
|
|
|
Point3f newVec = new Point3f();
|
|
|
|
positionMatrix.transform( vec, newVec );
|
|
|
|
|
2018-12-23 17:46:58 +00:00
|
|
|
float[] newData = new float[4];
|
2017-11-21 00:18:03 +00:00
|
|
|
newVec.get( newData );
|
|
|
|
super.put( element, newData );
|
|
|
|
|
|
|
|
|
2018-12-23 17:46:58 +00:00
|
|
|
before[vertexIndex] = vec;
|
|
|
|
after[vertexIndex] = newVec;
|
2017-11-21 00:18:03 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NORMAL:
|
|
|
|
{
|
|
|
|
Vector3f vec = new Vector3f( data );
|
|
|
|
normalMatrix.transform( vec );
|
|
|
|
|
2018-12-23 17:46:58 +00:00
|
|
|
float[] newData = new float[4];
|
2017-11-21 00:18:03 +00:00
|
|
|
vec.get( newData );
|
|
|
|
super.put( element, newData );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
super.put( element, data );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
elementIndex++;
|
|
|
|
if( elementIndex == getVertexFormat().getElementCount() )
|
|
|
|
{
|
|
|
|
vertexIndex++;
|
|
|
|
elementIndex = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean areNormalsInverted()
|
|
|
|
{
|
|
|
|
Vector3f temp1 = new Vector3f(), temp2 = new Vector3f();
|
|
|
|
Vector3f crossBefore = new Vector3f(), crossAfter = new Vector3f();
|
|
|
|
|
|
|
|
// Determine what cross product we expect to have
|
2018-12-23 17:46:58 +00:00
|
|
|
temp1.sub( before[1], before[0] );
|
|
|
|
temp2.sub( before[1], before[2] );
|
2017-11-21 00:18:03 +00:00
|
|
|
crossBefore.cross( temp1, temp2 );
|
|
|
|
normalMatrix.transform( crossBefore );
|
|
|
|
|
|
|
|
// And determine what cross product we actually have
|
2018-12-23 17:46:58 +00:00
|
|
|
temp1.sub( after[1], after[0] );
|
|
|
|
temp2.sub( after[1], after[2] );
|
2017-11-21 00:18:03 +00:00
|
|
|
crossAfter.cross( temp1, temp2 );
|
|
|
|
|
2018-12-23 17:46:58 +00:00
|
|
|
// If the angle between expected and actual cross product is greater than
|
2017-11-21 00:18:03 +00:00
|
|
|
// pi/2 radians then we will need to reorder our quads.
|
|
|
|
return Math.abs( crossBefore.angle( crossAfter ) ) >= Math.PI / 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A vertex consumer which is capable of building {@link BakedQuad}s.
|
|
|
|
*
|
|
|
|
* Equivalent to {@link net.minecraftforge.client.model.pipeline.UnpackedBakedQuad.Builder} but more memory
|
|
|
|
* efficient.
|
|
|
|
*
|
|
|
|
* This also provides the ability to swap vertices through {@link #swap(int, int)} to allow reordering.
|
|
|
|
*/
|
2019-03-29 21:21:39 +00:00
|
|
|
private static final class BakedQuadBuilder implements IVertexConsumer
|
2017-11-21 00:18:03 +00:00
|
|
|
{
|
|
|
|
private final VertexFormat format;
|
|
|
|
|
|
|
|
private final int[] vertexData;
|
|
|
|
private int vertexIndex = 0, elementIndex = 0;
|
|
|
|
|
|
|
|
private EnumFacing orientation;
|
|
|
|
private int quadTint;
|
|
|
|
private boolean diffuse;
|
|
|
|
private TextureAtlasSprite texture;
|
|
|
|
|
|
|
|
private BakedQuadBuilder( VertexFormat format )
|
|
|
|
{
|
|
|
|
this.format = format;
|
2019-03-29 21:21:39 +00:00
|
|
|
vertexData = new int[format.getSize()];
|
2017-11-21 00:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
|
|
|
public VertexFormat getVertexFormat()
|
|
|
|
{
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void setQuadTint( int tint )
|
|
|
|
{
|
2019-03-29 21:21:39 +00:00
|
|
|
quadTint = tint;
|
2017-11-21 00:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void setQuadOrientation( @Nonnull EnumFacing orientation )
|
|
|
|
{
|
|
|
|
this.orientation = orientation;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void setApplyDiffuseLighting( boolean diffuse )
|
|
|
|
{
|
|
|
|
this.diffuse = diffuse;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void setTexture( @Nonnull TextureAtlasSprite texture )
|
|
|
|
{
|
|
|
|
this.texture = texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void put( int element, @Nonnull float... data )
|
|
|
|
{
|
|
|
|
LightUtil.pack( data, vertexData, format, vertexIndex, element );
|
|
|
|
|
|
|
|
elementIndex++;
|
|
|
|
if( elementIndex == getVertexFormat().getElementCount() )
|
|
|
|
{
|
|
|
|
vertexIndex++;
|
|
|
|
elementIndex = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void swap( int a, int b )
|
|
|
|
{
|
|
|
|
int length = vertexData.length / 4;
|
|
|
|
for( int i = 0; i < length; i++ )
|
|
|
|
{
|
2018-12-23 17:46:58 +00:00
|
|
|
int temp = vertexData[a * length + i];
|
|
|
|
vertexData[a * length + i] = vertexData[b * length + i];
|
|
|
|
vertexData[b * length + i] = temp;
|
2017-11-21 00:18:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public BakedQuad build()
|
|
|
|
{
|
|
|
|
if( elementIndex != 0 || vertexIndex != 4 )
|
|
|
|
{
|
|
|
|
throw new IllegalStateException( "Got an unexpected number of elements/vertices" );
|
|
|
|
}
|
|
|
|
if( texture == null )
|
|
|
|
{
|
|
|
|
throw new IllegalStateException( "Texture has not been set" );
|
|
|
|
}
|
|
|
|
|
|
|
|
return new BakedQuad( vertexData, quadTint, orientation, texture, diffuse, format );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|