use of org.terasology.world.block.BlockAppearance in project Terasology by MovingBlocks.
the class BlockDamageAuthoritySystem method createBlockParticleEffect.
/**
* Creates a new entity for the block damage particle effect.
*
* If the terrain texture of the damaged block is available, the particles will have the block texture. Otherwise,
* the default sprite (smoke) is used.
*
* @param family the {@link BlockFamily} of the damaged block
* @param location the location of the damaged block
*/
private void createBlockParticleEffect(BlockFamily family, Vector3f location) {
EntityBuilder builder = entityManager.newBuilder("core:defaultBlockParticles");
builder.getComponent(LocationComponent.class).setWorldPosition(location);
Optional<Texture> terrainTexture = Assets.getTexture("engine:terrain");
if (terrainTexture.isPresent() && terrainTexture.get().isLoaded()) {
final BlockAppearance blockAppearance = family.getArchetypeBlock().getPrimaryAppearance();
final float relativeTileSize = worldAtlas.getRelativeTileSize();
final float particleScale = 0.25f;
final float spriteSize = relativeTileSize * particleScale;
ParticleDataSpriteComponent spriteComponent = builder.getComponent(ParticleDataSpriteComponent.class);
spriteComponent.texture = terrainTexture.get();
spriteComponent.textureSize.set(spriteSize, spriteSize);
final List<Vector2f> offsets = computeOffsets(blockAppearance, particleScale);
TextureOffsetGeneratorComponent textureOffsetGeneratorComponent = builder.getComponent(TextureOffsetGeneratorComponent.class);
textureOffsetGeneratorComponent.validOffsets.addAll(offsets);
}
builder.build();
}
use of org.terasology.world.block.BlockAppearance in project Terasology by MovingBlocks.
the class BlockBuilder method createAppearance.
private BlockAppearance createAppearance(BlockShape shape, Map<BlockPart, BlockTile> tiles, Rotation rot) {
Map<BlockPart, BlockMeshPart> meshParts = Maps.newEnumMap(BlockPart.class);
Map<BlockPart, Vector2f> textureAtlasPositions = Maps.newEnumMap(BlockPart.class);
for (BlockPart part : BlockPart.values()) {
// TODO: Need to be more sensible with the texture atlas. Because things like block particles read from a part that may not exist, we're being fairly lenient
Vector2f atlasPos;
if (tiles.get(part) == null) {
atlasPos = new Vector2f();
} else {
atlasPos = worldAtlas.getTexCoords(tiles.get(part), shape.getMeshPart(part) != null);
}
BlockPart targetPart = part.rotate(rot);
textureAtlasPositions.put(targetPart, atlasPos);
if (shape.getMeshPart(part) != null) {
meshParts.put(targetPart, shape.getMeshPart(part).rotate(rot.getQuat4f()).mapTexCoords(atlasPos, worldAtlas.getRelativeTileSize()));
}
}
return new BlockAppearance(meshParts, textureAtlasPositions);
}
use of org.terasology.world.block.BlockAppearance in project Terasology by MovingBlocks.
the class BlockMeshGeneratorSingleShape method generateChunkMesh.
@Override
public void generateChunkMesh(ChunkView view, ChunkMesh chunkMesh, int x, int y, int z) {
Biome selfBiome = view.getBiome(x, y, z);
Block selfBlock = view.getBlock(x, y, z);
// TODO: Needs review - too much hardcoded special cases and corner cases resulting from this.
ChunkVertexFlag vertexFlag = ChunkVertexFlag.NORMAL;
if (selfBlock.isWater()) {
if (view.getBlock(x, y + 1, z).isWater()) {
vertexFlag = ChunkVertexFlag.WATER;
} else {
vertexFlag = ChunkVertexFlag.WATER_SURFACE;
}
} else if (selfBlock.isLava()) {
vertexFlag = ChunkVertexFlag.LAVA;
} else if (selfBlock.isWaving() && selfBlock.isDoubleSided()) {
vertexFlag = ChunkVertexFlag.WAVING;
} else if (selfBlock.isWaving()) {
vertexFlag = ChunkVertexFlag.WAVING_BLOCK;
}
// Gather adjacent blocks
Map<Side, Block> adjacentBlocks = Maps.newEnumMap(Side.class);
for (Side side : Side.values()) {
Vector3i offset = side.getVector3i();
Block blockToCheck = view.getBlock(x + offset.x, y + offset.y, z + offset.z);
adjacentBlocks.put(side, blockToCheck);
}
BlockAppearance blockAppearance = selfBlock.getAppearance(adjacentBlocks);
/*
* Determine the render process.
*/
ChunkMesh.RenderType renderType = ChunkMesh.RenderType.TRANSLUCENT;
if (!selfBlock.isTranslucent()) {
renderType = ChunkMesh.RenderType.OPAQUE;
}
// TODO: Review special case, or alternatively compare uris.
if (selfBlock.isWater() || selfBlock.isIce()) {
renderType = ChunkMesh.RenderType.WATER_AND_ICE;
}
if (selfBlock.isDoubleSided()) {
renderType = ChunkMesh.RenderType.BILLBOARD;
}
if (blockAppearance.getPart(BlockPart.CENTER) != null) {
Vector4f colorOffset = selfBlock.calcColorOffsetFor(BlockPart.CENTER, selfBiome);
blockAppearance.getPart(BlockPart.CENTER).appendTo(chunkMesh, x, y, z, colorOffset, renderType, vertexFlag);
}
boolean[] drawDir = new boolean[6];
for (Side side : Side.values()) {
drawDir[side.ordinal()] = blockAppearance.getPart(BlockPart.fromSide(side)) != null && isSideVisibleForBlockTypes(adjacentBlocks.get(side), selfBlock, side);
}
// If the selfBlock is lowered, some more faces may have to be drawn
if (selfBlock.isLiquid()) {
Block bottomBlock = adjacentBlocks.get(Side.BOTTOM);
// Draw horizontal sides if visible from below
for (Side side : Side.horizontalSides()) {
Vector3i offset = side.getVector3i();
Block adjacentBelow = view.getBlock(x + offset.x, y - 1, z + offset.z);
Block adjacent = adjacentBlocks.get(side);
boolean visible = (blockAppearance.getPart(BlockPart.fromSide(side)) != null && isSideVisibleForBlockTypes(adjacentBelow, selfBlock, side) && !isSideVisibleForBlockTypes(bottomBlock, adjacent, side.reverse()));
drawDir[side.ordinal()] |= visible;
}
// Draw the top if below a non-lowered selfBlock
// TODO: Don't need to render the top if each side and the selfBlock above each side are either liquid or opaque solids.
Block blockToCheck = adjacentBlocks.get(Side.TOP);
drawDir[Side.TOP.ordinal()] |= !blockToCheck.isLiquid();
if (bottomBlock.isLiquid() || bottomBlock.getMeshGenerator() == null) {
for (Side dir : Side.values()) {
if (drawDir[dir.ordinal()]) {
Vector4f colorOffset = selfBlock.calcColorOffsetFor(BlockPart.fromSide(dir), selfBiome);
selfBlock.getLoweredLiquidMesh(dir).appendTo(chunkMesh, x, y, z, colorOffset, renderType, vertexFlag);
}
}
return;
}
}
for (Side dir : Side.values()) {
if (drawDir[dir.ordinal()]) {
Vector4f colorOffset = selfBlock.calcColorOffsetFor(BlockPart.fromSide(dir), selfBiome);
// TODO: Needs review since the new per-vertex flags introduce a lot of special scenarios - probably a per-side setting?
if (selfBlock.isGrass() && dir != Side.TOP && dir != Side.BOTTOM) {
blockAppearance.getPart(BlockPart.fromSide(dir)).appendTo(chunkMesh, x, y, z, colorOffset, renderType, ChunkVertexFlag.COLOR_MASK);
} else {
if (blockAppearance.getPart(BlockPart.fromSide(dir)) == null) {
// TODO: This would catch something like water blocks attempting to render with a "fixed" trimmedLoweredCube shape
// That shape has its top trimmed down a bit to let water sit slightly lower than land, however, underwater this shouldn't show
// Normally we would configure that shape with CENTER instead of TOP, that way the trimmed part wouldn't occlude in a stack
// But with that handling you don't get water blocks occluding tops underwater... and there's no TOP to retrieve below -> NPE
logger.debug("Cannot render side '{}' for a block - no stored block appearance for it. renderType {}, vertexFlag {}", dir, renderType, vertexFlag);
} else {
blockAppearance.getPart(BlockPart.fromSide(dir)).appendTo(chunkMesh, x, y, z, colorOffset, renderType, vertexFlag);
}
}
}
}
}
Aggregations