/* * This file is part of the Illarion project. * * Copyright © 2014 - Illarion e.V. * * Illarion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Illarion 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. */ package illarion.client.world; import illarion.client.net.client.MapDimensionCmd; import illarion.common.graphics.MapConstants; import illarion.common.util.FastMath; import javax.annotation.Nonnull; import javax.annotation.concurrent.NotThreadSafe; /** * This class is used to store and calculate the dimensions of the map. It requires the size of the screen as * information to offer the proper values. This class requires updates upon changes of the screen size. * * @author Martin Karing <nitram@illarion.org> */ @NotThreadSafe public final class MapDimensions { /** * This is the amount of rows and columns that are requested from the server in addition to the tiles needed to * fill the screen size. If this value is chosen too high the result is that large items and light sources are * known to the client too late and just "pop" in. */ private static final int ADD_MAP_RANGE = 3; /** * This is the additional map range that is attached to the bottom of the clipping ranges. */ private static final int ADD_CLIPPING_RANGE_BOTTOM = ADD_MAP_RANGE + 10; /** * The additional size for the clipping area. This is used to prevent black stripes caused by tiles removed too * early. */ private static final int ADD_CLIPPING_RANGE = ADD_MAP_RANGE + 8; /** * The singleton instance of this class. */ @Nonnull private static final MapDimensions INSTANCE = new MapDimensions(); /** * The amount of rows from the center to the bottom that are within the visible range. Tiles further away are * removed. */ private int clippingOffsetBottom; /** * The amount of rows from the center to the left that are within the visible range. Tiles further away are * removed. */ private int clippingOffsetLeft; /** * The amount of rows from the center to the right that are within the visible range. Tiles further away are * removed. */ private int clippingOffsetRight; /** * The amount of rows from the center to the top that are within the visible range. Tiles further away are * removed. */ private int clippingOffsetTop; /** * The height of the area that is within the clipping range. Measured in pixels. */ private int offScreenHeight; /** * The width of the area that is within the clipping range. Measured in pixels. */ private int offScreenWidth; /** * The height of the last reported screen size. */ private int onScreenHeight; /** * The width of the last reported screen size. */ private int onScreenWidth; /** * The amount of tile rows kept on the screen. */ private int stripesHeight; /** * The amount of tile columns kept on the screen. */ private int stripesWidth; /** * The last width that was reported as map width to the server. */ private int serverMapDimensionWidth; /** * The last height that was reported as map height to the server. */ private int serverMapDimensionHeight; /** * The private constructor to ensure that no further instances are created. */ private MapDimensions() { // nothing } /** * Get the singleton instance of this class. * * @return the singleton instance of this class. */ @Nonnull public static MapDimensions getInstance() { return INSTANCE; } /** * The offset from the center of the screen towards the bottom in tile stripes. Any tile beyond this offset is * allowed to be clipped away. * * @return the clipping distance from the center towards the bottom */ public int getClippingOffsetBottom() { return clippingOffsetBottom; } /** * The offset from the center of the screen towards the left in tile stripes. Any tile beyond this offset is * allowed to be clipped away. * * @return the clipping distance from the center towards the left */ public int getClippingOffsetLeft() { return clippingOffsetLeft; } /** * The offset from the center of the screen towards the right in tile stripes. Any tile beyond this offset is * allowed to be clipped away. * * @return the clipping distance from the center towards the right */ public int getClippingOffsetRight() { return clippingOffsetRight; } /** * The offset from the center of the screen towards the top in tile stripes. Any tile beyond this offset is * allowed to be clipped away. * * @return the clipping distance from the center towards the top */ public int getClippingOffsetTop() { return clippingOffsetTop; } /** * The height in pixels of the screen that needs to be rendered. This is usually slightly larger then the visible * screen. It represents the size of the map in pixels that is requested from the server. * * @return the height of the off screen */ public int getOffScreenHeight() { return offScreenHeight; } /** * The width in pixels of the screen that needs to be rendered. This is usually slightly larger then the visible * screen. It represents the size of the map in pixels that is requested from the server. * * @return the width of the off screen */ public int getOffScreenWidth() { return offScreenWidth; } /** * Get the height of the visible screen in pixels. * * @return the height of the visible screen */ public int getOnScreenHeight() { return onScreenHeight; } /** * Get the width of the visible screen in pixels. * * @return the width of the visible screen */ public int getOnScreenWidth() { return onScreenWidth; } /** * The height of the map in stripes. * * @return the height in stripes */ public int getStripesHeight() { return stripesHeight; } /** * The width of the map in stripes. * * @return the width in stripes */ public int getStripesWidth() { return stripesWidth; } /** * Report a new screen size to the application. This needs to be done upon every update of the screen size. This * function will cause all internal values to be recalculated in case new values are reported. * * @param width the width of the screen in pixels * @param height the height of the screen in pixels * @param forced send the new size to the server even if it did not change */ public void reportScreenSize(int width, int height, boolean forced) { if (!forced && (onScreenHeight == height) && (onScreenWidth == width)) { return; } onScreenWidth = width; onScreenHeight = height; int heightInTiles = FastMath.ceil(((float) height / (float) MapConstants.TILE_H) * 2.f); int widthInTiles = FastMath.ceil(((float) width / (float) MapConstants.TILE_W) * 2.f); clippingOffsetTop = FastMath.ceil(heightInTiles / 2.f) + ADD_CLIPPING_RANGE; clippingOffsetBottom = -FastMath.ceil(heightInTiles / 2.f) - ADD_CLIPPING_RANGE_BOTTOM; clippingOffsetLeft = -FastMath.ceil(widthInTiles / 2.f) - ADD_CLIPPING_RANGE; clippingOffsetRight = FastMath.ceil(widthInTiles / 2.f) + ADD_CLIPPING_RANGE; stripesWidth = widthInTiles + ADD_MAP_RANGE + ADD_MAP_RANGE; stripesHeight = heightInTiles + ADD_MAP_RANGE + ADD_MAP_RANGE; offScreenWidth = (stripesWidth * MapConstants.TILE_W) / 2; offScreenHeight = (stripesHeight * MapConstants.TILE_H) / 2; int serverMapDimWidth = stripesWidth >> 2; int serverMapDimHeight = stripesHeight >> 2; if (forced || (serverMapDimHeight != serverMapDimensionHeight) || (serverMapDimWidth != serverMapDimensionWidth)) { serverMapDimensionHeight = serverMapDimHeight; serverMapDimensionWidth = serverMapDimWidth; World.getNet().sendCommand(new MapDimensionCmd(serverMapDimWidth, serverMapDimHeight)); } } }