private void UpdateColorMapFromControls(bool forceUpdate = false) { if (colorMapEditorType != ColorMapEditorType.Controls) { return; } AllocateColorMapData(); if (forceUpdate || !colorMapEditorGradient.Equals(colorMapEditorGradientOld) || colorMapEditorContrast_ != colorMapEditorContrast || colorMapEditorBrightness_ != colorMapEditorBrightness || colorMapEditorPosterize_ != colorMapEditorPosterize) { colorMapEditorGradientOld.CopyFrom(colorMapEditorGradient); colorMapEditorContrast_ = colorMapEditorContrast; colorMapEditorBrightness_ = colorMapEditorBrightness; colorMapEditorPosterize_ = colorMapEditorPosterize; AllocateColorMapData(); // Populate colorMapData for (int i = 0; i < 256; i++) { // Apply contrast, brightness and posterization on the grayscale value double value = (double)i / 255.0; // Constrast and brightness double contrastFactor = colorMapEditorContrast + 1; // UI runs from -1 to 1 value = (value - 0.5) * contrastFactor + 0.5 + colorMapEditorBrightness; // Posterization if (colorMapEditorPosterize > 0.0f) { // The posterization slider feels more useful if the progression is exponential. The function is emprically tuned. const double posterizationBase = 50.0; double posterize = (Math.Pow(posterizationBase, colorMapEditorPosterize) - 1.0) / (posterizationBase - 1.0); value = Math.Round(value / posterize) * posterize; } // Clamp to [0, 1] value = Math.Min(Math.Max(value, 0.0), 1.0); // Map to value to color Color color = colorMapEditorGradient.Evaluate((float)value); WriteColorToColorMap(i, ref color); } styleDirty = true; } }