/******************************************************************************* * Copyright (c) 2015 * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. *******************************************************************************/ package jsettlers.algorithms.previewimage; import jsettlers.common.position.RelativePoint; import jsettlers.common.position.ShortPoint2D; /** * This class creates a preview image of a map that can be saved in the map header. * * @author Andreas Eberle */ public final class PreviewImageCreator { /** * Points to use for height computation. */ private final static RelativePoint[] HEIGHTPOINTS = new RelativePoint[] { new RelativePoint(0, 1), new RelativePoint(1, 1), new RelativePoint(0, 2), new RelativePoint(1, 2), new RelativePoint(2, 2), }; private final int gridWidth; private final int gridHeight; private final IPreviewImageDataSupplier dataSupplier; private final int previewImageSize; /** * Constructor to create a {@link PreviewImageCreator} object. * * @param gridWidth * The width of the grid that's the source of the preview image. * @param gridHeight * The height of the grid that's the source of the preview image. * @param previewImageSize * The height and width the preview image will have. * @param dataSupplier * The {@link IPreviewImageDataSupplier} that gives the data of the landscape of the source map. */ public PreviewImageCreator(int gridWidth, int gridHeight, int previewImageSize, IPreviewImageDataSupplier dataSupplier) { this.gridWidth = gridWidth; this.gridHeight = gridHeight; this.dataSupplier = dataSupplier; this.previewImageSize = previewImageSize; } /** * Calculates a preview image with the data supplied by the {@link IPreviewImageDataSupplier} given in the constructor. * * @return Array of colors as short values. The array represents a square image of the specified previewImageSize. */ public short[] getPreviewImage() { short[] image = new short[previewImageSize * previewImageSize]; for (short x = 0; x < gridWidth; x++) { for (short y = 0; y < gridHeight; y++) { int imageSpace = toImageSpace(x, y); if (image[imageSpace] == 0) { image[imageSpace] = getColor(x, y); } } } boolean usey = false; for (int x = 0; x < previewImageSize; x++) { for (int y = 0; y < previewImageSize; y++) { if (usey && y > 0 && image[x + y * previewImageSize] == 0) { image[x + y * previewImageSize] = image[x + (y - 1) * previewImageSize]; usey = false; } else if (x > 0 && image[x + y * previewImageSize] == 0) { image[x + y * previewImageSize] = image[x - 1 + y * previewImageSize]; usey = true; } else if (y > 0 && image[x + y * previewImageSize] == 0) { image[x + y * previewImageSize] = image[x + (y - 1) * previewImageSize]; } } } return image; } private int toImageSpace(int x, int y) { int inImageSpace = scale(x, gridWidth, previewImageSize) + scale(y, gridHeight, previewImageSize) * previewImageSize; return inImageSpace; } /** * Scale a coordinate to image space. * * @param x * @param width * @return */ private static final int scale(int x, int width, int previewImageSize) { int px = (int) ((double) x / width * previewImageSize); return px < 0 ? 0 : px >= previewImageSize ? previewImageSize : px; } private short getColor(short x, short y) { ShortPoint2D current = new ShortPoint2D(x, y); final int dheight = getLandscapeHeightAround(current, false) - getLandscapeHeightAround(current, true); final float basecolor = .8f + .15f * dheight; return dataSupplier.getLandscape(x, y).getColor().toShortColor(basecolor); } private int getLandscapeHeightAround(ShortPoint2D current, boolean upwards) { int count = 0; int height = 0; for (RelativePoint p : HEIGHTPOINTS) { ShortPoint2D toTest; if (upwards) { toTest = p.calculatePoint(current); } else { toTest = p.invert().calculatePoint(current); } short x = toTest.x; short y = toTest.y; if (x >= 0 && x < gridWidth && y >= 0 && y < gridHeight) { height += dataSupplier.getLandscapeHeight(x, y); count += 1; } } if (count > 0) { return height / count; } else { return dataSupplier.getLandscapeHeight(current.x, current.y); } } }