/******************************************************************************* * Copyright 2019 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.talosvfx.talos.runtime.modules; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Interpolation; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Json; import com.badlogic.gdx.utils.JsonValue; import com.talosvfx.talos.runtime.ScopePayload; import com.talosvfx.talos.runtime.values.ColorPoint; import com.talosvfx.talos.runtime.values.NumericalValue; import java.util.Comparator; public class GradientColorModule extends AbstractModule { public static final int ALPHA = 0; public static final int OUTPUT = 0; NumericalValue alpha; NumericalValue output; private Array<ColorPoint> points; private Color tmpColor = new Color(); Comparator<ColorPoint> comparator = new Comparator<ColorPoint>() { @Override public int compare (ColorPoint o1, ColorPoint o2) { if (o1.pos < o2.pos) return -1; if (o1.pos > o2.pos) return 1; return 0; } }; @Override public void init () { super.init(); resetPoints(); } @Override protected void defineSlots () { alpha = createInputSlot(ALPHA); output = createOutputSlot(OUTPUT); } protected void processAlphaDefaults () { if (alpha.isEmpty()) { // as default we are going to fetch the lifetime or duration depending on context float requester = getScope().getFloat(ScopePayload.REQUESTER_ID); if (requester < 1) { // particle alpha.set(getScope().get(ScopePayload.PARTICLE_ALPHA)); alpha.setEmpty(false); } else if (requester > 1) { // emitter alpha.set(getScope().get(ScopePayload.EMITTER_ALPHA)); alpha.setEmpty(false); } else { // whaat? alpha.set(0); } } } @Override public void processValues () { processAlphaDefaults(); interpolate(alpha.getFloat(), output); } private void interpolate (float alpha, NumericalValue output) { Color color = getPosColor(alpha); output.set(color.r, color.g, color.b, 1f); } public Array<ColorPoint> getPoints () { return points; } private void resetPoints () { // need to guarantee at least one point points = new Array<>(); ColorPoint colorPoint = new ColorPoint(); colorPoint.pos = 0; colorPoint.color.set(255 / 255f, 68 / 255f, 26 / 255f, 1f); points.add(colorPoint); } public ColorPoint createPoint (Color color, float pos) { ColorPoint colorPoint = new ColorPoint(); colorPoint.pos = pos; colorPoint.color.set(color); points.add(colorPoint); points.sort(comparator); return colorPoint; } public void removePoint (int hitIndex) { if (points.size <= 1) return; points.removeIndex(hitIndex); } public Color getPosColor (float pos) { if (pos <= points.get(0).pos) { tmpColor.set(points.get(0).color); } if (pos >= points.get(points.size - 1).pos) { tmpColor.set(points.get(points.size - 1).color); } for (int i = 0; i < points.size - 1; i++) { if (points.get(i).pos < pos && points.get(i + 1).pos > pos) { // found it if (points.get(i + 1).pos == points.get(i).pos) { tmpColor.set(points.get(i).color); } else { float localAlpha = (pos - points.get(i).pos) / (points.get(i + 1).pos - points.get(i).pos); tmpColor.r = Interpolation.linear.apply(points.get(i).color.r, points.get(i + 1).color.r, localAlpha); tmpColor.g = Interpolation.linear.apply(points.get(i).color.g, points.get(i + 1).color.g, localAlpha); tmpColor.b = Interpolation.linear.apply(points.get(i).color.b, points.get(i + 1).color.b, localAlpha); } break; } } return tmpColor; } public void setPoints (Array<ColorPoint> from) { points.clear(); for (ColorPoint fromPoint : from) { ColorPoint point = new ColorPoint(fromPoint.color, fromPoint.pos); points.add(point); } } @Override public void write (Json json) { super.write(json); Array<ColorPoint> points = getPoints(); json.writeArrayStart("points"); for (ColorPoint point : points) { json.writeObjectStart(); json.writeValue("r", point.color.r); json.writeValue("g", point.color.g); json.writeValue("b", point.color.b); json.writeValue("pos", point.pos); json.writeObjectEnd(); } json.writeArrayEnd(); } @Override public void read (Json json, JsonValue jsonData) { super.read(json, jsonData); points.clear(); final JsonValue jsonPpoints = jsonData.get("points"); for (JsonValue point : jsonPpoints) { createPoint(new Color(point.getFloat("r"), point.getFloat("g"), point.getFloat("b"), 1f), point.getFloat("pos")); } } }