All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.llbit.chunky.map.BlockLayer Maven / Gradle / Ivy

There is a newer version: 1.4.5
Show newest version
/* Copyright (c) 2014 Jesper Öqvist 
 *
 * This file is part of Chunky.
 *
 * Chunky is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Chunky 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 General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with Chunky.  If not, see .
 */
package se.llbit.chunky.map;

import org.apache.commons.math3.util.FastMath;
import se.llbit.chunky.renderer.scene.Scene;
import se.llbit.chunky.resources.Texture;
import se.llbit.chunky.world.Biomes;
import se.llbit.chunky.world.Block;
import se.llbit.chunky.world.Chunk;
import se.llbit.math.ColorUtil;

/**
 * A layer with block data.
 *
 * @author Jesper Öqvist 
 */
public class BlockLayer extends AbstractLayer {
  private final byte[] blocks;
  private final byte[] biomes;
  private final int avgColor;

  /**
   * Load layer from block data.
   */
  public BlockLayer(byte[] blockData, byte[] chunkBiomes, int layer) {
    blocks = new byte[Chunk.X_MAX * Chunk.Z_MAX];
    biomes = new byte[Chunk.X_MAX * Chunk.Z_MAX];
    double[] sum = new double[3];
    double[] rgb = new double[3];
    for (int x = 0; x < Chunk.X_MAX; ++x) {
      for (int z = 0; z < Chunk.Z_MAX; ++z) {
        byte block = blockData[Chunk.chunkIndex(x, layer, z)];
        byte biome = chunkBiomes[Chunk.chunkXZIndex(x, z)];
        blocks[x * Chunk.Z_MAX + z] = block;
        biomes[x * Chunk.Z_MAX + z] = block;
        ColorUtil.getRGBComponents(avgBlockColor(block, biome), rgb);
        sum[0] += rgb[0];
        sum[1] += rgb[1];
        sum[2] += rgb[2];
      }
    }
    sum[0] /= Chunk.X_MAX * Chunk.Z_MAX;
    sum[1] /= Chunk.X_MAX * Chunk.Z_MAX;
    sum[2] /= Chunk.X_MAX * Chunk.Z_MAX;
    avgColor = ColorUtil.getRGB(sum);
  }

  /**
   * Render this layer
   */
  @Override public synchronized void render(MapTile tile) {
    if (tile.scale == 1) {
      tile.setPixel(0, 0, getAvgColor());
    } else if (tile.scale == 16) {
      // TODO convert to using pixel array directly.
      for (int z = 0; z < Chunk.Z_MAX; ++z) {
        for (int x = 0; x < Chunk.X_MAX; ++x) {
          byte block = blocks[x * Chunk.Z_MAX + z];
          byte biome = biomes[x * Chunk.Z_MAX + z];
          tile.setPixel(x, z, avgBlockColor(block, biome));
        }
      }
    } else if (tile.scale == 16 * 16) {
      for (int z = 0; z < Chunk.Z_MAX; ++z) {
        int yp0 = z * 16;

        for (int x = 0; x < Chunk.X_MAX; ++x) {
          int xp0 = x * 16;

          byte block = blocks[x * Chunk.Z_MAX + z];
          if (block == Block.AIR_ID) {
            for (int i = 0; i < 16; ++i) {
              for (int j = 0; j < 16; ++j) {
                tile.setPixel(xp0 + j, yp0 + i, 0xFFFFFFFF);
              }
            }
            continue;
          }

          switch ((int) block) {
            case Block.GRASS_ID:
            case Block.TALLGRASS_ID:
            case Block.LEAVES_ID:
            case Block.LEAVES2_ID:
            case Block.VINES_ID: {
              Texture tex = Block.get(block).getIcon();
              for (int i = 0; i < 16; ++i) {
                for (int j = 0; j < 16; ++j) {
                  float[] rgb = tex.getColor(j, i);
                  if (rgb[3] != 0) {
                    tile.setPixel(xp0 + j, yp0 + i,
                        getBiomeColor(rgb, block, biomes[x * Chunk.Z_MAX + z]));
                  } else {
                    tile.setPixel(xp0 + j, yp0 + i, 0xFFFFFFFF);
                  }
                }
              }
              break;
            }
            default: {
              int[] tex = Block.get(block).getIcon().getData();
              for (int i = 0; i < 16; ++i) {
                for (int j = 0; j < 16; ++j) {
                  int rgb = tex[i * 16 + j];
                  if ((rgb & 0xFF000000) != 0) {
                    tile.setPixel(xp0 + j, yp0 + i, rgb);
                  } else {
                    tile.setPixel(xp0 + j, yp0 + i, 0xFFFFFFFF);
                  }
                }
              }
            }
          }
        }
      }
    } else {
      throw new Error("Unsupported chunk scale.");
    }
  }

  private int avgBlockColor(byte block, byte biome) {
    if (block == Block.AIR_ID) {
      return 0xFFFFFFFF;
    } else {
      switch ((int) block) {
        case Block.GRASS_ID:
        case Block.TALLGRASS_ID:
        case Block.LEAVES_ID:
        case Block.LEAVES2_ID:
        case Block.VINES_ID: {
          float[] rgb = Block.get(block).getIcon().getAvgColorLinear();
          return getBiomeColor(rgb, block, biome);
        }
        default:
          return Block.get(block).getIcon().getAvgColor();
      }
    }
  }

  private int getBiomeColor(float[] rgb, byte block, byte biome) {
    float[] biomeColor;
    float alpha = rgb[3];
    switch ((int) block) {
      case Block.GRASS_ID:
      case Block.TALLGRASS_ID:
        biomeColor = Biomes.getGrassColorLinear(biome);
        return ColorUtil.getRGB(
            (1 - alpha) + alpha * FastMath.pow(rgb[0] * biomeColor[0], Scene.DEFAULT_GAMMA_INV),
            (1 - alpha) + alpha * FastMath.pow(rgb[1] * biomeColor[1], Scene.DEFAULT_GAMMA_INV),
            (1 - alpha) + alpha * FastMath.pow(rgb[2] * biomeColor[2], Scene.DEFAULT_GAMMA_INV));
      case Block.LEAVES_ID:
      case Block.LEAVES2_ID:
      case Block.VINES_ID:
        biomeColor = Biomes.getFoliageColorLinear(biome);
        return ColorUtil.getRGB(
            (1 - alpha) + alpha * FastMath.pow(rgb[0] * biomeColor[0], Scene.DEFAULT_GAMMA_INV),
            (1 - alpha) + alpha * FastMath.pow(rgb[1] * biomeColor[1], Scene.DEFAULT_GAMMA_INV),
            (1 - alpha) + alpha * FastMath.pow(rgb[2] * biomeColor[2], Scene.DEFAULT_GAMMA_INV));
      default:
        return ColorUtil.getRGB((1 - alpha) + alpha * FastMath.pow(rgb[0], Scene.DEFAULT_GAMMA_INV),
            (1 - alpha) + alpha * FastMath.pow(rgb[1], Scene.DEFAULT_GAMMA_INV),
            (1 - alpha) + alpha * FastMath.pow(rgb[2], Scene.DEFAULT_GAMMA_INV));
    }
  }

  /**
   * Render block highlight.
   */
  @Override public synchronized void renderHighlight(MapTile tile, Block hlBlock, int hlColor) {

    if (blocks == null) {
      return;
    }

    if (tile.scale == 16) {
      for (int z = 0; z < 16; ++z) {
        for (int x = 0; x < 16; ++x) {
          if (hlBlock.id == (0xFF & blocks[x * 16 + z])) {
            tile.setPixel(x, z, hlColor);
          }
        }
      }
    } else if (tile.scale > 16) {
      int blockScale = tile.scale / 16;
      for (int x = 0; x < 16; ++x) {
        for (int z = 0; z < 16; ++z) {
          if (hlBlock.id == (0xFF & blocks[x * 16 + z])) {
            int xp0 = x * blockScale;
            int xp1 = xp0 + blockScale;
            int zp0 = z * blockScale;
            int zp1 = zp0 + blockScale;
            for (int j = zp0; j < zp1; ++j) {
              for (int i = xp0; i < xp1; ++i) {
                tile.setPixel(i, j, hlColor);
              }
            }
          }
        }
      }
    }
  }

  @Override public int getAvgColor() {
    return avgColor;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy