/*
* This file is part of the Illarion project.
*
* Copyright © 2015 - 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 org.illarion.engine.graphic;
import illarion.common.util.Bresenham;
import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.Map;
/**
* This class stores a set of light rays that originate from a root location.
*
* @author Nop
* @author Martin Karing <nitram@illarion.org>
*/
final class LightRays {
/**
* The root node.
*/
@Nonnull
private final RayNode root;
/**
* The length of the rays
*/
private final int size;
/**
* The caches for the rays.
*/
@Nonnull
private static final Map<Integer, LightRays> RAY_CACHE = new HashMap<>();
@Nonnull
public static LightRays getRays(int size) {
LightRays rays = RAY_CACHE.get(size);
if (rays == null) {
synchronized (RAY_CACHE) {
rays = RAY_CACHE.get(size);
if (rays == null) {
rays = new LightRays(size);
RAY_CACHE.put(size, rays);
}
}
}
return rays;
}
/**
* Create a new say of rays.
*
* @param targetSize the length of the light rays
*/
public LightRays(int targetSize) {
size = targetSize;
root = new RayNode(targetSize);
Bresenham bresenham = new Bresenham();
for (int i = -targetSize; i < targetSize; ++i) {
createRay(i, -targetSize, bresenham);
createRay(i + 1, targetSize, bresenham);
createRay(targetSize, i, bresenham);
createRay(-targetSize, i + 1, bresenham);
}
}
/**
* Apply a light source to the root node. This causes that the root node is set to the location of the
* light source and the rays are used for this light source. With knowing the real location there are the checks
* down with the {@link LightingMap} of the light ray gets over the tiles correctly and with the results the
* light rays are modified to the shadow by the objects on the map applies correctly.
*
* @param light the source of the light that shall be mapped with the pre
*/
public void apply(@Nonnull LightSource light) {
root.apply(light, 1.0f);
}
/**
* Prepare a single light ray and add it to the root node
*
* @param x the x coordinate of the target location of the ray
* @param y the y coordinate of the target location of the ray
*/
private void createRay(int x, int y, @Nonnull Bresenham bresenham) {
bresenham.calculate(0, 0, x, y);
bresenham.adjustStart(0, 0);
root.addRay(bresenham.getX(), bresenham.getY(), bresenham.getLength(), 1, size);
}
}