From 115f73de2ed00831e4382a24af511e34a266e162 Mon Sep 17 00:00:00 2001 From: shartte Date: Tue, 16 Aug 2016 16:04:31 +0200 Subject: [PATCH] Implemented Glass Blocks (#51) * Implemented connected texture glass blocks (different approach from 1.7). --- src/main/java/appeng/client/ClientHelper.java | 2 + .../client/render/model/GlassBakedModel.java | 313 ++++++++++++++++++ .../client/render/model/GlassModel.java | 69 ++++ .../client/render/model/GlassModelLoader.java | 55 +++ .../client/render/model/RenderHelper.java | 107 ++++++ .../appeng/decorative/solid/GlassState.java | 67 ++++ .../decorative/solid/QuartzGlassBlock.java | 59 +++- .../solid/UnlistedGlassStateProperty.java | 54 +++ .../blockstates/QuartzGlassBlock.json | 2 +- .../blockstates/QuartzLampBlock.json | 5 + .../models/block/QuartzGlassBlock.json | 6 - .../models/item/QuartzGlassBlock.json | 6 + .../models/item/QuartzLampBlock.json | 6 + .../blocks/glass/BlockQuartzGlassA.png | Bin 0 -> 232 bytes .../blocks/glass/BlockQuartzGlassB.png | Bin 0 -> 230 bytes .../blocks/glass/BlockQuartzGlassC.png | Bin 0 -> 244 bytes .../blocks/glass/BlockQuartzGlassD.png | Bin 0 -> 243 bytes .../glass/BlockQuartzGlassFrame0001.png | Bin 0 -> 151 bytes .../glass/BlockQuartzGlassFrame0010.png | Bin 0 -> 172 bytes .../glass/BlockQuartzGlassFrame0011.png | Bin 0 -> 191 bytes .../glass/BlockQuartzGlassFrame0100.png | Bin 0 -> 167 bytes .../glass/BlockQuartzGlassFrame0101.png | Bin 0 -> 192 bytes .../glass/BlockQuartzGlassFrame0110.png | Bin 0 -> 203 bytes .../glass/BlockQuartzGlassFrame0111.png | Bin 0 -> 228 bytes .../glass/BlockQuartzGlassFrame1000.png | Bin 0 -> 170 bytes .../glass/BlockQuartzGlassFrame1001.png | Bin 0 -> 192 bytes .../glass/BlockQuartzGlassFrame1010.png | Bin 0 -> 209 bytes .../glass/BlockQuartzGlassFrame1011.png | Bin 0 -> 229 bytes .../glass/BlockQuartzGlassFrame1100.png | Bin 0 -> 202 bytes .../glass/BlockQuartzGlassFrame1101.png | Bin 0 -> 223 bytes .../glass/BlockQuartzGlassFrame1110.png | Bin 0 -> 239 bytes .../glass/BlockQuartzGlassFrame1111.png | Bin 0 -> 248 bytes .../textures/items/BlockQuartzGlass.png | Bin 0 -> 311 bytes 33 files changed, 741 insertions(+), 10 deletions(-) create mode 100644 src/main/java/appeng/client/render/model/GlassBakedModel.java create mode 100644 src/main/java/appeng/client/render/model/GlassModel.java create mode 100644 src/main/java/appeng/client/render/model/GlassModelLoader.java create mode 100644 src/main/java/appeng/client/render/model/RenderHelper.java create mode 100644 src/main/java/appeng/decorative/solid/GlassState.java create mode 100644 src/main/java/appeng/decorative/solid/UnlistedGlassStateProperty.java create mode 100644 src/main/resources/assets/appliedenergistics2/blockstates/QuartzLampBlock.json delete mode 100644 src/main/resources/assets/appliedenergistics2/models/block/QuartzGlassBlock.json create mode 100644 src/main/resources/assets/appliedenergistics2/models/item/QuartzGlassBlock.json create mode 100644 src/main/resources/assets/appliedenergistics2/models/item/QuartzLampBlock.json create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassA.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassB.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassC.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassD.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0001.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0010.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0011.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0100.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0101.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0110.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0111.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1000.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1001.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1010.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1011.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1100.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1101.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1110.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1111.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/items/BlockQuartzGlass.png diff --git a/src/main/java/appeng/client/ClientHelper.java b/src/main/java/appeng/client/ClientHelper.java index c8ff2fb8..3f01b476 100644 --- a/src/main/java/appeng/client/ClientHelper.java +++ b/src/main/java/appeng/client/ClientHelper.java @@ -62,6 +62,7 @@ import appeng.client.render.effects.EnergyFx; import appeng.client.render.effects.LightningArcFX; import appeng.client.render.effects.LightningFX; import appeng.client.render.effects.VibrantFX; +import appeng.client.render.model.GlassModelLoader; import appeng.client.render.model.UVLModelLoader; import appeng.client.render.textures.ParticleTextures; import appeng.core.AEConfig; @@ -93,6 +94,7 @@ public class ClientHelper extends ServerHelper { MinecraftForge.EVENT_BUS.register( this ); ModelLoaderRegistry.registerLoader( UVLModelLoader.INSTANCE ); + ModelLoaderRegistry.registerLoader( new GlassModelLoader() ); for( IAEFeature feature : Api.INSTANCE.definitions().getFeatureRegistry().getRegisteredFeatures() ) { feature.handler().registerStateMapper(); diff --git a/src/main/java/appeng/client/render/model/GlassBakedModel.java b/src/main/java/appeng/client/render/model/GlassBakedModel.java new file mode 100644 index 00000000..9aca610b --- /dev/null +++ b/src/main/java/appeng/client/render/model/GlassBakedModel.java @@ -0,0 +1,313 @@ +/* + * This file is part of Applied Energistics 2. + * Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. + * + * Applied Energistics 2 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, either version 3 of the License, or + * (at your option) any later version. + * + * Applied Energistics 2 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 Applied Energistics 2. If not, see . + */ + +package appeng.client.render.model; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.stream.IntStream; +import javax.annotation.Nullable; + +import com.google.common.base.Function; +import com.google.common.base.Strings; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.block.model.ItemCameraTransforms; +import net.minecraft.client.renderer.block.model.ItemOverrideList; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad; +import net.minecraftforge.common.property.IExtendedBlockState; + +import appeng.decorative.solid.GlassState; +import appeng.decorative.solid.QuartzGlassBlock; + + +public class GlassBakedModel implements IBakedModel +{ + + private static final byte[][][] OFFSETS = generateOffsets(); + + // Alternating textures based on position + static final ResourceLocation TEXTURE_A = new ResourceLocation( "appliedenergistics2:blocks/glass/BlockQuartzGlassA" ); + static final ResourceLocation TEXTURE_B = new ResourceLocation( "appliedenergistics2:blocks/glass/BlockQuartzGlassB" ); + static final ResourceLocation TEXTURE_C = new ResourceLocation( "appliedenergistics2:blocks/glass/BlockQuartzGlassC" ); + static final ResourceLocation TEXTURE_D = new ResourceLocation( "appliedenergistics2:blocks/glass/BlockQuartzGlassD" ); + + // Frame texture + static final ResourceLocation[] TEXTURES_FRAME = generateTexturesFrame(); + + // Generates the required textures for the frame + private static ResourceLocation[] generateTexturesFrame() + { + return IntStream.range( 1, 16 ) + .mapToObj( Integer::toBinaryString ) + .map( s -> Strings.padStart( s, 4, '0' ) ) + .map( s -> new ResourceLocation( "appliedenergistics2:blocks/glass/BlockQuartzGlassFrame" + s ) ) + .toArray( ResourceLocation[]::new ); + } + + private final TextureAtlasSprite[] glassTextures; + + private final TextureAtlasSprite[] frameTextures; + + private final VertexFormat vertexFormat; + + public GlassBakedModel( VertexFormat format, Function bakedTextureGetter ) + { + this.glassTextures = new TextureAtlasSprite[] { + bakedTextureGetter.apply( TEXTURE_A ), + bakedTextureGetter.apply( TEXTURE_B ), + bakedTextureGetter.apply( TEXTURE_C ), + bakedTextureGetter.apply( TEXTURE_D ) + }; + + this.vertexFormat = format; + + // The first frame texture would be empty, so we simply leave it set to null here + this.frameTextures = new TextureAtlasSprite[16]; + for( int i = 0; i < TEXTURES_FRAME.length; i++ ) + { + this.frameTextures[1 + i] = bakedTextureGetter.apply( TEXTURES_FRAME[i] ); + } + } + + @Override + public List getQuads( @Nullable IBlockState state, @Nullable EnumFacing side, long rand ) + { + + if( !( state instanceof IExtendedBlockState ) || side == null ) + { + return Collections.emptyList(); + } + + IExtendedBlockState extState = (IExtendedBlockState) state; + + GlassState glassState = extState.getValue( QuartzGlassBlock.GLASS_STATE ); + + final int cx = Math.abs( glassState.getX() % 10 ); + final int cy = Math.abs( glassState.getY() % 10 ); + final int cz = Math.abs( glassState.getZ() % 10 ); + + int u = OFFSETS[cx][cy][cz] % 4; + int v = OFFSETS[9 - cx][9 - cy][9 - cz] % 4; + + int texIdx = Math.abs( ( OFFSETS[cx][cy][cz] + ( glassState.getX() + glassState.getY() + glassState.getZ() ) ) % 4 ); + + if( texIdx < 2 ) + { + u /= 2; + v /= 2; + } + + TextureAtlasSprite glassTexture = glassTextures[texIdx]; + + // Render the glass side + List quads = new ArrayList<>( 5 ); // At most 5 + + List corners = RenderHelper.getFaceCorners( side ); + quads.add( createQuad( side, corners, glassTexture, u, v ) ); + + /* + This needs some explanation: + The bit-field contains 4-bits, one for each direction that a frame may be drawn. + Converted to a number, the bit-field is then used as an index into the list of + frame textures, which have been created in such a way that their filenames + indicate, in which directions they contain borders. + i.e. bitmask = 0101 means a border should be drawn up and down (in terms of u,v space). + Converted to a number, this bitmask is 5. So the texture at index 5 is used. + That texture had "0101" in its filename to indicate this. + */ + int edgeBitmask = makeBitmask( glassState, side ); + TextureAtlasSprite sideSprite = frameTextures[edgeBitmask]; + if( sideSprite != null ) + { + quads.add( createQuad( side, corners, sideSprite, 0, 0 ) ); + } + + return quads; + } + + /** + * Creates the bitmask that indicates, in which directions (in terms of u,v space) a border should be drawn. + */ + private static int makeBitmask( GlassState state, EnumFacing side ) + { + switch( side ) + { + case DOWN: + return makeBitmask( state, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.NORTH, EnumFacing.WEST ); + case UP: + return makeBitmask( state, EnumFacing.SOUTH, EnumFacing.WEST, EnumFacing.NORTH, EnumFacing.EAST ); + case NORTH: + return makeBitmask( state, EnumFacing.UP, EnumFacing.WEST, EnumFacing.DOWN, EnumFacing.EAST ); + case SOUTH: + return makeBitmask( state, EnumFacing.UP, EnumFacing.EAST, EnumFacing.DOWN, EnumFacing.WEST ); + case WEST: + return makeBitmask( state, EnumFacing.UP, EnumFacing.SOUTH, EnumFacing.DOWN, EnumFacing.NORTH ); + case EAST: + return makeBitmask( state, EnumFacing.UP, EnumFacing.NORTH, EnumFacing.DOWN, EnumFacing.SOUTH ); + default: + throw new IllegalArgumentException( "Unsupported side!" ); + } + } + + private static int makeBitmask( GlassState state, EnumFacing up, EnumFacing right, EnumFacing down, EnumFacing left ) + { + + int bitmask = 0; + + if( !state.isFlushWith( up ) ) + { + bitmask |= 1; + } + if( !state.isFlushWith( right ) ) + { + bitmask |= 2; + } + if( !state.isFlushWith( down ) ) + { + bitmask |= 4; + } + if( !state.isFlushWith( left ) ) + { + bitmask |= 8; + } + return bitmask; + } + + private BakedQuad createQuad( EnumFacing side, List corners, TextureAtlasSprite sprite, float uOffset, float vOffset ) + { + return createQuad( side, corners.get( 0 ), corners.get( 1 ), corners.get( 2 ), corners.get( 3 ), sprite, uOffset, vOffset ); + } + + private BakedQuad createQuad( EnumFacing side, Vec3d c1, Vec3d c2, Vec3d c3, Vec3d c4, TextureAtlasSprite sprite, float uOffset, float vOffset ) + { + Vec3d normal = new Vec3d( side.getDirectionVec() ); + + // Apply the u,v shift. + // This mirrors the logic from OffsetIcon from 1.7 + float u1 = MathHelper.clamp_float( 0 - uOffset, 0, 16 ); + float u2 = MathHelper.clamp_float( 16 - uOffset, 0, 16 ); + float v1 = MathHelper.clamp_float( 0 - vOffset, 0, 16 ); + float v2 = MathHelper.clamp_float( 16 - vOffset, 0, 16 ); + + UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder( vertexFormat ); + builder.setTexture( sprite ); + putVertex( builder, normal, c1.xCoord, c1.yCoord, c1.zCoord, sprite, u1, v1 ); + putVertex( builder, normal, c2.xCoord, c2.yCoord, c2.zCoord, sprite, u1, v2 ); + putVertex( builder, normal, c3.xCoord, c3.yCoord, c3.zCoord, sprite, u2, v2 ); + putVertex( builder, normal, c4.xCoord, c4.yCoord, c4.zCoord, sprite, u2, v1 ); + return builder.build(); + } + + /* + This method is as complicated as it is, because the order in which we push data into the vertexbuffer actually has to be precisely the order + in which the vertex elements had been declared in the vertex format. + */ + private void putVertex( UnpackedBakedQuad.Builder builder, Vec3d normal, double x, double y, double z, TextureAtlasSprite sprite, float u, float v ) + { + for( int e = 0; e < vertexFormat.getElementCount(); e++ ) + { + switch( vertexFormat.getElement( e ).getUsage() ) + { + case POSITION: + builder.put( e, (float) x, (float) y, (float) z, 1.0f ); + break; + case COLOR: + builder.put( e, 1.0f, 1.0f, 1.0f, 1.0f ); + break; + case UV: + if( vertexFormat.getElement( e ).getIndex() == 0 ) + { + u = sprite.getInterpolatedU( u ); + v = sprite.getInterpolatedV( v ); + builder.put( e, u, v, 0f, 1f ); + break; + } + case NORMAL: + builder.put( e, (float) normal.xCoord, (float) normal.yCoord, (float) normal.zCoord, 0f ); + break; + default: + builder.put( e ); + break; + } + } + } + + @Override + public ItemOverrideList getOverrides() + { + return ItemOverrideList.NONE; + } + + @Override + public boolean isAmbientOcclusion() + { + return false; + } + + @Override + public boolean isGui3d() + { + return false; + } + + @Override + public boolean isBuiltInRenderer() + { + return false; + } + + @Override + public TextureAtlasSprite getParticleTexture() + { + return frameTextures[frameTextures.length - 1]; + } + + @Override + public ItemCameraTransforms getItemCameraTransforms() + { + return ItemCameraTransforms.DEFAULT; + } + + private static byte[][][] generateOffsets() + { + final Random r = new Random( 924 ); + final byte[][][] offset = new byte[10][10][10]; + + for( int x = 0; x < 10; x++ ) + { + for( int y = 0; y < 10; y++ ) + { + r.nextBytes( offset[x][y] ); + } + } + + return offset; + } +} diff --git a/src/main/java/appeng/client/render/model/GlassModel.java b/src/main/java/appeng/client/render/model/GlassModel.java new file mode 100644 index 00000000..8621a731 --- /dev/null +++ b/src/main/java/appeng/client/render/model/GlassModel.java @@ -0,0 +1,69 @@ +/* + * This file is part of Applied Energistics 2. + * Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. + * + * Applied Energistics 2 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, either version 3 of the License, or + * (at your option) any later version. + * + * Applied Energistics 2 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 Applied Energistics 2. If not, see . + */ + +package appeng.client.render.model; + + +import java.util.Collection; +import java.util.Collections; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableSet; + +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.IModel; +import net.minecraftforge.common.model.IModelState; +import net.minecraftforge.common.model.TRSRTransformation; + + +/** + * Model class for the connected texture glass model. + */ +public class GlassModel implements IModel +{ + + @Override + public Collection getDependencies() + { + return Collections.emptySet(); + } + + @Override + public Collection getTextures() + { + return ImmutableSet.builder() + .add( GlassBakedModel.TEXTURE_A, GlassBakedModel.TEXTURE_B, GlassBakedModel.TEXTURE_C, GlassBakedModel.TEXTURE_D ) + .add( GlassBakedModel.TEXTURES_FRAME ) + .build(); + } + + @Override + public IBakedModel bake( IModelState state, VertexFormat format, Function bakedTextureGetter ) + { + return new GlassBakedModel( format, bakedTextureGetter ); + } + + @Override + public IModelState getDefaultState() + { + return TRSRTransformation.identity(); + } +} diff --git a/src/main/java/appeng/client/render/model/GlassModelLoader.java b/src/main/java/appeng/client/render/model/GlassModelLoader.java new file mode 100644 index 00000000..5e1edc38 --- /dev/null +++ b/src/main/java/appeng/client/render/model/GlassModelLoader.java @@ -0,0 +1,55 @@ +/* + * This file is part of Applied Energistics 2. + * Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. + * + * Applied Energistics 2 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, either version 3 of the License, or + * (at your option) any later version. + * + * Applied Energistics 2 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 Applied Energistics 2. If not, see . + */ + +package appeng.client.render.model; + + +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.ICustomModelLoader; +import net.minecraftforge.client.model.IModel; + +import appeng.core.AppEng; + + +/** + * Model loader to manage connected texture glass. + */ +public class GlassModelLoader implements ICustomModelLoader +{ + + private static final GlassModel GLASS_MODEL = new GlassModel(); + + @Override + public boolean accepts( ResourceLocation modelLocation ) + { + return modelLocation.getResourceDomain().equals( AppEng.MOD_ID ) && "models/block/builtin/connected_glass".equals( modelLocation.getResourcePath() ); + } + + @Override + public IModel loadModel( ResourceLocation modelLocation ) throws Exception + { + return GLASS_MODEL; + } + + @Override + public void onResourceManagerReload( IResourceManager resourceManager ) + { + + } +} diff --git a/src/main/java/appeng/client/render/model/RenderHelper.java b/src/main/java/appeng/client/render/model/RenderHelper.java new file mode 100644 index 00000000..694708b7 --- /dev/null +++ b/src/main/java/appeng/client/render/model/RenderHelper.java @@ -0,0 +1,107 @@ +/* + * This file is part of Applied Energistics 2. + * Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. + * + * Applied Energistics 2 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, either version 3 of the License, or + * (at your option) any later version. + * + * Applied Energistics 2 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 Applied Energistics 2. If not, see . + */ +package appeng.client.render.model; + + +import java.util.EnumMap; +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.Vec3d; + + +final class RenderHelper +{ + + private static EnumMap> cornersForFacing = generateCornersForFacings(); + + private RenderHelper() { + + } + + static List getFaceCorners( EnumFacing side ) + { + return cornersForFacing.get( side ); + } + + private static EnumMap> generateCornersForFacings() + { + EnumMap> result = new EnumMap<>( EnumFacing.class ); + + for( EnumFacing facing : EnumFacing.values() ) + { + List corners; + + float offset = ( facing.getAxisDirection() == EnumFacing.AxisDirection.NEGATIVE ) ? 0 : 1; + + switch( facing.getAxis() ) + { + default: + case X: + corners = Lists.newArrayList( + new Vec3d( offset, 1, 1 ), + new Vec3d( offset, 0, 1 ), + new Vec3d( offset, 0, 0 ), + new Vec3d( offset, 1, 0 ) + ); + break; + case Y: + corners = Lists.newArrayList( + new Vec3d( 1, offset, 1 ), + new Vec3d( 1, offset, 0 ), + new Vec3d( 0, offset, 0 ), + new Vec3d( 0, offset, 1 ) + ); + break; + case Z: + corners = Lists.newArrayList( + new Vec3d( 0, 1, offset ), + new Vec3d( 0, 0, offset ), + new Vec3d( 1, 0, offset ), + new Vec3d( 1, 1, offset ) + ); + break; + } + + if (facing.getAxisDirection() == EnumFacing.AxisDirection.NEGATIVE) { + corners = Lists.reverse( corners ); + } + + result.put( facing, ImmutableList.copyOf( corners ) ); + } + + return result; + } + + private static Vec3d adjust( Vec3d vec, EnumFacing.Axis axis, double delta ) + { + switch( axis ) + { + default: + case X: + return new Vec3d( vec.xCoord + delta, vec.yCoord, vec.zCoord ); + case Y: + return new Vec3d( vec.xCoord, vec.yCoord + delta, vec.zCoord ); + case Z: + return new Vec3d( vec.xCoord, vec.yCoord, vec.zCoord + delta ); + } + } +} diff --git a/src/main/java/appeng/decorative/solid/GlassState.java b/src/main/java/appeng/decorative/solid/GlassState.java new file mode 100644 index 00000000..83173311 --- /dev/null +++ b/src/main/java/appeng/decorative/solid/GlassState.java @@ -0,0 +1,67 @@ +/* + * This file is part of Applied Energistics 2. + * Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. + * + * Applied Energistics 2 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, either version 3 of the License, or + * (at your option) any later version. + * + * Applied Energistics 2 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 Applied Energistics 2. If not, see . + */ +package appeng.decorative.solid; + + +import java.util.EnumSet; + +import net.minecraft.util.EnumFacing; + + +/** + * Immutable (and thus thread-safe) class that encapsulates the rendering state required for a connected texture + * glass block. + */ +public final class GlassState +{ + + private final int x; + private final int y; + private final int z; + + private final EnumSet flushWith = EnumSet.noneOf( EnumFacing.class ); + + public GlassState( int x, int y, int z, EnumSet flushWith ) + { + this.x = x; + this.y = y; + this.z = z; + this.flushWith.addAll( flushWith ); + } + + public int getX() + { + return x; + } + + public int getY() + { + return y; + } + + public int getZ() + { + return z; + } + + public boolean isFlushWith( EnumFacing side ) + { + return flushWith.contains( side ); + } + +} diff --git a/src/main/java/appeng/decorative/solid/QuartzGlassBlock.java b/src/main/java/appeng/decorative/solid/QuartzGlassBlock.java index 749338bc..d4920cdd 100644 --- a/src/main/java/appeng/decorative/solid/QuartzGlassBlock.java +++ b/src/main/java/appeng/decorative/solid/QuartzGlassBlock.java @@ -22,19 +22,29 @@ package appeng.decorative.solid; import java.util.EnumSet; import net.minecraft.block.material.Material; +import net.minecraft.block.properties.IProperty; +import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.property.ExtendedBlockState; +import net.minecraftforge.common.property.IExtendedBlockState; +import net.minecraftforge.common.property.IUnlistedProperty; import appeng.block.AEBaseBlock; +import appeng.block.IHasSpecialItemModel; import appeng.core.features.AEFeature; import appeng.helpers.AEGlassMaterial; -public class QuartzGlassBlock extends AEBaseBlock +public class QuartzGlassBlock extends AEBaseBlock implements IHasSpecialItemModel { + + // This unlisted property is used to determine the actual block that should be rendered + public static final UnlistedGlassStateProperty GLASS_STATE = new UnlistedGlassStateProperty(); + public QuartzGlassBlock() { super( Material.GLASS ); @@ -43,6 +53,40 @@ public class QuartzGlassBlock extends AEBaseBlock this.setFeature( EnumSet.of( AEFeature.DecorativeQuartzBlocks ) ); } + @Override + protected BlockStateContainer createBlockState() + { + IProperty[] listedProperties = new IProperty[0]; + IUnlistedProperty[] unlistedProperties = new IUnlistedProperty[] { GLASS_STATE }; + return new ExtendedBlockState( this, listedProperties, unlistedProperties ); + } + + @Override + public IBlockState getExtendedState( IBlockState state, IBlockAccess world, BlockPos pos ) + { + + EnumSet flushWith = EnumSet.noneOf( EnumFacing.class ); + // Test every direction for another glass block + for( EnumFacing facing : EnumFacing.values() ) + { + if( isGlassBlock( world, pos, facing ) ) + { + flushWith.add( facing ); + } + } + + GlassState glassState = new GlassState( pos.getX(), pos.getY(), pos.getZ(), flushWith ); + + IExtendedBlockState extState = (IExtendedBlockState) state; + + return extState.withProperty( GLASS_STATE, glassState ); + } + + private static boolean isGlassBlock( IBlockAccess world, BlockPos pos, EnumFacing facing ) + { + return world.getBlockState( pos.offset( facing ) ).getBlock() instanceof QuartzGlassBlock; + } + @Override public BlockRenderLayer getBlockLayer() { @@ -52,14 +96,23 @@ public class QuartzGlassBlock extends AEBaseBlock @Override public boolean shouldSideBeRendered( final IBlockState state, final IBlockAccess w, final BlockPos pos, final EnumFacing side ) { - final Material mat = w.getBlockState( pos ).getBlock().getMaterial(state); + BlockPos adjacentPos = pos.offset( side ); + + final Material mat = w.getBlockState( adjacentPos ).getBlock().getMaterial( state ); if( mat == Material.GLASS || mat == AEGlassMaterial.INSTANCE ) { - if( w.getBlockState( pos ).getBlock().getRenderType(state) == this.getRenderType(state) ) + if( w.getBlockState( adjacentPos ).getBlock().getRenderType( state ) == this.getRenderType( state ) ) { return false; } } return super.shouldSideBeRendered( state, w, pos, side ); } + + @Override + public boolean isFullCube( IBlockState state ) + { + return false; + } + } diff --git a/src/main/java/appeng/decorative/solid/UnlistedGlassStateProperty.java b/src/main/java/appeng/decorative/solid/UnlistedGlassStateProperty.java new file mode 100644 index 00000000..4d240d5b --- /dev/null +++ b/src/main/java/appeng/decorative/solid/UnlistedGlassStateProperty.java @@ -0,0 +1,54 @@ +/* + * This file is part of Applied Energistics 2. + * Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. + * + * Applied Energistics 2 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, either version 3 of the License, or + * (at your option) any later version. + * + * Applied Energistics 2 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 Applied Energistics 2. If not, see . + */ + +package appeng.decorative.solid; + + +import net.minecraftforge.common.property.IUnlistedProperty; + + +/** + * This unlisted property is used to transport the connected texture state into our model class. + */ +public class UnlistedGlassStateProperty implements IUnlistedProperty +{ + + @Override + public String getName() + { + return "glass_state"; + } + + @Override + public boolean isValid( GlassState value ) + { + return true; + } + + @Override + public Class getType() + { + return GlassState.class; + } + + @Override + public String valueToString( GlassState value ) + { + return null; + } +} diff --git a/src/main/resources/assets/appliedenergistics2/blockstates/QuartzGlassBlock.json b/src/main/resources/assets/appliedenergistics2/blockstates/QuartzGlassBlock.json index d5eea4f9..18dfe18d 100644 --- a/src/main/resources/assets/appliedenergistics2/blockstates/QuartzGlassBlock.json +++ b/src/main/resources/assets/appliedenergistics2/blockstates/QuartzGlassBlock.json @@ -1,5 +1,5 @@ { "variants": { - "normal": { "model": "appliedenergistics2:QuartzBlock" } + "normal": { "model": "appliedenergistics2:builtin/connected_glass" } } } diff --git a/src/main/resources/assets/appliedenergistics2/blockstates/QuartzLampBlock.json b/src/main/resources/assets/appliedenergistics2/blockstates/QuartzLampBlock.json new file mode 100644 index 00000000..18dfe18d --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/blockstates/QuartzLampBlock.json @@ -0,0 +1,5 @@ +{ + "variants": { + "normal": { "model": "appliedenergistics2:builtin/connected_glass" } + } +} diff --git a/src/main/resources/assets/appliedenergistics2/models/block/QuartzGlassBlock.json b/src/main/resources/assets/appliedenergistics2/models/block/QuartzGlassBlock.json deleted file mode 100644 index b783e945..00000000 --- a/src/main/resources/assets/appliedenergistics2/models/block/QuartzGlassBlock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "block/cube_all", - "textures": { - "all": "appliedenergistics2:blocks/QuartzOreBlock" - } -} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/item/QuartzGlassBlock.json b/src/main/resources/assets/appliedenergistics2/models/item/QuartzGlassBlock.json new file mode 100644 index 00000000..bdcd3444 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/models/item/QuartzGlassBlock.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "appliedenergistics2:items/BlockQuartzGlass" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/item/QuartzLampBlock.json b/src/main/resources/assets/appliedenergistics2/models/item/QuartzLampBlock.json new file mode 100644 index 00000000..bdcd3444 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/models/item/QuartzLampBlock.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "appliedenergistics2:items/BlockQuartzGlass" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassA.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassA.png new file mode 100644 index 0000000000000000000000000000000000000000..08ced73fffff852b4e77c07f73212b4b6475d9ff GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=Dh+K$tP>S|=w^P^!c=q9iy!t)x7$D3u`~F*C13&(AePq0Cs%RL{`R{j-xfP*sYj zi(`m||J_L&xf%?3SU>-_fB8h;LhX{%lbQ3b9a_Lu&A9vSvW5?5WwS>zac^5&;2QX$%3{0)5U54>S1 X)IPo8ja%{@pnVLUu6{1-oD!M!lvI6;>1s;*b z3=Dh+L6~vJ#O${~L8%hgh?3y^w370~qEv=}#LT=BJwMkFg)(D3Q$0gN_s>q|KvhYe zE{-7<{%0o|@--On9QpMB{zoRYeFttV;8CdB5zZ;5Q@N_fS?a%%v32J)DSMI4jitAb z7d~X078$dnG5m!>=0XS8bKb!V>~_=(vu3r&&0_l6w6Bxts#9auLWivZ3+hxJG5GY@ VOxk@Svk+(-gQu&X%Q~loCIF(PO;i8? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassC.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassC.png new file mode 100644 index 0000000000000000000000000000000000000000..640b0beac5d31ba6f604d984df6b9d413417037d GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=Dh+L6~vJ#O${~L8%hgh?3y^w370~qEv=}#LT=BJwMkFg)(D3Q$0gN_s>q|Kve~v zE{-7<{=GepTn!F9NB;a*xBbc5A3bxEw&U^~=A9-!{d$5Qe>G2>^lF|#P|#grH?LLI zhdew>{UtJ`&8Nj5llZq<+B>MPRr>VN%DZ19c5D>MezVIbX2Oxuo&CbspW6AwO#f|B k7`v@7`R1`+zopr0IL{Sk^lez literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassD.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassD.png new file mode 100644 index 0000000000000000000000000000000000000000..7844580746086a86b8901d0f3c8dc0a98a711481 GIT binary patch literal 243 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=Dh+L6~vJ#O${~L8%hgh?3y^w370~qEv=}#LT=BJwMkFg)(D3Q$0gN_s>q|Kvnsk zE{-7<{%gAravm_?Vcz_|Om>m>7fJJlCvNmzd3Lc`xuEaX`WZJDy)sy6w}DUi74vHd zL+9H)_o(&{Q!VG|OFNw`jH^p^esM(N_~eS!R<8o8uLic?THR-LCGKxa@1p1pig%iL gAByGt$au?k{mbD+{Fj_cfmSnky85}Sb4q9e0CW{v2mk;8 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0001.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0001.png new file mode 100644 index 0000000000000000000000000000000000000000..0096ebbb4eb6802c18d97e694de56ddb697e4130 GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5XEInNuLn>}1T?w1~|NOy&#~7G(&iL@WcyRuHeZ*1wx_`$G x{P_RBp3RFvn7K9KN<$#C8}EWij0}uy3_Yj0T4GZ!T>=`y;OXk;vd$@?2>^8qGtK}2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0010.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0010.png new file mode 100644 index 0000000000000000000000000000000000000000..18e178931bce3061d1be3611206de93a28daa0a0 GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X{5)M8Ln>}1{rLaio_S}4v+Fl|VP@8b+1<^JO3X7PB{hs2 zCU$ljG5`DX*L^0V&KZ$i5B}S8#eVp1f0&_~k%i4nOrz}Jf#oi%Sd<(Z7#SSJZOXkY S_df=j%;4$j=d#Wzp$Pyaj5t96 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0011.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0011.png new file mode 100644 index 0000000000000000000000000000000000000000..4c959e13ebc57b39283107d6f4ecb82486f64851 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X5}1T?w1~|NOy&#~7G(&iL@WcyRuHeZ*1wx_`$G zeE9#re$&Q{^Ip~aBzrQP>EYoKkvwqXh|5gI1sfKgUQXU|?p*S989n;d2tDnm{r-UW|nh;2N literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0100.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0100.png new file mode 100644 index 0000000000000000000000000000000000000000..8c28e98e7f122f9bfdd445cdfc871ba93ff9c394 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5XJUv|;Ln>}1{rUgjo>{e_v(d>Q>%a=e#cTm58N_l;cmB7D zkx7{R&&Z&Ob*ALM=9@k~0{{Nk|9>F$kNN0-rk!UTc>g!JGCDLcGMw@kSU&lFWk1kR N22WQ%mvv4FO#qp>I;a2u literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0101.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0101.png new file mode 100644 index 0000000000000000000000000000000000000000..c70506ed0ad6cc8d601cdb81678f200381b11350 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xl001;Ln>}1T?w1~|NOy&#~7G(&iL@WcyRuHeZ*1wx_`$G z{P_RBp3RFvn7K9KN<$#C8*jt2xLnhn|7~Jq5+?sMGH7C*DfzGYrjL)nzyJ0BA4vUU oKH9i*Hsh4t{~3#o92yuIJ~v44rMH9#18rmQboFyt=akR{0A$Qaga7~l literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0110.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0110.png new file mode 100644 index 0000000000000000000000000000000000000000..0a07653a56c2ad9cca0ad0461f34bc746046768d GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xay?xfLn>|^33lXaFyQgF=3i9j=&#iD|Nq?RHNiCvmTLku zY+JT?ItbNQ$ERDhNVUreIT&RyJX^;&XJ-aOtdQh}4j!Y6KU#L*TBTr|@&3rFBO7(+ z+zUy);mo^c^X}TVpJ#-B|B!WZoYL_{^#H@Xm+o9F2dfo<7BhId`njxgN@xNAHE~HD literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0111.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame0111.png new file mode 100644 index 0000000000000000000000000000000000000000..bc2a7120bae3ef935b18deefe45cc08682a216aa GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X+B{txLn>}1T?w1~|NOy&#~7G(&iL@WcyRuHeZ*1wx_`$G zeE9#re$&Q{^Ip~aBzrQP>EYoKkvwqXh|5gI1sfKgULb76xx59CrSeH*jZS bkzhFU!>{mk}1T?m`}pPz;2Ns^je9v_<*!{z<;|22&pIy)yC zG5`DX*L^0V&KaL6k{|xdx9TONEV{tTBf@lwSE83yi{;UC{reh53F Q2{f0%)78&qol`;+0FIb9lK=n! literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1001.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1001.png new file mode 100644 index 0000000000000000000000000000000000000000..6c7a463db10e76042823e97b5fc39205c4c1095f GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xl001;Ln>}1T?w1~|NOy&#~7G(&iL@WcyRuHeZ*1wx_`$G z96EgVV8Nq1yl!kpjF!0&yWB8PT~eefiIZYxEP|^33B9WFyMJ@#DDlF>qjM}AOELo&Wm|&^?~{2 zL5F_MOd-o{OU*cne_Mt7SaNpTs5NFSWla)b6v${~;Fz~)OGBZd%LS%muA%oD3lr-% zXz13@`@2`c@6T|^nY59s!GOo*a`2J`{~tVi^x)C|^M2?4wS`z^ zW(U7e;+w>?Z(~8`JH0fSUm3a1t-F|PE!Thewa?nW^m}1T?m`}pPz;2Ns^je9v_<*!{z<;|22&pIy)yC zG5`DX*L^0V&KaL6k{|xdx9TONEV{tTBf@lwSE85o6!XNVpQq>ZJY&oH@2K`Swc!bO yTHF5wGoASg)t~JHWJKOASn!+u%sB=|Hiq?&eV^|zK5-XlFN3G6pUXO@geCx7JxMnJ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1101.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1101.png new file mode 100644 index 0000000000000000000000000000000000000000..67511a5abac0e559e9972455b612e9842052270e GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X8a-VcLn>~)nQX|_V8G*Ae_4rjZ*#P`xcU42mX_7LfmWG| zLRkdG&%T=N)aL%l*+?v@4cd=~mLHCZx1&tj&eiOb0bIvXvlcOVs6{GFe6W3njzA3G%uNmj zFPD`I#I*5?E`7FsGe7r>BRhjLWWV?<%uPBka!c)7o5h}c@;R>`Ee!dvyPGHf|6{*@ mxm9c3-wDpWI{6-}1Vf~7cty*J6Ni9~WAJqKb6Mw<&;$Ux0bW7? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1111.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/glass/BlockQuartzGlassFrame1111.png new file mode 100644 index 0000000000000000000000000000000000000000..1b44a2e81d2114f9379f8a010c47225a791e7e8f GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5XW_h|ehE&`-5`2*Bkb#KzWyRmz{+F8H6+()arDFWi8i4C*$M7f4 zhlVv#nNKc(h>AJSE2aEdxkGBQg4^A2F_B(`2q^ke@@BPEV