196 lines
5.9 KiB
Java
196 lines
5.9 KiB
Java
/*
|
|
* Minecraft Forge
|
|
* Copyright (c) 2016-2019.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation version 2.1
|
|
* of the License.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
package net.minecraftforge.client.model.pipeline;
|
|
|
|
import com.google.common.collect.ImmutableList;
|
|
|
|
import net.minecraft.client.renderer.model.BakedQuad;
|
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
|
import net.minecraft.client.renderer.vertex.VertexFormat;
|
|
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
|
import net.minecraft.util.Direction;
|
|
|
|
/**
|
|
* Allows easier building of BakedQuad objects. During building, data is stored
|
|
* unpacked as floats, but is packed into the typical int array format on build.
|
|
*/
|
|
public class BakedQuadBuilder implements IVertexConsumer
|
|
{
|
|
private static final int SIZE = DefaultVertexFormats.BLOCK.getElements().size();
|
|
|
|
private final float[][][] unpackedData = new float[4][SIZE][4];
|
|
private int tint = -1;
|
|
private Direction orientation;
|
|
private TextureAtlasSprite texture;
|
|
private boolean applyDiffuseLighting = true;
|
|
|
|
private int vertices = 0;
|
|
private int elements = 0;
|
|
private boolean full = false;
|
|
private boolean contractUVs = false;
|
|
|
|
public BakedQuadBuilder() {}
|
|
|
|
public BakedQuadBuilder(TextureAtlasSprite texture)
|
|
{
|
|
this.texture = texture;
|
|
}
|
|
|
|
public void setContractUVs(boolean value)
|
|
{
|
|
this.contractUVs = value;
|
|
}
|
|
|
|
@Override
|
|
public VertexFormat getVertexFormat()
|
|
{
|
|
return DefaultVertexFormats.BLOCK;
|
|
}
|
|
|
|
@Override
|
|
public void setQuadTint(int tint)
|
|
{
|
|
this.tint = tint;
|
|
}
|
|
|
|
@Override
|
|
public void setQuadOrientation(Direction orientation)
|
|
{
|
|
this.orientation = orientation;
|
|
}
|
|
|
|
@Override
|
|
public void setTexture(TextureAtlasSprite texture)
|
|
{
|
|
this.texture = texture;
|
|
}
|
|
|
|
@Override
|
|
public void setApplyDiffuseLighting(boolean diffuse)
|
|
{
|
|
this.applyDiffuseLighting = diffuse;
|
|
}
|
|
|
|
@Override
|
|
public void put(int element, float... data)
|
|
{
|
|
for(int i = 0; i < 4; i++)
|
|
{
|
|
if(i < data.length)
|
|
{
|
|
unpackedData[vertices][element][i] = data[i];
|
|
}
|
|
else
|
|
{
|
|
unpackedData[vertices][element][i] = 0;
|
|
}
|
|
}
|
|
elements++;
|
|
if(elements == SIZE)
|
|
{
|
|
vertices++;
|
|
elements = 0;
|
|
}
|
|
if(vertices == 4)
|
|
{
|
|
full = true;
|
|
}
|
|
}
|
|
|
|
private final float eps = 1f / 0x100;
|
|
|
|
public BakedQuad build()
|
|
{
|
|
if(!full)
|
|
{
|
|
throw new IllegalStateException("not enough data");
|
|
}
|
|
if(texture == null)
|
|
{
|
|
throw new IllegalStateException("texture not set");
|
|
}
|
|
if(contractUVs)
|
|
{
|
|
float tX = texture.getWidth() / (texture.getMaxU() - texture.getMinU());
|
|
float tY = texture.getHeight() / (texture.getMaxV() - texture.getMinV());
|
|
float tS = tX > tY ? tX : tY;
|
|
float ep = 1f / (tS * 0x100);
|
|
int uve = 0;
|
|
ImmutableList<VertexFormatElement> elements = DefaultVertexFormats.BLOCK.getElements();
|
|
while(uve < elements.size())
|
|
{
|
|
VertexFormatElement e = elements.get(uve);
|
|
if(e.getUsage() == VertexFormatElement.Usage.UV && e.getIndex() == 0)
|
|
{
|
|
break;
|
|
}
|
|
uve++;
|
|
}
|
|
if(uve == elements.size())
|
|
{
|
|
throw new IllegalStateException("Can't contract UVs: format doesn't contain UVs");
|
|
}
|
|
float[] uvc = new float[4];
|
|
for(int v = 0; v < 4; v++)
|
|
{
|
|
for(int i = 0; i < 4; i++)
|
|
{
|
|
uvc[i] += unpackedData[v][uve][i] / 4;
|
|
}
|
|
}
|
|
for(int v = 0; v < 4; v++)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
float uo = unpackedData[v][uve][i];
|
|
float un = uo * (1 - eps) + uvc[i] * eps;
|
|
float ud = uo - un;
|
|
float aud = ud;
|
|
if(aud < 0) aud = -aud;
|
|
if(aud < ep) // not moving a fraction of a pixel
|
|
{
|
|
float udc = uo - uvc[i];
|
|
if(udc < 0) udc = -udc;
|
|
if(udc < 2 * ep) // center is closer than 2 fractions of a pixel, don't move too close
|
|
{
|
|
un = (uo + uvc[i]) / 2;
|
|
}
|
|
else // move at least by a fraction
|
|
{
|
|
un = uo + (ud < 0 ? ep : -ep);
|
|
}
|
|
}
|
|
unpackedData[v][uve][i] = un;
|
|
}
|
|
}
|
|
}
|
|
int[] packed = new int[DefaultVertexFormats.BLOCK.getIntegerSize() * 4];
|
|
for (int v = 0; v < 4; v++)
|
|
{
|
|
for (int e = 0; e < SIZE; e++)
|
|
{
|
|
LightUtil.pack(unpackedData[v][e], packed, DefaultVertexFormats.BLOCK, v, e);
|
|
}
|
|
}
|
|
return new BakedQuad(packed, tint, orientation, texture, applyDiffuseLighting);
|
|
}
|
|
}
|