Commands
CmSave:
PUBLIC Commander.CommandProc ~ {
arg: Rope.ROPE ← Args.GetRope[cmd];
IF arg = NIL THEN RETURN[$Failure, "Save requires a filename as argument"];
ColorTrixMap.Save[ColorTrixMap.Read[], arg];
}
;
CmLoad:
PUBLIC Commander.CommandProc ~ {
arg: Rope.ROPE ← Args.GetRope[cmd];
IF arg = NIL THEN RETURN[$Failure, "Filename required as argument"];
IF NOT ColorTrixMap.Load[arg] THEN RETURN[$Failure, "Can't read file."];
};
CmMono:
PUBLIC Commander.CommandProc ~ {ColorTrixMap.Mono[]};
Gammaler: Controls.ControlProc ~ {
IF control.mouse.button = right
OR control.mouse.state = up
THEN ColorTrixMap.Gamma[control.value];
};
CmGamma:
PUBLIC Commander.CommandProc ~ {
cmSave: Cmap ← ColorTrixMap.Read[];
arg: Args.Arg ← Args.ArgReal[cmd];
IF arg.ok
THEN ColorTrixMap.Gamma[arg.real]
ELSE [] ← Controls.OuterViewer[
name: "Gamma",
column: right,
buttons: standardButtonList,
controls: LIST[Controls.NewControl[name: "gamma", type: hSlider, min: 0.0, max: 5.0, init: 2.2, x: 60, y: 10, w: 200, h: 20, detents: LIST[[, 2.2]], proc: Gammaler]],
data: cmSave];
};
CmDither:
PUBLIC Commander.CommandProc ~ {
ImagerTerminal.SetStandardColorMap[InterminalBackdoor.terminal];
};
CmRamp:
PUBLIC Commander.CommandProc ~ {
args: ARRAY[0..8) OF Args.Arg;
FOR i:
INT
IN [0..8)
DO
args[i] ← Args.ArgIntRange[cmd, i, 0, 255];
IF NOT args[i].ok THEN RETURN[$Failure, "bad arguments"];
ENDLOOP;
ColorTrixMap.Ramp[args[0].int, args[1].int, args[2].int, args[3].int, args[4].int, args[5].int, args[6].int, args[7].int];
};
CmPrint:
PUBLIC Commander.CommandProc ~ {
cm: Cmap ← ColorTrixMap.Read[];
FOR i:
INT
IN [0..256)
DO
cmd.out.PutF["%3g:\t%3g\t%3g\t%3g\n", IO.int[i], IO.int[cm[0][i]], IO.int[cm[1][i]], IO.int[cm[2][i]]];
ENDLOOP;
};
CmOnly:
PUBLIC Commander.CommandProc ~ {
a: Rope.ROPE ← Args.GetRope[cmd];
IF a = NIL THEN RETURN[$Failure, "Only requires an argument"];
SELECT
TRUE
FROM
a.Equal["red"] => ColorTrixMap.PrimaryOnly[red];
a.Equal["green"] => ColorTrixMap.PrimaryOnly[green];
a.Equal["blue"] => ColorTrixMap.PrimaryOnly[blue];
ENDCASE => RETURN[$Failure, "argument one of: red, green, blue."];
};
CmTents:
PUBLIC Commander.CommandProc ~ {
a: Args.Arg ← Args.ArgInt[cmd];
IF a.ok THEN ColorTrixMap.Tents[a.int] ELSE RETURN[$Failure, "argument needed."];
};
CmSin:
PUBLIC Commander.CommandProc ~ {
a: Args.Arg;
v: ARRAY[0..2] OF REAL;
IF Args.NArgs[cmd] < 1 THEN RETURN[$Failure, "argument(s) needed."];
FOR i:
NAT
IN[0..2]
DO
a ← Args.ArgReal[cmd, i];
IF NOT a.ok AND i = 0 THEN RETURN[$Failure, "bad argument."];
v[i] ← IF a.ok THEN a.real ELSE v[i-1];
ENDLOOP;
ColorTrixMap.Sin[v[0], v[1], v[2]];
};
CmGauss:
PUBLIC Commander.CommandProc ~ {ColorTrixMap.Gauss[]};
CmColor:
PUBLIC Commander.CommandProc ~ {
i, r, g, b: Args.Arg;
IF NOT (i ← Args.ArgIntRange[cmd, 0, 0, 255]).ok THEN RETURN[$Failure, "bad arguments"];
IF NOT (r ← Args.ArgIntRange[cmd, 1, 0, 255]).ok THEN RETURN[$Failure, "bad arguments"];
IF NOT (g ← Args.ArgIntRange[cmd, 2, 0, 255]).ok THEN RETURN[$Failure, "bad arguments"];
IF NOT (b ← Args.ArgIntRange[cmd, 3, 0, 255]).ok THEN RETURN[$Failure, "bad arguments"];
ColorTrixMap.WriteEntry[i.int, r.int, g.int, b.int];
};
Cycler:
PROC [data: Controls.OuterData, cm: Cmap] ~ {
control: Controls.Control ← data.controls.first;
CedarProcess.SetPriority[background];
WHILE
NOT data.destroyed
DO
abs: REAL ← ABS[control.value];
n: INT ← MAX[1, Real.RoundI[abs]];
IF control.value = 0.0 THEN {Process.Pause[Process.MsecToTicks[100]]; LOOP};
ColorTrixMap.Write[ColorTrixMap.Cycle[cm, IF control.value > 0 THEN n ELSE -n]];
IF abs > 0.01 THEN Process.Pause[Process.MsecToTicks[Real.Round[100.0/abs]]];
ENDLOOP;
};
CmCycle:
PUBLIC Commander.CommandProc ~ {
cmSave: Cmap ← ColorTrixMap.Read[];
cm: Cmap ← ColorTrixMap.Copy[cmSave];
outer: Controls.Viewer ← Controls.OuterViewer[
name: "Cycle",
column: right,
buttons: standardButtonList,
controls: LIST[Controls.NewControl[type: hSlider, report: FALSE, x: 60, y: 10, w: 200, h: 20, min: -25.0, max: 25.0, init: 0.0, detents: LIST[[, 0.0]]]],
data: cmSave];
TRUSTED {Process.Detach[FORK Cycler[NARROW[outer.data], cm]]};
};
NBitser: Controls.ControlProc ~ {
cm: Cmap ← ColorTrixMap.ObtainCmap[];
ColorTrixMap.Mono[cm];
ColorTrixMap.NBits[cm, Real.Round[control.value]];
ColorTrixMap.ReleaseCmap[cm];
};
CmNBits:
PUBLIC Commander.CommandProc ~ {
arg: Args.Arg ← Args.ArgInt[cmd];
IF arg.ok
THEN ColorTrixMap.NBits[ColorTrixMap.Read[], arg.int]
ELSE [] ← Controls.OuterViewer[
name: "CmNBits",
column: right,
buttons: standardButtonList,
controls: LIST[Controls.NewControl[type: hSlider, x: 60, y: 10, w: 80, h: 20, min: 1.0, max: 8.0, init: 8.0, truncate: TRUE, proc: NBitser]],
data: ColorTrixMap.Read[]];
};
CmScale:
PUBLIC Commander.CommandProc ~ {
a: Args.Arg ← Args.ArgReal[cmd];
IF NOT a.ok THEN RETURN[$Failure, "argument needed."];
ColorTrixMap.Scale[ColorTrixMap.Read[], a.real];
};
CmAdd:
PUBLIC Commander.CommandProc ~ {
a: Args.Arg ← Args.ArgInt[cmd];
IF NOT a.ok THEN RETURN[$Failure, "argument needed."];
ColorTrixMap.Add[ColorTrixMap.Read[], a.int];
};
CmCompose:
PUBLIC Commander.CommandProc ~ {
cm1, cm2: Cmap;
ok1: BOOL ← ColorTrixMap.Load[Args.GetRope[cmd, 0], cm1 ← ColorTrixMap.NewCmap[]];
ok2: BOOL ← ColorTrixMap.Load[Args.GetRope[cmd, 1], cm2 ← ColorTrixMap.NewCmap[]];
IF NOT ok1 OR NOT ok2 THEN RETURN[$Failure, "bad color map name(s)."];
ColorTrixMap.Compose[cm1, cm2];
};
CmInterp:
PUBLIC Commander.CommandProc ~ {
cmLoad: Cmap ← ColorTrixMap.NewCmap[];
a: Args.Arg ← Args.ArgReal[cmd, 0];
IF
NOT a.ok
OR
NOT ColorTrixMap.Load[Args.GetRope[cmd, 1], cmLoad]
THEN RETURN[$Failure, "bad argument(s)."];
ColorTrixMap.Interp[a.real, cmLoad, ColorTrixMap.Read[]];
};
CmScramble:
PUBLIC Commander.CommandProc ~ {ColorTrixMap.Scramble[ColorTrixMap.Read[]]};
CmRandom:
PUBLIC Commander.CommandProc ~ {ColorTrixMap.Rand[]};
Shifter: Controls.ControlProc ~ {
cm: Cmap ← ColorTrixMap.ObtainCmap[];
shift: INTEGER ← Real.Round[control.valuePrev]-Real.Round[control.value];
ColorTrixMap.Write[ColorTrixMap.Cycle[ColorTrixMap.Read[cm], shift]];
ColorTrixMap.ReleaseCmap[cm];
};
ShiftRestore: Controls.ClickProc ~ {
outerData: OuterData ← NARROW[clientData];
ColorTrixMap.Write[NARROW[outerData.data]];
Controls.Reset[outerData.controls.first];
};
CmShift:
PUBLIC Commander.CommandProc ~ {
arg: Args.Arg ← Args.ArgInt[cmd];
cm: Cmap ← ColorTrixMap.Read[];
IF arg.ok
THEN ColorTrixMap.Write[ColorTrixMap.Cycle[ColorTrixMap.Read[], arg.int]]
ELSE [] ← Controls.OuterViewer[
name: "Shift",
column: right,
buttons: LIST[["Restore", ShiftRestore], ["Restore&Quit", RestoreAndQuit]],
destroyProc: Destroy,
controls: LIST[Controls.NewControl[type: dial, report: FALSE, x: 60, y: 10, w: 80, h: 80, min: 0.0, max: 255.0, init: 0.0, detents: LIST[[, 0.0]], proc: Shifter, data: cm]],
data: cm];
};
Speckler:
PROC [data: Controls.OuterData] ~ {
RandInt: PROC RETURNS [INTEGER] ~ {RETURN[Random.ChooseInt[max: 255]]};
CedarProcess.SetPriority[background];
WHILE
NOT data.destroyed
DO
Process.Pause[Process.MsecToTicks[Real.Round[100.0*data.controls.first.value]]];
ColorTrixMap.WriteEntry[RandInt[], RandInt[], RandInt[], RandInt[]];
ENDLOOP;
};
CmSpeckle:
PUBLIC Commander.CommandProc ~ {
cmSave: Cmap ← ColorTrixMap.Read[];
outer: Controls.Viewer ← Controls.OuterViewer[
name: "Speckle",
column: right,
buttons: standardButtonList,
controls:
LIST[Controls.NewControl[
type: hSlider, report: FALSE, x: 60, y: 10, w: 200, h: 20, min: 1.0, max: 0.0, init: 0.5]],
data: cmSave];
TRUSTED {Process.Detach[FORK Speckler[NARROW[outer.data]]]};
};
Flasher:
PROC [data: Controls.OuterData] ~ {
CedarProcess.SetPriority[background];
WHILE
NOT data.destroyed
DO
ColorTrixMap.Rand[];
Process.Pause[Process.MsecToTicks[Real.Round[1000.0*data.controls.first.value]]];
ENDLOOP;
};
CmFlash:
PUBLIC Commander.CommandProc ~ {
cmSave: Cmap ← ColorTrixMap.Read[];
outer: ViewerClasses.Viewer ← Controls.OuterViewer[
name: "Flash",
column: right,
buttons: standardButtonList,
controls: LIST[Controls.NewControl[type: hSlider, report: FALSE, x: 60, y: 10, w: 200, h: 20, min: 1.0, max: 0.0, init: 0.5]],
data: cmSave];
TRUSTED {Process.Detach[FORK Flasher[NARROW[outer.data]]]};
};
Rippler:
PROC [data: Controls.OuterData] ~ {
cmOut: Cmap ← ColorTrixMap.ObtainCmap[];
vals: ARRAY [0..2] OF REAL ← ALL[0.0];
cs: ARRAY [0..2] OF Controls.Control;
incs: ARRAY [0..2] OF INTEGER ← ALL[1];
cs[0] ← data.controls.first;
cs[1] ← data.controls.rest.first;
cs[2] ← data.controls.rest.rest.first;
CedarProcess.SetPriority[background];
DO
FOR i:
NAT
IN[0..2]
DO
IF vals[i] < 0.25 THEN incs[i] ← 1 ELSE IF vals[i] > 25.0 THEN incs[i] ← -1;
vals[i] ← vals[i]+incs[i]*cs[i].value;
ENDLOOP;
ColorTrixMap.Sin[vals[0], vals[1], vals[2], cmOut];
IF data.destroyed THEN EXIT;
ColorTrixMap.Write[cmOut];
ENDLOOP;
ColorTrixMap.ReleaseCmap[cmOut];
};
CmRipple:
PUBLIC Commander.CommandProc ~ {
cmSave: Cmap ← ColorTrixMap.Read[];
outer: ViewerClasses.Viewer ← Controls.OuterViewer[
name: "Ripple",
column: right,
buttons: standardButtonList,
controls:
LIST[
Controls.NewControl[type:hSlider,report:FALSE,x:60,y:10,w:200,h:20,min:0.,max:1.,init:0.5],
Controls.NewControl[type:hSlider,report:FALSE,x:60,y:40,w:200,h:20,min:0.,max:1.,init:0.5],
Controls.NewControl[type:hSlider,report:FALSE,x:60,y:70,w:200,h:20,min:0.,max:1.,init:0.5]],
data: cmSave];
TRUSTED {Process.Detach[FORK Rippler[NARROW[outer.data]]]};
};
rec: TYPE ~ RECORD [data: SEQUENCE num: NAT OF Cmap];
Blender:
PROC [d: Controls.OuterData, cm:
REF rec, ncm:
NAT] ~ {
inc: INTEGER ← 1;
n0, n1: INTEGER ← 0;
WHILE
NOT d.destroyed
DO
Process.CheckForAbort[];
IF (n1 ← n0+inc) = -1 OR n1 = ncm THEN {inc ← -inc; n1 ← n0+inc};
FOR t:
REAL ← 0, t+d.controls.first.value
WHILE t <= 0.5*3.1415926535
DO
IF d.destroyed THEN EXIT;
ColorTrixMap.Interp[RealFns.Sin[t], cm.data[n0], cm.data[n1]];
ENDLOOP;
n0 ← n1;
ENDLOOP;
};
CmBlend:
PUBLIC Commander.CommandProc ~ {
ncm: NAT ← 0;
outer: Controls.Viewer;
cmSave: Cmap ← ColorTrixMap.Read[];
cm: REF rec ← NEW[rec[Args.NArgs[cmd]]];
FOR a:
NAT
IN[0..Args.NArgs[cmd])
DO
Process.CheckForAbort[];
IF ColorTrixMap.Load[Args.GetRope[cmd, a], cm.data[ncm] ← ColorTrixMap.NewCmap[]]
THEN ncm ← ncm+1
ELSE cmd.out.PutF["Can't read %g\n", IO.rope[Args.GetRope[cmd, a]]];
ENDLOOP;
IF ncm = 0 THEN RETURN;
outer ← Controls.OuterViewer[
name: "Color Map Blender",
column: right,
buttons: standardButtonList,
controls: LIST[Controls.NewControl[type: hSlider, report: FALSE, x: 60, y: 10, w: 200, h: 20, min: 0.01, max: 1.0, init: 0.1]],
data: cmSave];
TRUSTED {Process.Detach[FORK Blender[NARROW[outer.data], cm, ncm]]};
};
Snaker:
PROC [data: Controls.OuterData] ~ {
r, g, b: REAL;
cm: Cmap ← ColorTrixMap.Read[];
CedarProcess.SetPriority[background];
WHILE
NOT data.destroyed
DO
[r, g, b] ← GetSnake[];
[] ← ColorTrixMap.Cycle[cm, 1];
ColorTrixMap.SetEntry[cm, 1, Real.RoundI[255*r], Real.RoundI[255*g], Real.RoundI[255*b]];
ColorTrixMap.Write[cm];
ENDLOOP;
};
CmSnake:
PUBLIC Commander.CommandProc ~ {
cmSave: Cmap ← ColorTrixMap.Read[];
outer: Controls.Viewer ← Controls.OuterViewer[
name: "Snake",
column: right,
buttons: standardButtonList,
data: cmSave];
TRUSTED {Process.Detach[FORK Snaker[NARROW[outer.data]]]};
};
r, g, b: Section;
Section: TYPE ~ RECORD [count: INTEGER ← 0, p, d: REAL ← 0.0];
GetSnake:
PROC
RETURNS [
REAL,
REAL,
REAL] ~ {
RandomReal:
PROC
RETURNS [
REAL] ~ {
RETURN[(1.0/1024.0)*REAL[Random.ChooseInt[min: 1, max: 1024]]];
};
NewSection:
PROC [p:
REAL]
RETURNS[s: Section] ~ {
s.p ← p;
s.count ← Random.ChooseInt[min: 5, max: 30];
s.d ← (RandomReal[]-p)/REAL[s.count];
};
IF (r.count ← r.count-1) <= 0 THEN r ← NewSection[r.p];
IF (g.count ← g.count-1) <= 0 THEN g ← NewSection[g.p];
IF (b.count ← b.count-1) <= 0 THEN b ← NewSection[b.p];
r.p ← MAX[0.0, MIN[1.0, r.p+r.d]];
g.p ← MAX[0.0, MIN[1.0, g.p+g.d]];
b.p ← MAX[0.0, MIN[1.0, b.p+b.d]];
RETURN[r.p, g.p, b.p];
};
CmContours:
PUBLIC Commander.CommandProc ~ {
ok: BOOL;
nCyclesArg, powerArg: Args.Arg;
twoPI: REAL ~ 2.0*3.1415926535;
halfPI: REAL ~ 0.5*3.1415926535;
[ok, nCyclesArg, powerArg] ← Args.ArgsGet[cmd, "-power%r-ncycles%r"];
IF ok
THEN {
nCycles: REAL ~ IF nCyclesArg.ok THEN nCyclesArg.real ELSE 4.0;
power: REAL ~ 1.0/(IF powerArg.ok THEN powerArg.real ELSE 6.0);
FOR n:
NAT
IN [0..255]
DO
cmapValue: INT;
t: REAL ~ REAL[n]/255.0;
intensity: REAL ← 0.5+0.5*RealFns.Sin[(nCycles*twoPI+halfPI)*RealFns.Power[t, power]];
intensity ← t+(1.0-t)*intensity;
cmapValue ← Real.RoundI[intensity*255.0];
ColorTrixMap.WriteEntry[n, cmapValue, cmapValue, cmapValue];
ENDLOOP;
ColorTrixMap.JustWritten[];
};
};
CmToOthers:
PUBLIC Commander.CommandProc ~ {
source: Rope.ROPE ~ Args.GetRope[cmd];
i0dst, i1dst, isrc: INT ← -1;
SELECT
TRUE
FROM
Rope.Equal[source, "red", FALSE] => {isrc ← 0; i0dst ← 1; i1dst ← 2};
Rope.Equal[source, "grn", FALSE] => {isrc ← 1; i0dst ← 0; i1dst ← 2};
Rope.Equal[source, "blu", FALSE] => {isrc ← 2; i0dst ← 0; i1dst ← 1};
ENDCASE;
IF isrc # -1
THEN {
cmap: ColorTrixMap.Cmap ← ColorTrixMap.Read[];
FOR n:
NAT
IN [0..255]
DO
cmap[i0dst][n] ← cmap[i1dst][n] ← cmap[isrc][n];
ENDLOOP;
ColorTrixMap.Write[cmap];
ColorTrixMap.JustWritten[];
};
};
Usage Messages
cmSaveUsage: ROPE ~ "Cm Save <color map name>.";
cmLoadUsage: ROPE ~ "Cm Load <color map name>.";
cmMonoUsage: ROPE ~ "Cm Mono: set the color map to a linear ramp.";
cmGammaUsage: ROPE ~ "Cm Gamma [value]: if no argument, interactive.";
cmDitherUsage: ROPE ~ "Cm Dither: set color to Imager.StandardMap.";
cmRampUsage: ROPE ~ "Cm Ramp <i0 r0 g0 b0 i1 r1 g1 b1>.";
cmPrintUsage: ROPE ~ "Cm Print: print the color map contents.";
cmOnlyUsage: ROPE ~ "Cm Only <red | green | blue>.";
cmTentsUsage: ROPE ~ "Cm Tents <nTents>.";
cmSinUsage: ROPE ~ "Cm Sin <nCycles>.";
cmGaussUsage: ROPE ~ "Cm Gauss: put a gaussian in color map.";
cmColorUsage: ROPE ~ "Cm Color <i r g b>: Set color map entry i.";
cmCycleUsage: ROPE ~ "Cm Cycle: interactively cycle color map.";
cmNBitsUsage: ROPE ~ "Cm NBits [nBits]: if no argument, interactive.";
cmScaleUsage: ROPE ~ "Cm Scale <scale>.";
cmAddUsage: ROPE ~ "Cm Add <offset>.";
cmComposeUsage: ROPE ~ "Cm Compose <cmap1 cmap2>: result ← c2[c1].";
cmInterpUsage: ROPE ~ "Cm Interp <t: REAL, cmap: ROPE>.";
cmScrambleUsage: ROPE ~ "Cm Scramble: randomly interchange entries.";
cmRandomUsage: ROPE ~ "Cm Random: randomize the color map.";
cmShiftUsage: ROPE ~ "Cm Shift [n]: in no argument, interactive.";
cmSpeckleUsage: ROPE ~ "Cm Speckle: randomly set single entries.";
cmFlashUsage: ROPE ~ "Cm Flash: interactively randomize color map.";
cmBlendUsage: ROPE ~ "Cm Blend <LIST of Cmap>: continuously blend.";
cmRippleUsage: ROPE ~ "Cm Ripple: interactively ripple sine waves.";
cmSnakeUsage: ROPE ~ "Cm Snake: snake through color space.";
cmToOthersUsage: ROPE ~ "Cm ToOthers <red | grn | blu> one component to other two.";
cmContoursUsage: ROPE ~ "Cm Contours [-power <real>] [-ncycles <real>] show contours.";
Start Code
ColorTrixDispatch.RegisterCmOp["Save", CmSave, cmSaveUsage];
ColorTrixDispatch.RegisterCmOp["Load", CmLoad, cmLoadUsage];
ColorTrixDispatch.RegisterCmOp["Mono", CmMono, cmMonoUsage];
ColorTrixDispatch.RegisterCmOp["Gamma", CmGamma, cmGammaUsage];
ColorTrixDispatch.RegisterCmOp["Dither", CmDither, cmDitherUsage];
ColorTrixDispatch.RegisterCmOp["Ramp", CmRamp, cmRampUsage];
ColorTrixDispatch.RegisterCmOp["Print", CmPrint, cmPrintUsage];
ColorTrixDispatch.RegisterCmOp["Only", CmOnly, cmOnlyUsage];
ColorTrixDispatch.RegisterCmOp["Tents", CmTents, cmTentsUsage];
ColorTrixDispatch.RegisterCmOp["Sin", CmSin, cmSinUsage];
ColorTrixDispatch.RegisterCmOp["Gauss", CmGauss, cmGaussUsage];
ColorTrixDispatch.RegisterCmOp["Color", CmColor, cmColorUsage];
ColorTrixDispatch.RegisterCmOp["Cycle", CmCycle, cmCycleUsage];
ColorTrixDispatch.RegisterCmOp["NBits", CmNBits, cmNBitsUsage];
ColorTrixDispatch.RegisterCmOp["Scale", CmScale, cmScaleUsage];
ColorTrixDispatch.RegisterCmOp["Add", CmAdd, cmAddUsage];
ColorTrixDispatch.RegisterCmOp["Compose", CmCompose, cmComposeUsage];
ColorTrixDispatch.RegisterCmOp["Interp", CmInterp, cmInterpUsage];
ColorTrixDispatch.RegisterCmOp["Scramble", CmScramble, cmScrambleUsage];
ColorTrixDispatch.RegisterCmOp["Random", CmRandom, cmRandomUsage];
ColorTrixDispatch.RegisterCmOp["Shift", CmShift, cmShiftUsage];
ColorTrixDispatch.RegisterCmOp["Speckle", CmSpeckle, cmSpeckleUsage];
ColorTrixDispatch.RegisterCmOp["Flash", CmFlash, cmFlashUsage];
ColorTrixDispatch.RegisterCmOp["Blend", CmBlend, cmBlendUsage];
ColorTrixDispatch.RegisterCmOp["Ripple", CmRipple, cmRippleUsage];
ColorTrixDispatch.RegisterCmOp["Snake", CmSnake, cmSnakeUsage];
ColorTrixDispatch.RegisterCmOp["ToOthers", CmToOthers, cmToOthersUsage];
ColorTrixDispatch.RegisterCmOp["Contours", CmContours, cmContoursUsage];