ColorSource syntax - KSPSnark/IndicatorLights GitHub Wiki

What's a ColorSource?

A ColorSource is a common type of property on ModuleEmissiveControllers in IndicatorLights.

It's a string value, written in a syntax that defines where to get the color from. The syntax for a ColorSource is simple enough to be easy to use, but with enough flexibility to do useful and interesting things.

This page describes the syntax of ColorSource parameters and provides some examples.

Please see the IndicatorLights syntax overview for a high-level summary of the syntax language, and a discussion of the various other types of syntax available besides color sources.

Background: Why is this needed?

A common concept in IndicatorLights is the idea of a "source" for a color: some "thing" that has an output color that can then be used to perform some task, such as set the color of an emissive.

For example, consider a "blink" controller. What does it actually do? Well, it continually switches the emissive back and forth from some color #1 to some other color #2.

So where does it get those colors from? Well, it would be possible to just hard-code the controller for two specific colors-- say, black and white. It would work just fine... but wouldn't be super interesting. What if someone wants a blink between some other colors?

Okay, you say, just design the blink controller so that it has a couple of fields on it that it reads from config. One field would define color #1, and the other field would define color #2. Now people can set up a blink between any two colors they like, right?

Well, yes... but it's still not as flexible as we might like. That would be fine if I just want a control that blinks between "red" and "green". But what if I want one of those colors to be not just literally "red" but rather "whatever the currently configured 'resource full' color is"? Or "whatever is the current output of <some controller>"?

What we really need is a simple "color definition language" that allows flexibly specifying where to get a color from, so that we can define this flexible concept in the config file for a part. That's what a ColorSource is.


Types of ColorSource

The following types of ColorSource are supported:

The following sections describe the syntax for each of these types of ColorSource.


Literal color

This is the simplest form of ColorSource; it just specifies the RGB components of a constant color.

A literal ColorSource has one of the following forms:

  • RGB: #xxxxxx
  • RGBA: #xxxxxxxx

...where the x's are hexadecimal digits 0-9, A-F. The first two digits are the red component, the next two are green, the next two are blue. In the eight-digit form, the last two digits are the alpha component (which defaults to FF in the six-digit form, i.e. #xxxxxx is equivalent to #xxxxxxFF). Some examples:

  • #000000 - black
  • #FF0000 - red
  • #00FF00 - green
  • #0000FF - blue
  • #FFFFFF - white

...You actually won't find many instances of literal colors in the part config that comes with IndicatorLights. That's because choosing a color like this means that the user can't configure it, which isn't super user-friendly.

However, one place you will see a lot of this syntax is in the config.xml config file that the mod writes to PluginData/IndicatorLights when it runs; that's where the default colors are configured (see next section).

Example

MODULE {
    name = ModuleToggleLED
    activeColor = #FFFF00
    inactiveColor = #000000
}

...the above would be a controller whose output is bright yellow (#FFFF00) when switched on, and totally dark (#000000, black) when switched off.


Default (logical) color

IndicatorLights makes extensive use of "default" (logical) colors. These are colors that are specified by role rather than as a particular RGB value.

A default ColorSource has the form

$Name

...where "Name" must be one of a set of pre-defined values. You can find the full list of these values in the enum located in DefaultColor.cs. Some examples of default ColorSources:

  • $Off
  • $LowResource
  • $DockingCrossfeedOn

...there are quite a few of these, and the list is gradually growing as IndicatorLights adds new features.

With the exception of $Off (which is hard-coded to black), the RGB value for every one of these logical colors is read at run time from the PluginData/IndicatorLights/config.xml file. This is important, because it allows users to configure these colors to suit themselves. That's not just a matter of personal taste-- a significant portion of the population has color-blindness issues, and may have trouble distinguishing certain colors.

Example

MODULE {
    name = ModuleToggleLED
    activeColor = $DockingCrossfeedOn
    inactiveColor = $DockingCrossfeedOff
}

...the above would be a controller whose output is the "crossfeed on" color when switched on, and the "crossfeed off" color when switched off. Both of those colors would be whatever is read from the config.xml file.


Reference

This is a simple but powerful feature that enables chaining together sequences of controllers to create complex behavior.

A reference ColorSource is simply the "name" of some module on the part which functions as a ColorSource-- in practice, some subclass of ModuleResourceController.

The syntax is very simple. There are three basic use cases:

  • By controller name: The ModuleEmissiveController base class (and therefore all its subclasses) has a controllerName property. (See Setting up a ModuleEmissiveController for details.) You can use that name as a reference ColorSource. If a controller on the part has set its controllerName to "foo", for example, then you can simply use the string "foo" as a ColorSource value, which means "go find the controller whose name is 'foo' and use its current output color".
  • By field name: You can reference another field on the same controller module, by using the name of the field. Thus, for example, suppose you have a ModuleResourceLevelIndicator. It has one field named "lowColor" (for when the resource level is low), and another named "criticalColor" (for when the resource is critically low, close to zero). Suppose you don't want to have a separate color for criticalColor, and just want it to follow whatever lowColor is. Then you could set the value of the criticalColor field to be the string "lowColor", and it would automatically reference that field.
  • By class: If a controller doesn't set its controllerName property (i.e. the value is empty or null), then you can refer to it by its class name, e.g "ModuleCrewIndicator" or "ModuleResourceIndicator" or whatever.
  • this keyword: The reserved word this means "the current module where this config lives". For example, a module implementing IScalar can use this in scalar contexts, meaning "the current scalar value of this module".

Note that you can only use the class name for a controller if it doesn't set a controllerName. Essentially, what using the class name does is, "find the first module on the part of this type that doesn't have a controllerName set, and use the output color of that."

Example

MODULE {
    name = ModuleToggleLED
    activeColor = foo
    inactiveColor = ModuleCrewIndicator
}

...the behavior of this controller would be as follows: When switched on, its output will be whatever the output is of the controller on this part whose controllerName is "foo". When switched off, its output will be whatever the output is of the first ModuleCrewIndicator on the part.


Parameterized

This is the most complex (but most flexible and powerful) type of ColorSource. It allows specifying some complex behaviors by using parameters. An important use case is the ability to set up animations with just a snippet of syntax, without requiring code.

A parameterized ColorSource has the form:

functionName(param1,param2,param3,...)

The number and type of parameters will depend on what the function is.

The following functions are currently supported (more may be added in the future):

An important feature is that the parameters may themselves be ColorSource values (including parameterized ones). This allows ColorSources to be nested, allowing you to set up quite complex behavior using the appropriate syntax.

Example

From IndicatorLights' config for the small docking port:

MODULE {
    name = ModuleDockingStateIndicator
    emissiveName = indicator
    readyColor = ModuleToggleLED
    acquireColor = blink(ModuleDockingCrossfeedIndicator, 100, $Off, 100)
    disengageColor = blink(ModuleDockingCrossfeedIndicator, 120, $Off, 1080)
}

...ModuleDockingStateIndicator is a tri-state controller that has three colors (ColorSources, really) for representing the current state of a docking port: readyColor (nothing docked), acquireColor (docking field engaged, but docking not yet completed), and disengageColor (undocked, but not yet far enough apart to be ready to dock again).

In this example, we see the use of several ColorSource types (default, reference, and parameterized):

  • readyColor: "Use whatever the output color is of the ModuleToggleLED on this part."
  • acquireColor: "Blink rapidly, 100 milliseconds on and 100 milliseconds off. The 'on' color is whatever the ModuleDockingCrossfeedIndicator is emitting, and the 'off' color is totally dark."
  • disengageColor: Same deal, but with different timing on the blink.

Here's where we see the power of using parameterized ColorSources: the fact that this module uses blinking patterns when the docking field is engaging/disengaging is in the part config, rather than programmed into the source code-- which means it's completely customizable and easily changed.

A complete list of available functions appears below.

blink

A simple on/off blinking animation. Example usage.

blink(source1, millis1, source2, millis2)

blink(source1, millis1, source2, millis2, phase)

Parameters:

  • source1: The color source to use when "on".
  • millis1: Static expression. The number of milliseconds to spend in the "on" phase.
  • source2: The color source to use when "off".
  • millis2: Static expression. The number of milliseconds to spend in the "off" phase.
  • phase: Static expression. A floating-point number representing the number of cycle intervals that the pattern is shifted in time. Can be any number, but usually expressed in the range [0,1]. Positive number = pattern shifted earlier in time. Defaults to 0 in the 4-argument form of this color source.

dim

A constant brightness adjustment of an input source. Example usage.

dim(source, multiplier)

Parameters:

  • source: The input color source to which to apply the brightness filter.
  • multiplier: Static expression. A floating-point number by which to multiply the input source's brightness. A value in the range [0, 1] will reduce the brightness, though actually you can increase brightness by using a number greater than 1.

if

A two-state source that uses a toggle input to select which of two input color sources to display.

if(input, onSource)

if(input, onSource, offSource)

Parameters:

  • input: Identifies the toggle that controls the color source. Must be in toggle syntax.
  • onSource: The color source to display when the input toggle state is true.
  • offSource: The color source to display when the input toggle state is false. Defaults to off (black) in the 2-argument form of this color source.

lerp

Linearly interpolates between two color sources, based on the value of an input scalar. When the input scalar is at value1, returns the color of source1. When the input scalar is at value2, returns the color of source2. When the input scalar is between value1 and value2, then returns a color appropriately interpolated between the two input color sources.

lerp(input, source1, source2) (suitable when input scalar is in the range [0,1])

lerp(input, source1, value1, source2, value2)

Parameters:

  • input: Identifies the scalar input that controls the interpolation. Must be in scalar syntax.
  • source1: Color source ID of the first color source.
  • value1: Static expression. Input value at-or-below which to return the first color source's color. Defaults to 0 in the 3-argument form of this color source.
  • source2: Color source ID of the second color source.
  • value2: Static expression. Input value at-or-above which to return the second color source's color. Defaults to 1 in the 3-argument form of this color source.

pulsate

An animation that smoothly ramps the brightness up and down between two levels. Example usage.

pulsate(source, millis, multiplier1)

pulsate(source, millis, multiplier1, multiplier2)

pulsate(source, millis, multiplier1, multiplier2, phase)

Parameters:

  • source: The color source to take as input.
  • millis: Static expression. The duration of the pulsate cycle, in milliseconds.
  • multiplier1: Static expression. A floating-point number in the range [0,1] that multiplies source's brightness at one end of the cycle.
  • multiplier2: Static expression. A floating-point number in the range [0,1] that multiplies source's brightness at the other end of the cycle. Defaults to 1 in the 3-argument form of this color source.
  • phase: Static expression. A floating-point number representing the number of cycle intervals that the pattern is shifted in time. Can be any number, but usually expressed in the range [0,1]. Positive number = pattern shifted earlier in time. Defaults to 0 in the 3- and 4-argument forms of this color source.

random

An animation that generates a random on/off flicker, like old-style modem lights. Example usage.

random(source1, source2, period, bias, seed)

random(source1, source2, period, bias)

random(source1, source2, period)

Parameters:

  • source1: The color source to use when the flicker is in the "on" phase.
  • source2: The color source to use when the flicker is in the "off" phase.
  • period: Static expression. Time constant, in milliseconds, that controls the speed it flickers on average.
  • bias: Static expression. A floating point number in the range (-1, 1) that controls what percentage of the time the flicker is "on" versus "off". When it's zero (the default), on/off is 50/50. At 1, the light is on all the time; at -1, it's off all the time. Defaults to 0 in the 3-argument form of this color source.
  • seed: Static expression. An integer that controls the pseudorandom flicker. Useful if you want a set of emissives on a part that flicker independently rather than in unison. Defaults to 0 in the 3- and 4-argument forms of this color source.