Search in sources :

Example 1 with Chunk

use of org.pepsoft.minecraft.Chunk in project WorldPainter by Captain-Chaos.

the class LayerPreviewCreator method renderPreview.

public MinecraftWorldObject renderPreview() {
    // Phase one: setup
    long timestamp = System.currentTimeMillis();
    long seed = 0L;
    TileFactory tileFactory = subterranean ? TileFactoryFactory.createNoiseTileFactory(seed, Terrain.BARE_GRASS, previewHeight, 56, 62, false, true, 20f, 0.5) : TileFactoryFactory.createNoiseTileFactory(seed, Terrain.BARE_GRASS, previewHeight, 8, 14, false, true, 20f, 0.5);
    Dimension dimension = new Dimension(seed, tileFactory, DIM_NORMAL, previewHeight);
    dimension.setSubsurfaceMaterial(Terrain.STONE);
    MinecraftWorldObject minecraftWorldObject = new MinecraftWorldObject(layer.getName() + " Preview", new Box(-8, 136, -8, 136, 0, previewHeight), previewHeight, null, new Point3i(-64, -64, 0));
    long now = System.currentTimeMillis();
    if (logger.isDebugEnabled()) {
        logger.debug("Creating data structures took " + (now - timestamp) + " ms");
    }
    // Phase two: apply layer to dimension
    timestamp = now;
    Tile tile = tileFactory.createTile(0, 0);
    switch(layer.getDataSize()) {
        case BIT:
            Random random = new Random(seed);
            for (int x = 0; x < 128; x++) {
                for (int y = 0; y < 128; y++) {
                    if (random.nextFloat() < pattern.getStrength(x, y)) {
                        tile.setBitLayerValue(layer, x, y, true);
                    }
                }
            }
            break;
        case BIT_PER_CHUNK:
            random = new Random(seed);
            for (int x = 0; x < 128; x += 16) {
                for (int y = 0; y < 128; y += 16) {
                    if (random.nextFloat() < pattern.getStrength(x, y)) {
                        tile.setBitLayerValue(layer, x, y, true);
                    }
                }
            }
            break;
        case BYTE:
            for (int x = 0; x < 128; x++) {
                for (int y = 0; y < 128; y++) {
                    tile.setLayerValue(layer, x, y, Math.min((int) (pattern.getStrength(x, y) * 256), 255));
                }
            }
            break;
        case NIBBLE:
            // any
            if (layer instanceof CombinedLayer) {
                final Terrain terrain = ((CombinedLayer) layer).getTerrain();
                final int biome = ((CombinedLayer) layer).getBiome();
                final boolean terrainConfigured = terrain != null;
                final boolean biomeConfigured = biome != -1;
                for (int x = 0; x < 128; x++) {
                    for (int y = 0; y < 128; y++) {
                        float strength = pattern.getStrength(x, y);
                        tile.setLayerValue(layer, x, y, Math.min((int) (strength * 16), 15));
                        // Double the strength so that 50% intensity results
                        // in full coverage for terrain and biome, which is
                        // inaccurate but probably more closely resembles
                        // practical usage
                        strength = Math.min(strength * 2, 1.0f);
                        if (terrainConfigured && ((strength > 0.95f) || (Math.random() < strength))) {
                            tile.setTerrain(x, y, terrain);
                        }
                        if (biomeConfigured && ((strength > 0.95f) || (Math.random() < strength))) {
                            tile.setLayerValue(Biome.INSTANCE, x, y, biome);
                        }
                    }
                }
            } else {
                for (int x = 0; x < 128; x++) {
                    for (int y = 0; y < 128; y++) {
                        tile.setLayerValue(layer, x, y, Math.min((int) (pattern.getStrength(x, y) * 16), 15));
                    }
                }
            }
            break;
        default:
            throw new IllegalArgumentException("Unsupported data size " + layer.getDataSize() + " encountered");
    }
    // If the layer is a combined layer, apply it recursively and collect
    // the added layers
    List<Layer> layers;
    if (layer instanceof CombinedLayer) {
        layers = new ArrayList<>();
        layers.add(layer);
        while (true) {
            List<Layer> addedLayers = new ArrayList<>();
            for (Iterator<Layer> i = layers.iterator(); i.hasNext(); ) {
                Layer tmpLayer = i.next();
                if (tmpLayer instanceof CombinedLayer) {
                    i.remove();
                    addedLayers.addAll(((CombinedLayer) tmpLayer).apply(tile));
                }
            }
            if (!addedLayers.isEmpty()) {
                layers.addAll(addedLayers);
            } else {
                break;
            }
        }
    } else {
        layers = Collections.singletonList(layer);
    }
    dimension.addTile(tile);
    now = System.currentTimeMillis();
    if (logger.isDebugEnabled()) {
        logger.debug("Applying layer(s) took " + (now - timestamp) + " ms");
    }
    // Collect the exporters (could be multiple if the layer was a combined
    // layer)
    Map<Layer, LayerExporter> pass1Exporters = new HashMap<>();
    Map<Layer, SecondPassLayerExporter> pass2Exporters = new HashMap<>();
    for (Layer tmpLayer : layers) {
        LayerExporter exporter = tmpLayer.getExporter();
        if (tmpLayer.equals(layer)) {
            exporter.setSettings(settings);
        }
        if (exporter instanceof FirstPassLayerExporter) {
            pass1Exporters.put(layer, exporter);
        }
        if (exporter instanceof SecondPassLayerExporter) {
            pass2Exporters.put(layer, (SecondPassLayerExporter) exporter);
        }
    }
    // Phase three: generate terrain and render first pass layers, if any
    timestamp = now;
    WorldPainterChunkFactory chunkFactory = new WorldPainterChunkFactory(dimension, pass1Exporters, DefaultPlugin.JAVA_ANVIL, previewHeight);
    for (int x = 0; x < 8; x++) {
        for (int y = 0; y < 8; y++) {
            Chunk chunk = chunkFactory.createChunk(x, y).chunk;
            minecraftWorldObject.addChunk(chunk);
        }
    }
    now = System.currentTimeMillis();
    if (logger.isDebugEnabled()) {
        logger.debug("Generating terrain and rendering first pass layer(s) (if any) took " + (now - timestamp) + " ms");
    }
    if (!pass2Exporters.isEmpty()) {
        // Phase four: render the second pass layers, if any
        timestamp = now;
        Rectangle area = new Rectangle(128, 128);
        for (SecondPassLayerExporter exporter : pass2Exporters.values()) {
            exporter.render(dimension, area, area, minecraftWorldObject);
        }
        now = System.currentTimeMillis();
        if (logger.isDebugEnabled()) {
            logger.debug("Rendering second pass layer(s) took " + (now - timestamp) + " ms");
        }
    }
    // Final phase: post processing
    timestamp = now;
    now = System.currentTimeMillis();
    try {
        new JavaPostProcessor().postProcess(minecraftWorldObject, new Rectangle(-8, -8, 136, 136), null);
    } catch (ProgressReceiver.OperationCancelled e) {
        // Can't happen since we didn't pass in a progress receiver
        throw new InternalError();
    }
    if (logger.isDebugEnabled()) {
        logger.debug("Post processing took " + (now - timestamp) + " ms");
    }
    return minecraftWorldObject;
}
Also used : Point3i(javax.vecmath.Point3i) MinecraftWorldObject(org.pepsoft.worldpainter.objects.MinecraftWorldObject) Box(org.pepsoft.util.Box) Dimension(org.pepsoft.worldpainter.Dimension) Chunk(org.pepsoft.minecraft.Chunk) TunnelLayer(org.pepsoft.worldpainter.layers.tunnel.TunnelLayer) UndergroundPocketsLayer(org.pepsoft.worldpainter.layers.pockets.UndergroundPocketsLayer) ProgressReceiver(org.pepsoft.util.ProgressReceiver)

Example 2 with Chunk

use of org.pepsoft.minecraft.Chunk in project WorldPainter by Captain-Chaos.

the class LightingCalculator method recalculatePrimaryLight.

public void recalculatePrimaryLight() {
    for (int x = dirtyArea.getX1(); x <= dirtyArea.getX2(); x++) {
        for (int z = dirtyArea.getZ1(); z <= dirtyArea.getZ2(); z++) {
            Chunk chunk = world.getChunkForEditing(x >> 4, z >> 4);
            if (chunk == null) {
                continue;
            }
            boolean daylight = (dirtyArea.getY2() >= (world.getMaxHeight() - 1)) ? true : (world.getSkyLightLevel(x, z, dirtyArea.getY2() + 1) == 15);
            for (int y = dirtyArea.getY2(); y >= dirtyArea.getY1(); y--) {
                int blockType = chunk.getBlockType(x & 0xf, y, z & 0xf);
                int blockLightLevel = chunk.getBlockLightLevel(x & 0xf, y, z & 0xf);
                int skyLightLevel = chunk.getSkyLightLevel(x & 0xf, y, z & 0xf);
                int newBlockLightLevel, newSkyLightLevel;
                if ((blockType > HIGHEST_KNOWN_BLOCK_ID) || (BLOCK_TRANSPARENCY[blockType] < 15)) {
                    // Transparent block, or unknown block. We err on the
                    // side of transparency for unknown blocks to try and
                    // cause less visible lighting bugs
                    int transparency = (blockType > HIGHEST_KNOWN_BLOCK_ID) ? 0 : BLOCK_TRANSPARENCY[blockType];
                    if ((transparency == 0) && daylight) {
                        // Propagate daylight down
                        newSkyLightLevel = 15;
                    } else {
                        newSkyLightLevel = 0;
                        daylight = false;
                    }
                } else {
                    newSkyLightLevel = 0;
                    daylight = false;
                }
                if ((blockType <= HIGHEST_KNOWN_BLOCK_ID) && (LIGHT_SOURCES[blockType] > 0)) {
                    newBlockLightLevel = LIGHT_SOURCES[blockType];
                } else {
                    newBlockLightLevel = 0;
                }
                if (newBlockLightLevel != blockLightLevel) {
                    chunk.setBlockLightLevel(x & 0xf, y, z & 0xf, newBlockLightLevel);
                }
                if (newSkyLightLevel != skyLightLevel) {
                    chunk.setSkyLightLevel(x & 0xf, y, z & 0xf, newSkyLightLevel);
                }
            }
        }
    }
}
Also used : Chunk(org.pepsoft.minecraft.Chunk)

Example 3 with Chunk

use of org.pepsoft.minecraft.Chunk in project WorldPainter by Captain-Chaos.

the class LightingCalculator method calculateSecondaryLight.

/**
 * For the selected chunk and the chunks around it, calculate the secondary
 * light, if necessary. The dirty area is constricted to the blocks that
 * were actually changed, and <code>false</code> is returned if no changes
 * were made at all (indicating that lighting is complete).
 */
public boolean calculateSecondaryLight() {
    int lowestY = Integer.MAX_VALUE, highestY = Integer.MIN_VALUE;
    boolean changed = false;
    for (int x = dirtyArea.getX1(); x <= dirtyArea.getX2(); x++) {
        for (int z = dirtyArea.getZ1(); z <= dirtyArea.getZ2(); z++) {
            Chunk chunk = world.getChunk(x >> 4, z >> 4);
            if (chunk == null) {
                continue;
            }
            for (int y = dirtyArea.getY1(); y <= dirtyArea.getY2(); y++) {
                int blockType = world.getBlockTypeAt(x, z, y);
                int currentSkylightLevel = world.getSkyLightLevel(x, z, y);
                int currentBlockLightLevel = world.getBlockLightLevel(x, z, y);
                int newSkyLightLevel;
                int newBlockLightLevel;
                if ((blockType <= HIGHEST_KNOWN_BLOCK_ID) && (BLOCK_TRANSPARENCY[blockType] == 15)) {
                    // Opaque block
                    newSkyLightLevel = 0;
                    newBlockLightLevel = (LIGHT_SOURCES[blockType] > 0) ? currentBlockLightLevel : 0;
                } else {
                    // Transparent block, or unknown block. We err on the
                    // side of transparency for unknown blocks to try and
                    // cause less visible lighting bugs
                    newSkyLightLevel = (currentSkylightLevel < 15) ? calculateSkyLightLevel(x, y, z) : 15;
                    newBlockLightLevel = ((blockType <= HIGHEST_KNOWN_BLOCK_ID) && (LIGHT_SOURCES[blockType] > 0)) ? currentBlockLightLevel : calculateBlockLightLevel(x, y, z);
                }
                if ((newSkyLightLevel != currentSkylightLevel) || (newBlockLightLevel != currentBlockLightLevel)) {
                    if (newSkyLightLevel != currentSkylightLevel) {
                        world.setSkyLightLevel(x, z, y, newSkyLightLevel);
                    }
                    if (newBlockLightLevel != currentBlockLightLevel) {
                        world.setBlockLightLevel(x, z, y, newBlockLightLevel);
                    }
                    changed = true;
                    if (y - 1 < lowestY) {
                        lowestY = y - 1;
                    }
                    if (y + 1 > highestY) {
                        highestY = y + 1;
                    }
                }
            }
        }
    }
    if (changed) {
        dirtyArea.setY1(Math.max(lowestY, 0));
        dirtyArea.setY2(Math.min(highestY, maxHeight - 1));
    }
    return changed;
}
Also used : Chunk(org.pepsoft.minecraft.Chunk)

Aggregations

Chunk (org.pepsoft.minecraft.Chunk)3 Point3i (javax.vecmath.Point3i)1 Box (org.pepsoft.util.Box)1 ProgressReceiver (org.pepsoft.util.ProgressReceiver)1 Dimension (org.pepsoft.worldpainter.Dimension)1 UndergroundPocketsLayer (org.pepsoft.worldpainter.layers.pockets.UndergroundPocketsLayer)1 TunnelLayer (org.pepsoft.worldpainter.layers.tunnel.TunnelLayer)1 MinecraftWorldObject (org.pepsoft.worldpainter.objects.MinecraftWorldObject)1