Package rakama.worldtools.light

Source Code of rakama.worldtools.light.ChunkRelighter

/*
* Copyright (c) 2012, RamsesA <ramsesakama@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/

package rakama.worldtools.light;

import rakama.worldtools.data.Chunk;
import rakama.worldtools.light.LightCache.Mode;
import rakama.worldtools.util.CircularBuffer;

public class ChunkRelighter
{
    public static final int min_span = 3;
    public static final int max_span = 34;

    protected CircularBuffer queue;
    protected LightCache cache;
    protected TempChunk[] tempChunk;

    protected final int span, width, length, height;

    public ChunkRelighter()
    {
        this(3);
    }
   
    public ChunkRelighter(int span)
    {
        if(span < min_span || span > max_span)
            throw new IllegalArgumentException("span value out of range");

        this.span = span;
        width = span * Chunk.width;
        length = span * Chunk.length;
        height = Chunk.height;

        queue = new CircularBuffer(width * length * height);
        cache = new LightCache(span, span);
        tempChunk = new TempChunk[span * span];

        for(int z = 0; z < span; z++)
            for(int x = 0; x < span; x++)
                if(isImmutable(x, z))
                    tempChunk[x + z * span] = new TempChunk();
    }

    public int getSpan()
    {
        return span;
    }

    public void lightChunks(Chunk[] localChunks)
    {
        if(localChunks.length != span * span)
            throw new IllegalArgumentException("expected array of size " + span * span);

        fillLightCache(localChunks);

        // compute block lights
        queue.clear();
        cache.setMode(Mode.BLOCKLIGHT);
        cache.clearBlockLights();
        cache.enqueueBlockLights(queue);
        propagateLights();

        // compute sky lights
        queue.clear();
        cache.setMode(Mode.SKYLIGHT);
        cache.clearSkyLights();
        cache.enqueueSkyLights(queue);
        propagateLights();
       
        cache.clear();
        clearTemp();
    }

    protected void fillLightCache(Chunk[] localChunks)
    {
        for(int z = 0; z < span; z++)
            for(int x = 0; x < span; x++)
                setChunk(x, z, localChunks[x + z * span]);
    }
   
    private void setChunk(int x, int z, Chunk chunk)
    {
        if(chunk == null)
        {
            cache.setChunk(x, z, null);
            return;
        }
       
        if(isImmutable(x, z))
            chunk = getTempChunk(x, z, chunk);

        chunk.trimSections();       
        chunk.recomputeHeightmap();                 
           
        cache.setChunk(x, z, chunk);  
    }
   
    protected void propagateLights()
    {
        int[] pos = new int[3];

        // perform wavefront propagation
        while(!queue.isEmpty())
        {
            int index = queue.poll();
            byte light = unpack(index, pos);
            int x = pos[0];
            int y = pos[1];
            int z = pos[2];

            light--;
           
            propagateLight(x, y + 1, z, light);
            propagateLight(x, y - 1, z, light);
            propagateLight(x - 1, y, z, light);
            propagateLight(x + 1, y, z, light);
            propagateLight(x, y, z + 1, light);
            propagateLight(x, y, z - 1, light);
        }
    }

    private void propagateLight(int x, int y, int z, byte light)
    {
        // skip if x/y/z is out of bounds
        if(x < 0 || x >= width || y < 0 || y >= height || z < 0 || z >= length)
            return;
       
        int diffusion = cache.getBlockDiffusion(x, y, z);
       
        if(diffusion > 0)
        {
            light -= diffusion - 1;
            if(light < 1)
                return;           
        }
           
        if(setLight(x, y, z, light))
            queue.push(pack(x, y, z, light));
    }

    private boolean setLight(int x, int y, int z, byte newLight)
    {
        // get previous light value
        int prevLight = cache.getLight(x, y, z);

        // return false if block has higher light value or if block is opaque
        if(newLight <= prevLight || cache.isOpaque(x, y, z))
            return false;
       
        // update with new light value
        cache.setLight(x, y, z, newLight);

        return true;
    }

    private TempChunk getTempChunk(int x, int z, Chunk chunk)
    {
        if(chunk == null)
            return null;
       
        TempChunk p = tempChunk[x + z * span];
        p.assignData(chunk);
        return p;
    }
   
    private void clearTemp()
    {
        for(int z = 0; z < span; z++)
            for(int x = 0; x < span; x++)
                if(isImmutable(x, z))
                    tempChunk[x + z * span].clear();
    }
   
    private boolean isImmutable(int x, int z)
    {
        return z <= 0 || z >= span - 1 || x <= 0 || x >= span - 1;
    }

    protected static int pack(int x, int y, int z, byte light)
    {
        // max x/z = 1023
        // max y = 255
        // max light = 15

        x = x << 22;
        z = z << 12;
        y = y << 4;
        return x | y | z | light;
    }

    protected static byte unpack(int i, int[] coordinates)
    {
        coordinates[0] = (i >> 22) & 0x3FF;
        coordinates[1] = (i >> 4) & 0xFF;
        coordinates[2] = (i >> 12) & 0x3FF;
        return (byte) (i & 0xF);
    }
}
TOP

Related Classes of rakama.worldtools.light.ChunkRelighter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.