/* Copyright (c) 2016 Jesper Öqvist <jesper@llbit.se>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package se.llbit.chunky.map;
import javafx.scene.paint.Color;
import se.llbit.chunky.resources.BitmapImage;
import se.llbit.chunky.world.Chunk;
import se.llbit.chunky.world.ChunkPosition;
import se.llbit.chunky.world.ChunkView;
import se.llbit.chunky.world.Region;
import se.llbit.math.ColorUtil;
/**
* A tile in the 2D world map or minimap. The tile contains either a chunk or a region.
* The scale of the tile can not be changed.
*/
public class MapTile {
int[] pixels;
public ChunkPosition pos;
/**
* Decides if each tile is a chunk or a region (tile=chunk if true).
*/
private boolean chunkMode;
/**
* Size of a single chunk in pixels.
*/
public int scale;
/**
* Size of the pixel buffer.
*/
public int size;
public boolean isCached = false;
public MapTile(ChunkPosition position, ChunkView view) {
rebuild(position, view);
}
public void drawCached(MapBuffer buffer, WorldMapLoader mapLoader, ChunkView view) {
if (isCached) {
drawCached(buffer, view);
} else {
draw(buffer, mapLoader, view);
}
}
public void draw(MapBuffer buffer, WorldMapLoader mapLoader, ChunkView view) {
if (scale >= 16) {
Chunk chunk = mapLoader.getWorld().getChunk(pos);
view.renderer.render(chunk, this);
if (buffer.highlightEnabled()) {
Color fxColor = buffer.highlightColor();
int hlColor = ColorUtil.getArgb(fxColor.getRed(), fxColor.getGreen(), fxColor.getBlue(),
fxColor.getOpacity());
chunk.renderHighlight(this, buffer.highlightBlock(), hlColor);
}
if (mapLoader.getChunkSelection().isSelected(pos)) {
for (int i = 0; i < size * size; ++i) {
pixels[i] = selectionTint(pixels[i]);
}
}
} else {
Region region = mapLoader.getWorld().getRegion(pos);
int pixelOffset = 0;
for (int z = 0; z < 32; ++z) {
for (int x = 0; x < 32; ++x) {
Chunk chunk = region.getChunk(x, z);
pixels[pixelOffset] = view.renderer.getChunkColor(chunk);
if (mapLoader.getChunkSelection().isSelected(chunk.getPosition())) {
pixels[pixelOffset] = selectionTint(pixels[pixelOffset]);
}
pixelOffset += 1;
}
}
}
drawCached(buffer, view);
isCached = true;
}
/** @return the argb color value tinted with the selection color. */
private int selectionTint(int argb) {
int red = (argb >> 16) & 0xFF;
int green = (argb >> 8) & 0xFF;
int blue = argb & 0xFF;
return (argb & 0xFF000000) | ((red / 2 + 0x7F) << 16) | (green / 2) << 8 | (blue / 2);
}
private void drawCached(MapBuffer buffer, ChunkView view) {
if (view.isVisible(pos)) {
int x0;
int z0;
if (chunkMode) {
x0 = size * (pos.x - view.px0);
z0 = size * (pos.z - view.pz0);
} else {
x0 = size * (pos.x - view.prx0);
z0 = size * (pos.z - view.prz0);
}
int srcPos = 0;
for (int z = 0; z < size; ++z) {
buffer.copyPixels(pixels, srcPos, x0, z0 + z, size);
srcPos += size;
}
}
}
public void setPixel(int x, int z, int argb) {
pixels[z * size + x] = argb;
}
public void setPixels(int[] newPixels) {
System.arraycopy(newPixels, 0, pixels, 0, size * size);
}
public void fill(int argb) {
int[] pixels = new int[size * size];
for (int i = 0; i < size * size; ++i) {
pixels[i] = argb;
}
setPixels(pixels);
}
public void rebuild(ChunkPosition newPos, ChunkView view) {
isCached = false;
pos = newPos;
scale = view.chunkScale;
chunkMode = scale >= 16;
int newSize = chunkMode ? scale : 32;
// Resize buffer if needed.
if (newSize != size) {
size = newSize;
pixels = new int[size * size];
}
}
/**
* Draw a bitmap image to this map tile.
*/
public void drawImage(BitmapImage image) {
// Safety check to see that the image has the correct size.
// This check fails when trying to draw static icons not rendered to the tile size.
// TODO: ensure that the image is always scaled to the tile size.
if (image.width == size || image.height == size) {
System.arraycopy(image.data, 0, pixels, 0, size * size);
}
}
}