001package squidpony.squidgrid.gui.gdx; 002 003import com.badlogic.gdx.graphics.Color; 004import squidpony.StringKit; 005import squidpony.squidmath.NumberTools; 006 007import java.io.Serializable; 008 009/** 010 * Grouping of qualities related to glow and light emission. When a Radiance variable in some object is null, it 011 * means that object doesn't emit light; if a Radiance variable is non-null, it will probably emit light unless the 012 * color of light it produces is fully transparent. Light may take up one cell or extend into nearby cells, and the 013 * radius may change over time in up to two patterns (flicker, which randomly increases and decreases lighting radius, 014 * and/or strobe, which increases and decreases lighting radius in an orderly retract-expand-retract-expand pattern). 015 * You can set the {@link #flare} variable to some value between 0.0f and 1.0f to temporarily expand the minimum radius 016 * for strobe and/or flare, useful for gameplay-dependent brightening of a Radiance. 017 * <br> 018 * This object has 6 fields, each a float: 019 * <ul> 020 * <li>range, how far the light extends; 0f is "just this cell"</li> 021 * <li>color, the color of the light as a float; typically opaque and lighter than the glowing object's color</li> 022 * <li>flicker, the rate of random continuous change to radiance range</li> 023 * <li>strobe, the rate of non-random continuous change to radiance range</li> 024 * <li>flare, used to suddenly increase the minimum radius of lighting; expected to be changed after creation</li> 025 * <li>delay, which delays the pattern of effects like strobe so a sequence can be formed with multiple Radiance</li> 026 * </ul> 027 * These all have defaults; if no parameters are specified the light will be white, affect only the current cell, and 028 * won't flicker or strobe. 029 * <br> 030 * Created by Tommy Ettinger on 6/16/2018. 031 */ 032public class Radiance implements Serializable { 033 private static final long serialVersionUID = 1L; 034 035 /** 036 * How far the radiated light extends; 0f is "just this cell", anything higher can go into neighboring cells. 037 * This is permitted to be a non-integer value, which will make this extend into further cells partially. 038 */ 039 public float range; 040 /** 041 * The color of light as a float; typically opaque and lighter than the glowing object's symbol. 042 */ 043 public float color; 044 /** 045 * The rate of random continuous change to radiance range, like the light from a campfire. The random component of 046 * the change is determined by the {@link System#identityHashCode(Object)} of this Radiance, which will probably 047 * make all flicker effects different when flicker is non-0. 048 */ 049 public float flicker; 050 /** 051 * The rate of non-random continuous change to radiance range, like a mechanical strobe effect. This looks like a 052 * strobe light when the value is high enough, but at lower values it will smoothly pulse, which can be less 053 * distracting to players. 054 */ 055 public float strobe; 056 057 /** 058 * A time delay that applies to when the strobe and flicker effects change; useful with strobe to make a strobe 059 * expand its lit radius at one point, then expand at a slightly later time at another Radiance with a delay. The 060 * range for delay should be considered 0f to 1f, with 0f the default (no delay) and values between 0 and 1f that 061 * fraction of a full strobe delayed from that default. 062 */ 063 public float delay; 064 /** 065 * A temporary increase to the minimum radiance range, meant to brighten a glow during an effect. 066 * This should be a float between 0f and 1f, with 0f meaning no change and 1f meaning always max radius. 067 */ 068 public float flare; 069 070 /** 071 * All-default constructor; makes a single-cell unchanging white light. 072 */ 073 public Radiance() 074 { 075 this(0f, SColor.FLOAT_WHITE, 0f, 0f, 0f, 0f); 076 } 077 078 /** 079 * Makes an unchanging white light with the specified range in cells. 080 * @param range possibly-non-integer radius to light, in cells 081 */ 082 public Radiance(float range) 083 { 084 this(range, SColor.FLOAT_WHITE, 0f, 0f, 0f, 0f); 085 } 086 087 /** 088 * Makes an unchanging light with the given color (as a packed float) and the specified range in cells. 089 * @param range possibly-non-integer radius to light, in cells 090 * @param color packed float color, as produced by {@link Color#toFloatBits()} 091 */ 092 public Radiance(float range, float color) 093 { 094 this(range, color, 0f, 0f, 0f, 0f); 095 } 096 097 /** 098 * Makes a flickering light with the given color (as a packed float) and the specified range in cells; the flicker 099 * parameter affects the rate at which this will randomly reduce its range and return to normal. 100 * @param range possibly-non-integer radius to light, in cells 101 * @param color packed float color, as produced by {@link Color#toFloatBits()} 102 * @param flicker the rate at which to flicker, as a non-negative float 103 */ 104 public Radiance(float range, float color, float flicker) 105 { 106 this(range, color, flicker, 0f, 0f, 0f); 107 } 108 /** 109 * Makes a flickering light with the given color (as a packed float) and the specified range in cells; the flicker 110 * parameter affects the rate at which this will randomly reduce its range and return to normal, and the strobe 111 * parameter affects the rate at which this will steadily reduce its range and return to normal. Usually one of 112 * flicker or strobe is 0; if both are non-0, the radius will be smaller than normal. 113 * @param range possibly-non-integer radius to light, in cells 114 * @param color packed float color, as produced by {@link Color#toFloatBits()} 115 * @param flicker the rate at which to flicker, as a non-negative float 116 * @param strobe the rate at which to strobe or pulse, as a non-negative float 117 */ 118 public Radiance(float range, float color, float flicker, float strobe) 119 { 120 this(range, color, flicker, strobe, 0f, 0f); 121 } 122 /** 123 * Makes a flickering light with the given color (as a libGDX Color) and the specified range in cells; the flicker 124 * parameter affects the rate at which this will randomly reduce its range and return to normal, and the strobe 125 * parameter affects the rate at which this will steadily reduce its range and return to normal. Usually one of 126 * flicker or strobe is 0; if both are non-0, the radius will be smaller than normal. 127 * @param range possibly-non-integer radius to light, in cells 128 * @param color a libGDX Color object; will not be modified 129 * @param flicker the rate at which to flicker, as a non-negative float 130 * @param strobe the rate at which to strobe or pulse, as a non-negative float 131 */ 132 public Radiance(float range, Color color, float flicker, float strobe) 133 { 134 this(range, color.toFloatBits(), flicker, strobe, 0f, 0f); 135 } 136 137 /** 138 * Makes a flickering light with the given color (as a packed float) and the specified range in cells; the flicker 139 * parameter affects the rate at which this will randomly reduce its range and return to normal, and the strobe 140 * parameter affects the rate at which this will steadily reduce its range and return to normal. Usually one of 141 * flicker or strobe is 0; if both are non-0, the radius will be smaller than normal. The delay parameter is usually 142 * from 0f to 1f, and is almost always 0f unless this is part of a group of related Radiance objects; it affects 143 * when strobe and flicker hit "high points" and "low points", and should usually be used with strobe. 144 * @param range possibly-non-integer radius to light, in cells 145 * @param color packed float color, as produced by {@link Color#toFloatBits()} 146 * @param flicker the rate at which to flicker, as a non-negative float 147 * @param strobe the rate at which to strobe or pulse, as a non-negative float 148 * @param delay a delay applied to the "high points" and "low points" of strobe and flicker, from 0f to 1f 149 */ 150 public Radiance(float range, float color, float flicker, float strobe, float delay) 151 { 152 this(range, color, flicker, strobe, delay, 0f); 153 } 154 /** 155 * Makes a flickering light with the given color (as a packed float) and the specified range in cells; the flicker 156 * parameter affects the rate at which this will randomly reduce its range and return to normal, and the strobe 157 * parameter affects the rate at which this will steadily reduce its range and return to normal. Usually one of 158 * flicker or strobe is 0; if both are non-0, the radius will be smaller than normal. The delay parameter is usually 159 * from 0f to 1f, and is almost always 0f unless this is part of a group of related Radiance objects; it affects 160 * when strobe and flicker hit "high points" and "low points", and should usually be used with strobe. This allows 161 * setting flare, where flare is used to create a sudden increase in the minimum radius for the Radiance, but flare 162 * makes the most sense to set when an event should brighten a Radiance, not in the constructor. Valid values for 163 * flare are usually between 0f and 1f. 164 * @param range possibly-non-integer radius to light, in cells 165 * @param color packed float color, as produced by {@link Color#toFloatBits()} 166 * @param flicker the rate at which to flicker, as a non-negative float 167 * @param strobe the rate at which to strobe or pulse, as a non-negative float 168 * @param delay a delay applied to the "high points" and "low points" of strobe and flicker, from 0f to 1f 169 * @param flare affects the minimum radius for the Radiance, from 0f to 1f with a default of 0f 170 */ 171 public Radiance(float range, float color, float flicker, float strobe, float delay, float flare) 172 { 173 this.range = range; 174 this.color = color; 175 this.flicker = flicker; 176 this.strobe = strobe; 177 this.delay = delay; 178 this.flare = flare; 179 } 180 181 /** 182 * Copies another Radiance exactly, except for the pattern its flicker may have, if any. 183 * @param other another Radiance to copy 184 */ 185 public Radiance(Radiance other) 186 { 187 this(other.range, other.color, other.flicker, other.strobe, other.delay, other.flare); 188 } 189 190 /** 191 * Provides the calculated current range adjusted for flicker and strobe at the current time in milliseconds, with 192 * flicker seeded with the identity hash code of this Radiance. Higher values of flicker and strobe will increase 193 * the frequency at which the range changes but will not allow it to exceed its starting range, only to diminish 194 * temporarily. If both flicker and strobe are non-0, the range will usually be smaller than if only one was non-0, 195 * and if both are 0, this simply returns range. 196 * @return the current range, adjusting for flicker and strobe using the current time 197 */ 198 public float currentRange() 199 { 200 final float time = (System.currentTimeMillis() & 0x3ffffL) * 0x1.9p-9f; 201 float current = range; 202 if(flicker != 0f) 203 current *= NumberTools.swayRandomized(System.identityHashCode(this), time * flicker + delay) * 0.375f + 0.625f; 204 if(strobe != 0f) 205 current *= NumberTools.swayTight(time * strobe + delay) * 0.5f + 0.5f; 206 return Math.max(current, range * flare); 207 } 208 209 /** 210 * Makes a chain of Radiance objects that will pulse in a sequence, expanding from one to the next. 211 * This chain is an array of Radiance where the order matters. 212 * @param length how many Radiance objects should be in the returned array 213 * @param range in cells, how far each Radiance should expand from its start at its greatest radius 214 * @param color as a packed float color 215 * @param strobe the rate at which the chain will pulse; should be greater than 0 216 * @return an array of Radiance objects that will pulse in sequence. 217 */ 218 public static Radiance[] makeChain(int length, float range, float color, float strobe) 219 { 220 if(length <= 1) 221 return new Radiance[]{new Radiance(range, color, 0f, strobe)}; 222 Radiance[] chain = new Radiance[length]; 223 float d = -2f / (length); 224 for (int i = 0; i < length; i++) { 225 chain[i] = new Radiance(range, color, 0f, strobe, d * i); 226 } 227 return chain; 228 } 229 230 @Override 231 public String toString() { 232 return "Radiance{" + 233 "range=" + range + 234 ", color=" + color + 235 ", flicker=" + flicker + 236 ", strobe=" + strobe + 237 ", delay=" + delay + 238 ", flare=" + flare + 239 '}'; 240 } 241 242 @Override 243 public boolean equals(Object o) { 244 if (this == o) return true; 245 if (o == null || getClass() != o.getClass()) return false; 246 247 Radiance radiance = (Radiance) o; 248 249 if (Float.compare(radiance.range, range) != 0) return false; 250 if (Float.compare(radiance.color, color) != 0) return false; 251 if (Float.compare(radiance.flicker, flicker) != 0) return false; 252 if (Float.compare(radiance.strobe, strobe) != 0) return false; 253 if (Float.compare(radiance.delay, delay) != 0) return false; 254 return Float.compare(radiance.flare, flare) == 0; 255 } 256 257 @Override 258 public int hashCode() { 259 int result = NumberTools.floatToIntBits(range); 260 result ^= (result << 11 | result >>> 21) + (result << 19 | result >>> 13) + NumberTools.floatToIntBits(color); 261 result ^= (result << 11 | result >>> 21) + (result << 19 | result >>> 13) + NumberTools.floatToIntBits(flicker); 262 result ^= (result << 11 | result >>> 21) + (result << 19 | result >>> 13) + NumberTools.floatToIntBits(strobe); 263 result ^= (result << 11 | result >>> 21) + (result << 19 | result >>> 13) + NumberTools.floatToIntBits(delay); 264 result ^= (result << 11 | result >>> 21) + (result << 19 | result >>> 13) + NumberTools.floatToIntBits(flare); 265 return result; 266 } 267 268 public String serializeToString() 269 { 270 return "{" + StringKit.hex(NumberTools.floatToIntBits(range)) + 271 "," + StringKit.hex(NumberTools.floatToIntBits(color)) + 272 "," + StringKit.hex(NumberTools.floatToIntBits(flicker)) + 273 "," + StringKit.hex(NumberTools.floatToIntBits(strobe)) + 274 "," + StringKit.hex(NumberTools.floatToIntBits(delay)) + 275 "," + StringKit.hex(NumberTools.floatToIntBits(flare)) + 276 "}"; 277 } 278 279 public static Radiance deserializeFromString(String data) 280 { 281 return data != null && data.length() >= 54 282 ? new Radiance( 283 NumberTools.intBitsToFloat(StringKit.intFromHex(data, 1, 9)), 284 NumberTools.intBitsToFloat(StringKit.intFromHex(data, 10, 18)), 285 NumberTools.intBitsToFloat(StringKit.intFromHex(data, 19, 27)), 286 NumberTools.intBitsToFloat(StringKit.intFromHex(data, 28, 36)), 287 NumberTools.intBitsToFloat(StringKit.intFromHex(data, 37, 45)), 288 NumberTools.intBitsToFloat(StringKit.intFromHex(data, 46, 54))) 289 : null; 290 } 291}