//
// This unit is part of the GLScene Engine https://github.com/glscene
//
{
  All color types, constants and utilities should go here

  History :
  06/06/07 - DaStr - separated from GLTexture.pas and GLCrossPlatform.pas
  The whole history is logged in previous version of the unit
}
unit GLColor;

interface

{$I GLScene.inc}

uses
  SysUtils, 
  Classes, 
  Dialogs, 
  Graphics,
   
  GLVectorTypes, 
  GLVectorGeometry, 
  GLCrossPlatform,
  GLPersistentClasses, 
  GLBaseClasses;

type
  PColorVector = ^TColorVector;
  TColorVector = TVector4f;

  PRGBColor = ^TRGBColor;
  TRGBColor = TVector3b;

   { Wraps an OpenGL color. }
   TGLColor = class(TGLUpdateAbleObject)
      private
         { Private Properties }
			FColor : TColorVector;
         FPDefaultColor : PColorVector;
			procedure SetColorVector(const aColor : TColorVector); overload;
			procedure SetColorComponent(index : Integer; value : Single);
      function GetColorComponent(const Index: Integer): Single;
			procedure SetAsWinColor(const val : TColor);
			function GetAsWinColor : TColor;
      procedure SetDirectColorVector(const AColor: TColorVector);

		protected
         { Protected Properties }
			procedure DefineProperties(Filer: TFiler); override;
			procedure ReadData(Stream: TStream);
			procedure WriteData(Stream: TStream);

         function GetHSVA : TVector;
         procedure SetHSVA(const hsva : TVector);

		public
         { Public Properties }
			constructor Create(AOwner : TPersistent); override;
			constructor CreateInitialized(AOwner : TPersistent; const color : TColorVector;
                                       changeEvent : TNotifyEvent = nil);
         destructor Destroy; override;
         procedure NotifyChange(Sender : TObject); override;
			procedure Assign(Source : TPersistent); override;
			procedure Initialize(const color : TColorVector);
			function AsAddress : PSingle;

         procedure RandomColor;
         procedure SetColor(red, green, blue : Single; alpha : Single = 1); overload;

			property Color : TColorVector read FColor write SetColorVector;
      property DirectColor : TColorVector read FColor write SetDirectColorVector;
			property AsWinColor : TColor read GetAsWinColor write SetAsWinColor;
         property HSVA : TVector read GetHSVA write SetHSVA;

         property DefaultColor : TColorVector read FColor;
 published
    property Red: Single index 0 read GetColorComponent
      write SetColorComponent;
    property Green: Single index 1 read GetColorComponent
      write SetColorComponent;
    property Blue: Single index 2 read GetColorComponent
      write SetColorComponent;
    property Alpha: Single index 3 read GetColorComponent
      write SetColorComponent;

	end;

   PColorEntry = ^TColorEntry;
   TColorEntry = record
                   Name  : String[31];
                   Color : TColorVector;
                 end;

   // TGLColorManager
   //
   TGLColorManager = class (TList)
      public
         destructor Destroy; override;
         procedure AddColor(const aName: String; const aColor: TColorVector);
         procedure EnumColors(Proc: TGetStrProc); overload;
         procedure EnumColors(AValues: TStrings); overload;

         function  FindColor(const aName: String): TColorVector;
         { Convert a clrXxxx or a '<red green blue alpha> to a color vector }
         function  GetColor(const aName: String): TColorVector;
         function  GetColorName(const aColor: TColorVector): String;
         procedure RegisterDefaultColors;
         procedure RemoveColor(const aName: String);
   end;

function ColorManager: TGLColorManager;

procedure RegisterColor(const aName : String; const aColor : TColorVector);
procedure UnRegisterColor(const aName : String);


function GetRValue(rgb: DWORD): Byte;  {$NODEFINE GetRValue}
function GetGValue(rgb: DWORD): Byte;  {$NODEFINE GetGValue}
function GetBValue(rgb: DWORD): Byte;  {$NODEFINE GetBValue}

procedure InitGLSceneColors;
{ Converts a delphi color into its RGB fragments and correct range. }
function ConvertWinColor(aColor: TColor; alpha : Single = 1) : TColorVector;

// Converts a color vector (containing float values)
function ConvertColorVector(const AColor: TColorVector): TColor; overload;
{ Converts a color vector (containing float values) and alter intensity.
   intensity is in [0..1] }
function ConvertColorVector(const AColor: TColorVector; intensity: Single): TColor; overload;
// Converts RGB components into a color vector with correct range
function ConvertRGBColor(const aColor: array of Byte): TColorVector;

// color definitions
const
  // Some extra colors, not declared in Graphics.pas
  clForeground = TColor(-1);
  clButton = TColor(-2);
  clLight = TColor(-3);
  clMidlight = TColor(-4);
  clDark = TColor(-5);
  clMid = TColor(-6);
  clText = TColor(-7);
  clBrightText = TColor(-8);
  clButtonText = TColor(-9);
  clBase = TColor(-10);
  clBackground = TColor(-11);
  clShadow = TColor(-12);
  clHighlight = TColor(-13);
  clHighlightedText = TColor(-14);

  { Mapped role offsets }
  cloNormal = 32;
  cloDisabled = 64;
  cloActive = 96;

  { Normal, mapped, pseudo, rgb values }
  clNormalForeground = TColor(clForeground - cloNormal);
  clNormalButton = TColor(clButton - cloNormal);
  clNormalLight = TColor(clLight - cloNormal);
  clNormalMidlight = TColor(clMidlight - cloNormal);
  clNormalDark = TColor(clDark - cloNormal);
  clNormalMid = TColor(clMid - cloNormal);
  clNormalText = TColor(clText - cloNormal);
  clNormalBrightText = TColor(clBrightText - cloNormal);
  clNormalButtonText = TColor(clButtonText - cloNormal);
  clNormalBase = TColor(clBase - cloNormal);
  clNormalBackground = TColor(clBackground - cloNormal);
  clNormalShadow = TColor(clShadow - cloNormal);
  clNormalHighlight = TColor(clHighlight - cloNormal);
  clNormalHighlightedText = TColor(clHighlightedText - cloNormal);

  { Disabled, mapped, pseudo, rgb values }
  clDisabledForeground = TColor(clForeground - cloDisabled);
  clDisabledButton = TColor(clButton - cloDisabled);
  clDisabledLight = TColor(clLight - cloDisabled);
  clDisabledMidlight = TColor(clMidlight - cloDisabled);
  clDisabledDark = TColor(clDark - cloDisabled);
  clDisabledMid = TColor(clMid - cloDisabled);
  clDisabledText = TColor(clText - cloDisabled);
  clDisabledBrightText = TColor(clBrightText - cloDisabled);
  clDisabledButtonText = TColor(clButtonText - cloDisabled);
  clDisabledBase = TColor(clBase - cloDisabled);
  clDisabledBackground = TColor(clBackground - cloDisabled);
  clDisabledShadow = TColor(clShadow - cloDisabled);
  clDisabledHighlight = TColor(clHighlight - cloDisabled);
  clDisabledHighlightedText = TColor(clHighlightedText - cloDisabled);

  { Active, mapped, pseudo, rgb values }
  clActiveForeground = TColor(clForeground - cloActive);
  clActiveButton = TColor(clButton - cloActive);
  clActiveLight = TColor(clLight - cloActive);
  clActiveMidlight = TColor(clMidlight - cloActive);
  clActiveDark = TColor(clDark - cloActive);
  clActiveMid = TColor(clMid - cloActive);
  clActiveText = TColor(clText - cloActive);
  clActiveBrightText = TColor(clBrightText - cloActive);
  clActiveButtonText = TColor(clButtonText - cloActive);
  clActiveBase = TColor(clBase - cloActive);
  clActiveBackground = TColor(clBackground - cloActive);
  clActiveShadow = TColor(clShadow - cloActive);
  clActiveHighlight = TColor(clHighlight - cloActive);
  clActiveHighlightedText = TColor(clHighlightedText - cloActive);

  clFirstSpecialColor = clActiveHighlightedText;
  clMask = clWhite;
  clDontMask = clBlack;

// Window's colors (must be filled at program
// startup, since they depend on the desktop scheme)
const
   {$J+ - allow change of the following typed constants}
   clrScrollBar           : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrBackground          : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrActiveCaption       : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrInactiveCaption     : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrMenu                : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrWindow              : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrWindowFrame         : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrMenuText            : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrWindowText          : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrCaptionText         : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrActiveBorder        : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrInactiveBorder      : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrAppWorkSpace        : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrHighlight           : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrHighlightText       : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrBtnFace             : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrBtnShadow           : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrGrayText            : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrBtnText             : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrInactiveCaptionText : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrBtnHighlight        : TColorVector = (X:0;Y:0;Z:0;W:1);
   clr3DDkShadow          : TColorVector = (X:0;Y:0;Z:0;W:1);
   clr3DLight             : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrInfoText            : TColorVector = (X:0;Y:0;Z:0;W:1);
   clrInfoBk              : TColorVector = (X:0;Y:0;Z:0;W:1);

   {$J- - disable change of other typed constants}

   // 'static' color definitions
   // sort of grays
   clrTransparent         : TColorVector = (X:0;    Y:0;    Z:0;    W:0);
   clrBlack               : TColorVector = (X:0;    Y:0;    Z:0;    W:1);
   clrGray05              : TColorVector = (X:0.05; Y:0.05; Z:0.05; W:1);
   clrGray10              : TColorVector = (X:0.10; Y:0.10; Z:0.10; W:1);
   clrGray15              : TColorVector = (X:0.15; Y:0.15; Z:0.15; W:1);
   clrGray20              : TColorVector = (X:0.20; Y:0.20; Z:0.20; W:1);
   clrGray25              : TColorVector = (X:0.25; Y:0.25; Z:0.25; W:1);
   clrGray30              : TColorVector = (X:0.30; Y:0.30; Z:0.30; W:1);
   clrGray35              : TColorVector = (X:0.35; Y:0.35; Z:0.35; W:1);
   clrGray40              : TColorVector = (X:0.40; Y:0.40; Z:0.40; W:1);
   clrGray45              : TColorVector = (X:0.45; Y:0.45; Z:0.45; W:1);
   clrGray50              : TColorVector = (X:0.50; Y:0.50; Z:0.50; W:1);
   clrGray55              : TColorVector = (X:0.55; Y:0.55; Z:0.55; W:1);
   clrGray60              : TColorVector = (X:0.60; Y:0.60; Z:0.60; W:1);
   clrGray65              : TColorVector = (X:0.65; Y:0.65; Z:0.65; W:1);
   clrGray70              : TColorVector = (X:0.70; Y:0.70; Z:0.70; W:1);
   clrGray75              : TColorVector = (X:0.75; Y:0.75; Z:0.75; W:1);
   clrGray80              : TColorVector = (X:0.80; Y:0.80; Z:0.80; W:1);
   clrGray85              : TColorVector = (X:0.85; Y:0.85; Z:0.85; W:1);
   clrGray90              : TColorVector = (X:0.90; Y:0.90; Z:0.90; W:1);
   clrGray95              : TColorVector = (X:0.95; Y:0.95; Z:0.95; W:1);
   clrWhite               : TColorVector = (X:1;    Y:1;    Z:1;    W:1);

   // other grays
   clrDimGray             : TColorVector = (X:0.329412; Y:0.329412; Z:0.329412; W:1);
   clrGray                : TColorVector = (X:0.752941; Y:0.752941; Z:0.752941; W:1);
   clrLightGray           : TColorVector = (X:0.658824; Y:0.658824; Z:0.658824; W:1);

   // colors en masse
   clrAquamarine          : TColorVector = (X:0.439216; Y:0.858824; Z:0.576471; W:1);
   clrBlueViolet          : TColorVector = (X:0.62352;  Y:0.372549; Z:0.623529; W:1);
   clrBrown               : TColorVector = (X:0.647059; Y:0.164706; Z:0.164706; W:1);
   clrCadetBlue           : TColorVector = (X:0.372549; Y:0.623529; Z:0.623529; W:1);
   clrCoral               : TColorVector = (X:1;        Y:0.498039; Z:0.0;      W:1);
   clrCornflowerBlue      : TColorVector = (X:0.258824; Y:0.258824; Z:0.435294; W:1);
   clrDarkGreen           : TColorVector = (X:0.184314; Y:0.309804; Z:0.184314; W:1);
   clrDarkOliveGreen      : TColorVector = (X:0.309804; Y:0.309804; Z:0.184314; W:1);
   clrDarkOrchid          : TColorVector = (X:0.6;      Y:0.196078; Z:0.8;      W:1);
   clrDarkSlateBlue       : TColorVector = (X:0.419608; Y:0.137255; Z:0.556863; W:1);
   clrDarkSlateGray       : TColorVector = (X:0.184314; Y:0.309804; Z:0.309804; W:1);
   clrDarkSlateGrey       : TColorVector = (X:0.184314; Y:0.309804; Z:0.309804; W:1);
   clrDarkTurquoise       : TColorVector = (X:0.439216; Y:0.576471; Z:0.858824; W:1);
   clrFirebrick           : TColorVector = (X:0.556863; Y:0.137255; Z:0.137255; W:1);
   clrForestGreen         : TColorVector = (X:0.137255; Y:0.556863; Z:0.137255; W:1);
   clrGold                : TColorVector = (X:0.8;      Y:0.498039; Z:0.196078; W:1);
   clrGoldenrod           : TColorVector = (X:0.858824; Y:0.858824; Z:0.439216; W:1);
   clrGreenYellow         : TColorVector = (X:0.576471; Y:0.858824; Z:0.439216; W:1);
   clrIndian              : TColorVector = (X:0.309804; Y:0.184314; Z:0.184314; W:1);
   clrKhaki               : TColorVector = (X:0.623529; Y:0.623529; Z:0.372549; W:1);
   clrLightBlue           : TColorVector = (X:0.74902;  Y:0.847059; Z:0.847059; W:1);
   clrLightSteelBlue      : TColorVector = (X:0.560784; Y:0.560784; Z:0.737255; W:1);
   clrLimeGreen           : TColorVector = (X:0.196078; Y:0.8;      Z:0.196078; W:1);
   clrMaroon              : TColorVector = (X:0.556863; Y:0.137255; Z:0.419608; W:1);
   clrMediumAquamarine    : TColorVector = (X:0.196078; Y:0.8;      Z:0.6;      W:1);
   clrMediumBlue          : TColorVector = (X:0.196078; Y:0.196078; Z:0.8;      W:1);
   clrMediumForestGreen   : TColorVector = (X:0.419608; Y:0.556863; Z:0.137255; W:1);
   clrMediumGoldenrod     : TColorVector = (X:0.917647; Y:0.917647; Z:0.678431; W:1);
   clrMediumOrchid        : TColorVector = (X:0.576471; Y:0.439216; Z:0.858824; W:1);
   clrMediumSeaGreen      : TColorVector = (X:0.258824; Y:0.435294; Z:0.258824; W:1);
   clrMediumSlateBlue     : TColorVector = (X:0.498039; Y:0;        Z:1;        W:1);
   clrMediumSpringGreen   : TColorVector = (X:0.498039; Y:1;        Z:0;        W:1);
   clrMediumTurquoise     : TColorVector = (X:0.439216; Y:0.858824; Z:0.858824; W:1);
   clrMediumViolet        : TColorVector = (X:0.858824; Y:0.439216; Z:0.576471; W:1);
   clrMidnightBlue        : TColorVector = (X:0.184314; Y:0.184314; Z:0.309804; W:1);
   clrNavy                : TColorVector = (X:0.137255; Y:0.137255; Z:0.556863; W:1);
   clrNavyBlue            : TColorVector = (X:0.137255; Y:0.137255; Z:0.556863; W:1);
   clrOrange              : TColorVector = (X:1;        Y:0.5;      Z:0.0;      W:1);
   clrOrangeRed           : TColorVector = (X:1;        Y:0.25;     Z:0;        W:1);
   clrOrchid              : TColorVector = (X:0.858824; Y:0.439216; Z:0.858824; W:1);
   clrPaleGreen           : TColorVector = (X:0.560784; Y:0.737255; Z:0.560784; W:1);
   clrPink                : TColorVector = (X:0.737255; Y:0.560784; Z:0.560784; W:1);
   clrPlum                : TColorVector = (X:0.917647; Y:0.678431; Z:0.917647; W:1);
   clrSalmon              : TColorVector = (X:0.435294; Y:0.258824; Z:0.258824; W:1);
   clrSeaGreen            : TColorVector = (X:0.137255; Y:0.556863; Z:0.419608; W:1);
   clrSienna              : TColorVector = (X:0.556863; Y:0.419608; Z:0.137255; W:1);
   clrSkyBlue             : TColorVector = (X:0.196078; Y:0.6;      Z:0.8;      W:1);
   clrSlateBlue           : TColorVector = (X:0;        Y:0.498039; Z:1;        W:1);
   clrSpringGreen         : TColorVector = (X:0;        Y:1;        Z:0.498039; W:1);
   clrSteelBlue           : TColorVector = (X:0.137255; Y:0.419608; Z:0.556863; W:1);
   clrTan                 : TColorVector = (X:0.858824; Y:0.576471; Z:0.439216; W:1);
   clrThistle             : TColorVector = (X:0.847059; Y:0.74902;  Z:0.847059; W:1);
   clrTurquoise           : TColorVector = (X:0.678431; Y:0.917647; Z:0.917647; W:1);
   clrViolet              : TColorVector = (X:0.309804; Y:0.184314; Z:0.309804; W:1);
   clrVioletRed           : TColorVector = (X:0.8;      Y:0.196078; Z:0.6;      W:1);
   clrWheat               : TColorVector = (X:0.847059; Y:0.847059; Z:0.74902;  W:1);
   clrYellowGreen         : TColorVector = (X:0.6;      Y:0.8;      Z:0.196078; W:1);
   clrSummerSky           : TColorVector = (X:0.22;     Y:0.69;     Z:0.87;     W:1);
   clrRichBlue            : TColorVector = (X:0.35;     Y:0.35;     Z:0.67;     W:1);
   clrBrass               : TColorVector = (X:0.71;     Y:0.65;     Z:0.26;     W:1);
   clrCopper              : TColorVector = (X:0.72;     Y:0.45;     Z:0.20;     W:1);
   clrBronze              : TColorVector = (X:0.55;     Y:0.47;     Z:0.14;     W:1);
   clrBronze2             : TColorVector = (X:0.65;     Y:0.49;     Z:0.24;     W:1);
   clrSilver              : TColorVector = (X:0.90;     Y:0.91;     Z:0.98;     W:1);
   clrBrightGold          : TColorVector = (X:0.85;     Y:0.85;     Z:0.10;     W:1);
   clrOldGold             : TColorVector = (X:0.81;     Y:0.71;     Z:0.23;     W:1);
   clrFeldspar            : TColorVector = (X:0.82;     Y:0.57;     Z:0.46;     W:1);
   clrQuartz              : TColorVector = (X:0.85;     Y:0.85;     Z:0.95;     W:1);
   clrNeonPink            : TColorVector = (X:1.00;     Y:0.43;     Z:0.78;     W:1);
   clrDarkPurple          : TColorVector = (X:0.53;     Y:0.12;     Z:0.47;     W:1);
   clrNeonBlue            : TColorVector = (X:0.30;     Y:0.30;     Z:1.00;     W:1);
   clrCoolCopper          : TColorVector = (X:0.85;     Y:0.53;     Z:0.10;     W:1);
   clrMandarinOrange      : TColorVector = (X:0.89;     Y:0.47;     Z:0.20;     W:1);
   clrLightWood           : TColorVector = (X:0.91;     Y:0.76;     Z:0.65;     W:1);
   clrMediumWood          : TColorVector = (X:0.65;     Y:0.50;     Z:0.39;     W:1);
   clrDarkWood            : TColorVector = (X:0.52;     Y:0.37;     Z:0.26;     W:1);
   clrSpicyPink           : TColorVector = (X:1.00;     Y:0.11;     Z:0.68;     W:1);
   clrSemiSweetChoc       : TColorVector = (X:0.42;     Y:0.26;     Z:0.15;     W:1);
   clrBakersChoc          : TColorVector = (X:0.36;     Y:0.20;     Z:0.09;     W:1);
   clrFlesh               : TColorVector = (X:0.96;     Y:0.80;     Z:0.69;     W:1);
   clrNewTan              : TColorVector = (X:0.92;     Y:0.78;     Z:0.62;     W:1);
   clrNewMidnightBlue     : TColorVector = (X:0.00;     Y:0.00;     Z:0.61;     W:1);
   clrVeryDarkBrown       : TColorVector = (X:0.35;     Y:0.16;     Z:0.14;     W:1);
   clrDarkBrown           : TColorVector = (X:0.36;     Y:0.25;     Z:0.20;     W:1);
   clrDarkTan             : TColorVector = (X:0.59;     Y:0.41;     Z:0.31;     W:1);
   clrGreenCopper         : TColorVector = (X:0.32;     Y:0.49;     Z:0.46;     W:1);
   clrDkGreenCopper       : TColorVector = (X:0.29;     Y:0.46;     Z:0.43;     W:1);
   clrDustyRose           : TColorVector = (X:0.52;     Y:0.39;     Z:0.39;     W:1);
   clrHuntersGreen        : TColorVector = (X:0.13;     Y:0.37;     Z:0.31;     W:1);
   clrScarlet             : TColorVector = (X:0.55;     Y:0.09;     Z:0.09;     W:1);
   clrMediumPurple        : TColorVector = (X:0.73;     Y:0.16;     Z:0.96;     W:1);
   clrLightPurple         : TColorVector = (X:0.87;     Y:0.58;     Z:0.98;     W:1);
   clrVeryLightPurple     : TColorVector = (X:0.94;     Y:0.81;     Z:0.99;     W:1);
   clrGreen               : TColorVector = (X:0;        Y:0.5;      Z:0;        W:1);
   clrOlive               : TColorVector = (X:0.5;      Y:0.5;      Z:1;        W:1);
   clrPurple              : TColorVector = (X:1;        Y:0;        Z:1;        W:1);
   clrTeal                : TColorVector = (X:0;        Y:0.5;      Z:0.5;      W:1);
   clrRed                 : TColorVector = (X:1;        Y:0;        Z:0;        W:1);
   clrLime                : TColorVector = (X:0;        Y:1;        Z:0;        W:1);
   clrYellow              : TColorVector = (X:1;        Y:1;        Z:0;        W:1);
   clrBlue                : TColorVector = (X:0;        Y:0;        Z:1;        W:1);
   clrFuchsia             : TColorVector = (X:1;        Y:0;        Z:1;        W:1);
   clrAqua                : TColorVector = (X:0;        Y:1;        Z:1;        W:1);

   cDefaultNormalMapScale = 0.125;

{$J- - disallow change of the following typed constants}

var
   // Specifies if TGLColor should allocate memory for
   // their default values (ie. design-time) or not (run-time)
   vUseDefaultColorSets : Boolean = False;

implementation

var
	vColorManager : TGLColorManager;

// ColorManager
//
function ColorManager : TGLColorManager;
begin
	if not Assigned(vColorManager) then begin
		vColorManager:=TGLColorManager.Create;
		vColorManager.RegisterDefaultColors;
	end;
	Result:=vColorManager;
end;


// ConvertWinColor
//



function ConvertWinColor(aColor: TColor; alpha: Single = 1): TColorVector;
var
  winColor: Integer;
begin
  // Delphi color to Windows color
  winColor := aColor and $FFFFFF; //ColorToRGB(aColor);
  // convert 0..255 range into 0..1 range
  Result.V[0] := (winColor and $FF) * (1 / 255);
  Result.V[1] := ((winColor shr 8) and $FF) * (1 / 255);
  Result.V[2] := ((winColor shr 16) and $FF) * (1 / 255);
  Result.V[3] := alpha;
end;

// GetRValue
//
function GetRValue(rgb: DWORD): Byte;
begin
  Result := Byte(rgb);
end;

// GetGValue
//
function GetGValue(rgb: DWORD): Byte;
begin
  Result := Byte(rgb shr 8);
end;

// GetBValue
//
function GetBValue(rgb: DWORD): Byte;
begin
  Result := Byte(rgb shr 16);
end;

// InitGLSceneColors
//
procedure InitGLSceneColors;
begin
  clrScrollBar := ConvertWinColor(clScrollBar);
  clrActiveCaption := ConvertWinColor(clActiveCaption);
  clrInactiveCaption := ConvertWinColor(clInactiveCaption);
  clrMenu := ConvertWinColor(clMenu);
  clrWindow := ConvertWinColor(clWindow);
  clrWindowFrame := ConvertWinColor(clWindowFrame);
  clrMenuText := ConvertWinColor(clMenuText);
  clrWindowText := ConvertWinColor(clWindowText);
  clrCaptionText := ConvertWinColor(clCaptionText);
  clrActiveBorder := ConvertWinColor(clActiveBorder);
  clrInactiveBorder := ConvertWinColor(clInactiveBorder);
  clrAppWorkSpace := ConvertWinColor(clAppWorkSpace);
  clrHighlightText := ConvertWinColor(clHighlightText);
  clrBtnFace := ConvertWinColor(clBtnFace);
  clrBtnShadow := ConvertWinColor(clBtnShadow);
  clrGrayText := ConvertWinColor(clGrayText);
  clrBtnText := ConvertWinColor(clBtnText);
  clrInactiveCaptionText := ConvertWinColor(clInactiveCaptionText);
  clrBtnHighlight := ConvertWinColor(clBtnHighlight);
  clr3DDkShadow := ConvertWinColor(cl3DDkShadow);
  clr3DLight := ConvertWinColor(cl3DLight);
  clrInfoText := ConvertWinColor(clInfoText);
  clrInfoBk := ConvertWinColor(clInfoBk);
  {$ifndef LCLGTK2}
  clrHighlight := ConvertWinColor(clHighlight);
  clrBackground := ConvertWinColor(clBackground);
  {$ENDIF}
end;

// ConvertColorVector
//
function ConvertColorVector(const aColor: TColorVector): TColor;
begin
  Result := RGB(
    Round(255 * aColor.V[0]),
    Round(255 * aColor.V[1]),
    Round(255 * aColor.V[2]));
end;

// ConvertColorVector
//
function ConvertColorVector(const aColor: TColorVector; intensity: Single): TColor;
begin
  intensity := 255 * intensity;
  Result := RGB(Round(intensity * aColor.V[0]),
    Round(intensity * aColor.V[1]),
    Round(intensity * aColor.V[2]));
end;

// ConvertRGBColor
//
function ConvertRGBColor(const aColor: array of Byte): TColorVector;
var
  n: Integer;
begin
  // convert 0..255 range into 0..1 range
  n := High(AColor);
  Result.V[0] := AColor[0] * (1 / 255);
  if n > 0 then
    Result.V[1] := AColor[1] * (1 / 255)
  else
    Result.V[1] := 0;
  if n > 1 then
    Result.V[2] := AColor[2] * (1 / 255)
  else
    Result.V[2] := 0;
  if n > 2 then
    Result.V[3] := AColor[3] * (1 / 255)
  else
    Result.V[3] := 1;
end;

// ------------------
// ------------------ TGLColor ------------------
// ------------------

// Create
//
constructor TGLColor.Create(AOwner: TPersistent);
begin
   inherited;
   Initialize(clrBlack);
end;

// CreateInitialized
//
constructor TGLColor.CreateInitialized(AOwner : TPersistent; const color : TColorVector;
                                       changeEvent : TNotifyEvent = nil);
begin
   Create(AOwner);
   Initialize(color);
   OnNotifyChange:=changeEvent;
end;

// Destroy
//
destructor TGLColor.Destroy;
begin
   if assigned(FPDefaultColor) then Dispose(FPDefaultColor);
   inherited;
end;

// Initialize
//
procedure TGLColor.Initialize(const color : TColorVector);
begin
   SetVector(FColor, color);
   if vUseDefaultColorSets then
   begin
      if not assigned(FPDefaultColor) then
         New(FPDefaultColor);
      SetVector(FPDefaultColor^, color);
   end;
end;

// SetColorVector
//
procedure TGLColor.SetColorVector(const aColor : TColorVector);
begin
   SetVector(FColor, AColor);
	NotifyChange(Self);
end;

procedure TGLColor.SetDirectColorVector(const AColor: TColorVector);
begin
  SetVector(FColor, AColor);
end;

// SetColorComponent
//
procedure TGLColor.SetColorComponent(index : Integer; value : Single);
begin
	if FColor.V[index]<>value then begin
		FColor.V[index]:=value;
		NotifyChange(Self);
	end;
end;

// SetAsWinColor
//
procedure TGLColor.SetAsWinColor(const val : TColor);
begin
	FColor:=ConvertWinColor(val);
	NotifyChange(Self);
end;

// GetAsWinColor
//
function TGLColor.GetAsWinColor : TColor;
begin
	Result:=ConvertColorVector(FColor);
end;

// GetColorComponent
//
function TGLColor.GetColorComponent(const Index: Integer): Single;
begin
  Result := FColor.V[Index];
end;

 
//
procedure TGLColor.Assign(Source: TPersistent);
begin
   if Assigned(Source) and (Source is TGLColor) then begin
		FColor:=TGLColor(Source).FColor;
      NotifyChange(Self);
   end else inherited;
end;

// DefineProperties
//
procedure TGLColor.DefineProperties(Filer: TFiler);
begin
  inherited;
  Filer.DefineBinaryProperty('Color', ReadData, WriteData,
                             not (Assigned(FPDefaultColor) and VectorEquals(FColor, FPDefaultColor^)));
end;

// ReadData
//
procedure TGLColor.ReadData(Stream: TStream);
begin
   Stream.Read(FColor, SizeOf(FColor));
end;

// WriteData
//
procedure TGLColor.WriteData(Stream: TStream);
begin
   Stream.Write(FColor, SizeOf(FColor));
end;

// NotifyChange
//
procedure TGLColor.NotifyChange(Sender : TObject);
var
  intf: IGLNotifyable;
begin
   if Assigned(Owner) then begin
      if Supports(Owner,IGLNotifyable, intf) then
        intf.NotifyChange(Self);
//      if Owner is TGLBaseSceneObject then
//         TGLBaseSceneObject(Owner).StructureChanged;
      inherited;
   end;
end;

// AsAddress
//
function TGLColor.AsAddress: PSingle;
begin
	Result:=@FColor;
end;

// RandomColor
//
procedure TGLColor.RandomColor;
begin
   Red:=Random;
   Green:=Random;
   Blue:=Random;
end;

// SetColor
//
procedure TGLColor.SetColor(red, green, blue : Single; alpha : Single = 1);
begin
   FColor.V[0]:=red;
   FColor.V[1]:=Green;
   FColor.V[2]:=blue;
   FColor.V[3]:=alpha;
   NotifyChange(Self);
end;

// GetHSVA
//
function TGLColor.GetHSVA : TVector;
var
   delta, min : Single;
const
   H = 0;
   S = 1;
   V = 2;
begin
   min:=MinFloat(PFloatVector(@FColor), 3);
   Result.V[V]:=MaxFloat(PFloatVector(@FColor), 3);
   delta:=Result.V[V]-min;

  // saturation is zero if R, G & B are zero
  // hue undefined (zero) if saturation is zero or color is gray (delta=zero)
   if (Result.V[V]=0) or (delta=0) then begin
      Result.V[S]:=0;
      Result.V[H]:=0;
   end else begin
      Result.V[S]:=delta/Result.V[V];
      if Red=Result.V[V] then
         // between yellow and magenta
         Result.V[H]:=60*(Green-Blue)/delta
      else if Green=Result.V[V] then
         // between cyan and yellow
         Result.V[H]:=120+60*(Blue-Red)/delta
      else // between magenta and cyan
         Result.V[H]:=240+60*(Red-Green)/delta;
      if Result.V[H]<0 then  // normalize H
         Result.V[H]:=Result.V[H]+360;
   end;
   Result.V[3]:=Alpha;
end;

// SetHSVA
//
procedure TGLColor.SetHSVA(const hsva : TVector);
var
   f, hTemp, p, q, t : Single;
const
   H = 0;
   S = 1;
   V = 2;
begin
   if hsva.V[S]=0 then begin
      // gray (ignore hue)
      FColor.V[0]:=hsva.V[V];
      FColor.V[1]:=hsva.V[V];
      FColor.V[2]:=hsva.V[V];
   end else begin
      hTemp:=hsva.V[H]*(1/60);
      f:=Frac(hTemp);

      p:=hsva.V[V]*(1-hsva.V[S]);
      q:=hsva.V[V]*(1-(hsva.V[S]*f));
      t:=hsva.V[V]*(1-(hsva.V[S]*(1-f)));

      case Trunc(hTemp) mod 6 of
         0 : begin
            FColor.V[0]:=hsva.V[V];
            FColor.V[1]:=t;
            FColor.V[2]:=p;
         end;
         1 : begin
            FColor.V[0]:=q;
            FColor.V[1]:=hsva.V[V];
            FColor.V[2]:=p;
         end;
         2 : begin
            FColor.V[0]:=p;
            FColor.V[1]:=hsva.V[V];
            FColor.V[2]:=t;
         end;
         3 : begin
            FColor.V[0]:=p;
            FColor.V[1]:=q;
            FColor.V[2]:=hsva.V[V];
         end;
         4 : begin
            FColor.V[0]:=t;
            FColor.V[1]:=p;
            FColor.V[2]:=hsva.V[V];
         end;
         5 : begin
            FColor.V[0]:=hsva.V[V];
            FColor.V[1]:=p;
            FColor.V[2]:=q;
         end;
      end
   end;
   FColor.V[3]:=hsva.V[3];
   NotifyChange(Self);
end;

// ------------------
// ------------------ TGLColorManager ------------------
// ------------------

// Find Color
//
function TGLColorManager.FindColor(const aName: String): TColorVector;
var
   i : Integer;
begin
   Result:=clrBlack;
   for i:=0 to Count-1 do
      if CompareText(string(TColorEntry(Items[i]^).Name), AName)=0 then begin
         SetVector(Result, TColorEntry(Items[i]^).Color);
         Break;
      end;
end;

// GetColor
//
function TGLColorManager.GetColor(const aName : String): TColorVector;
var
   workCopy  : String;
   delimiter : Integer;
begin
   if aName='' then
      Result:=clrBlack
   else begin
      workCopy:=Trim(AName);
      if CharInSet(AName[1], ['(','[','<']) then
         workCopy:=Copy(workCopy, 2, Length(AName)-2);
      if CompareText(Copy(workCopy,1,3),'clr')=0 then
         SetVector(Result, FindColor(workCopy))
      else try
         // initialize result
         Result:=clrBlack;
         workCopy:=Trim(workCopy);
         delimiter:=Pos(' ', workCopy);
         if (Length(workCopy)>0) and (delimiter>0) then begin
            Result.V[0]:=StrToFloat(Copy(workCopy, 1, delimiter-1));
            System.Delete(workCopy, 1, delimiter);
            workCopy:=TrimLeft(workCopy);
            delimiter:=Pos(' ',workCopy);
            if (Length(workCopy)>0) and (delimiter>0) then begin
               Result.V[1]:=StrToFloat(Copy(workCopy, 1, delimiter-1));
               System.Delete(workCopy, 1, delimiter);
               workCopy:=TrimLeft(workCopy);
               delimiter:=Pos(' ', workCopy);
               if (Length(workCopy)>0) and (delimiter>0) then begin
                  Result.V[2]:=StrToFloat(Copy(workCopy, 1, delimiter-1));
                  System.Delete(workCopy, 1, delimiter);
                  workCopy:=TrimLeft(workCopy);
                  Result.V[3]:=StrToFloat(workCopy);
               end else Result.V[2]:=StrToFloat(workCopy);
            end else Result.V[1]:=StrToFloat(workCopy);
         end else Result.V[0]:=StrToFloat(workCopy);
      except
         ShowMessage('Wrong vector format. Use: ''<red green blue alpha>''!');
         Abort;
      end;
   end;
end;

//------------------------------------------------------------------------------

function TGLColorManager.GetColorName(const aColor: TColorVector): String;

const MinDiff = 1e-6;

var I : Integer;

begin
  for I:=0 to Count-1 do
    with TColorEntry(Items[I]^) do
      if (Abs(Color.V[0]-AColor.V[0]) < MinDiff) and
         (Abs(Color.V[1]-AColor.V[1]) < MinDiff) and
         (Abs(Color.V[2]-AColor.V[2]) < MinDiff) and
         (Abs(Color.V[3]-AColor.V[3]) < MinDiff) then Break;
  if I < Count then
    Result:=string(TColorEntry(Items[I]^).Name)
  else
    Result:=Format('<%.3f %.3f %.3f %.3f>',[AColor.V[0],AColor.V[1],
                   AColor.V[2],AColor.V[3]]);
end;

// Destroy
//
destructor TGLColorManager.Destroy;
var
   i : Integer;
begin
   for i:=0 to Count-1 do
      FreeMem(Items[i], SizeOf(TColorEntry));
   inherited Destroy;
end;

// AddColor
//
procedure TGLColorManager.AddColor(const aName: String; const aColor: TColorVector);
var
   newEntry : PColorEntry;
begin
   New(newEntry);
   if newEntry = nil then
      raise Exception.Create('Could not allocate memory for color registration!');
   with newEntry^ do begin
     Name:=shortstring(AName);
     SetVector(Color, aColor);
   end;
   Add(newEntry);
end;

// EnumColors
//
procedure TGLColorManager.EnumColors(Proc: TGetStrProc);
var
   i : Integer;
begin
   for i:=0 to Count-1 do
      Proc(string(TColorEntry(Items[i]^).Name));
end;

// EnumColors
//
procedure TGLColorManager.EnumColors(AValues: TStrings);
var
   i : Integer;
begin
   for i:=0 to Count-1 do
      AValues.Add(string(TColorEntry(Items[i]^).Name));
end;


// RegisterDefaultColors
//
procedure TGLColorManager.RegisterDefaultColors;
begin
   Capacity:=150;
   AddColor('clrTransparent',clrTransparent);
   AddColor('clrBlack',clrBlack);
   AddColor('clrGray05',clrGray05);
   AddColor('clrGray10',clrGray10);
   AddColor('clrGray15',clrGray15);
   AddColor('clrGray20',clrGray20);
   AddColor('clrGray25',clrGray25);
   AddColor('clrGray30',clrGray30);
   AddColor('clrGray35',clrGray35);
   AddColor('clrGray40',clrGray40);
   AddColor('clrGray45',clrGray45);
   AddColor('clrGray50',clrGray50);
   AddColor('clrGray55',clrGray55);
   AddColor('clrGray60',clrGray60);
   AddColor('clrGray65',clrGray65);
   AddColor('clrGray70',clrGray70);
   AddColor('clrGray75',clrGray75);
   AddColor('clrGray80',clrGray80);
   AddColor('clrGray85',clrGray85);
   AddColor('clrGray90',clrGray90);
   AddColor('clrGray95',clrGray95);
   AddColor('clrWhite',clrWhite);
   AddColor('clrDimGray',clrDimGray);
   AddColor('clrGray',clrGray);
   AddColor('clrLightGray',clrLightGray);
   AddColor('clrAquamarine',clrAquamarine);
   AddColor('clrBakersChoc',clrBakersChoc);
   AddColor('clrBlueViolet',clrBlueViolet);
   AddColor('clrBrass',clrBrass);
   AddColor('clrBrightGold',clrBrightGold);
   AddColor('clrBronze',clrBronze);
   AddColor('clrBronze2',clrBronze2);
   AddColor('clrBrown',clrBrown);
   AddColor('clrCadetBlue',clrCadetBlue);
   AddColor('clrCoolCopper',clrCoolCopper);
   AddColor('clrCopper',clrCopper);
   AddColor('clrCoral',clrCoral);
   AddColor('clrCornflowerBlue',clrCornflowerBlue);
   AddColor('clrDarkBrown',clrDarkBrown);
   AddColor('clrDarkGreen',clrDarkGreen);
   AddColor('clrDarkOliveGreen',clrDarkOliveGreen);
   AddColor('clrDarkOrchid',clrDarkOrchid);
   AddColor('clrDarkPurple',clrDarkPurple);
   AddColor('clrDarkSlateBlue',clrDarkSlateBlue);
   AddColor('clrDarkSlateGray',clrDarkSlateGray);
   AddColor('clrDarkSlateGrey',clrDarkSlateGrey);
   AddColor('clrDarkTan',clrDarkTan);
   AddColor('clrDarkTurquoise',clrDarkTurquoise);
   AddColor('clrDarkWood',clrDarkWood);
   AddColor('clrDkGreenCopper',clrDkGreenCopper);
   AddColor('clrDustyRose',clrDustyRose);
   AddColor('clrFeldspar',clrFeldspar);
   AddColor('clrFirebrick',clrFirebrick);
   AddColor('clrFlesh',clrFlesh);
   AddColor('clrForestGreen',clrForestGreen);
   AddColor('clrGold',clrGold);
   AddColor('clrGoldenrod',clrGoldenrod);
   AddColor('clrGreenCopper',clrGreenCopper);
   AddColor('clrGreenYellow',clrGreenYellow);
   AddColor('clrHuntersGreen',clrHuntersGreen);
   AddColor('clrIndian',clrIndian);
   AddColor('clrKhaki',clrKhaki);
   AddColor('clrLightBlue',clrLightBlue);
   AddColor('clrLightPurple',clrLightPurple);
   AddColor('clrLightSteelBlue',clrLightSteelBlue);
   AddColor('clrLightWood',clrLightWood);
   AddColor('clrLimeGreen',clrLimeGreen);
   AddColor('clrMandarinOrange',clrMandarinOrange);
   AddColor('clrMaroon',clrMaroon);
   AddColor('clrMediumAquamarine',clrMediumAquamarine);
   AddColor('clrMediumBlue',clrMediumBlue);
   AddColor('clrMediumForestGreen',clrMediumForestGreen);
   AddColor('clrMediumGoldenrod',clrMediumGoldenrod);
   AddColor('clrMediumOrchid',clrMediumOrchid);
   AddColor('clrMediumPurple',clrMediumPurple);
   AddColor('clrMediumSeaGreen',clrMediumSeaGreen);
   AddColor('clrMediumSlateBlue',clrMediumSlateBlue);
   AddColor('clrMediumSpringGreen',clrMediumSpringGreen);
   AddColor('clrMediumTurquoise',clrMediumTurquoise);
   AddColor('clrMediumViolet',clrMediumViolet);
   AddColor('clrMediumWood',clrMediumWood);
   AddColor('clrMidnightBlue',clrMidnightBlue);
   AddColor('clrNavy',clrNavy);
   AddColor('clrNavyBlue',clrNavyBlue);
   AddColor('clrNeonBlue',clrNeonBlue);
   AddColor('clrNeonPink',clrNeonPink);
   AddColor('clrNewMidnightBlue',clrNewMidnightBlue);
   AddColor('clrNewTan',clrNewTan);
   AddColor('clrOldGold',clrOldGold);
   AddColor('clrOrange',clrOrange);
   AddColor('clrOrangeRed',clrOrangeRed);
   AddColor('clrOrchid',clrOrchid);
   AddColor('clrPaleGreen',clrPaleGreen);
   AddColor('clrPink',clrPink);
   AddColor('clrPlum',clrPlum);
   AddColor('clrQuartz',clrQuartz);
   AddColor('clrRichBlue',clrRichBlue);
   AddColor('clrSalmon',clrSalmon);
   AddColor('clrScarlet',clrScarlet);
   AddColor('clrSeaGreen',clrSeaGreen);
   AddColor('clrSemiSweetChoc',clrSemiSweetChoc);
   AddColor('clrSienna',clrSienna);
   AddColor('clrSilver',clrSilver);
   AddColor('clrSkyBlue',clrSkyBlue);
   AddColor('clrSlateBlue',clrSlateBlue);
   AddColor('clrSpicyPink',clrSpicyPink);
   AddColor('clrSpringGreen',clrSpringGreen);
   AddColor('clrSteelBlue',clrSteelBlue);
   AddColor('clrSummerSky',clrSummerSky);
   AddColor('clrTan',clrTan);
   AddColor('clrThistle',clrThistle);
   AddColor('clrTurquoise',clrTurquoise);
   AddColor('clrViolet',clrViolet);
   AddColor('clrVioletRed',clrVioletRed);
   AddColor('clrVeryDarkBrown',clrVeryDarkBrown);
   AddColor('clrVeryLightPurple',clrVeryLightPurple);
   AddColor('clrWheat',clrWheat);
   AddColor('clrYellowGreen',clrYellowGreen);
   AddColor('clrGreen',clrGreen);
   AddColor('clrOlive',clrOlive);
   AddColor('clrPurple',clrPurple);
   AddColor('clrTeal',clrTeal);
   AddColor('clrRed',clrRed);
   AddColor('clrLime',clrLime);
   AddColor('clrYellow',clrYellow);
   AddColor('clrBlue',clrBlue);
   AddColor('clrFuchsia',clrFuchsia);
   AddColor('clrAqua',clrAqua);

   AddColor('clrScrollBar',clrScrollBar);
   AddColor('clrBackground',clrBackground);
   AddColor('clrActiveCaption',clrActiveCaption);
   AddColor('clrInactiveCaption',clrInactiveCaption);
   AddColor('clrMenu',clrMenu);
   AddColor('clrWindow',clrWindow);
   AddColor('clrWindowFrame',clrWindowFrame);
   AddColor('clrMenuText',clrMenuText);
   AddColor('clrWindowText',clrWindowText);
   AddColor('clrCaptionText',clrCaptionText);
   AddColor('clrActiveBorder',clrActiveBorder);
   AddColor('clrInactiveBorder',clrInactiveBorder);
   AddColor('clrAppWorkSpace',clrAppWorkSpace);
   AddColor('clrHighlight',clrHighlight);
   AddColor('clrHighlightText',clrHighlightText);
   AddColor('clrBtnFace',clrBtnFace);
   AddColor('clrBtnShadow',clrBtnShadow);
   AddColor('clrGrayText',clrGrayText);
   AddColor('clrBtnText',clrBtnText);
   AddColor('clrInactiveCaptionText',clrInactiveCaptionText);
   AddColor('clrBtnHighlight',clrBtnHighlight);
   AddColor('clr3DDkShadow',clr3DDkShadow);
   AddColor('clr3DLight',clr3DLight);
   AddColor('clrInfoText',clrInfoText);
   AddColor('clrInfoBk',clrInfoBk);
end;

// RemoveColor
//
procedure TGLColorManager.RemoveColor(const aName: String);
var
   i : Integer;
begin
   for i:=0 to Count-1 do begin
      if CompareText(string(TColorEntry(Items[i]^).Name), aName)=0 then begin
         Delete(i);
         Break;
	   end;
   end;
end;

// RegisterColor
//
procedure RegisterColor(const aName : String; const aColor : TColorVector);
begin
   ColorManager.AddColor(AName, AColor);
end;

// UnregisterColor
//
procedure UnregisterColor(const aName : String);
begin
   ColorManager.RemoveColor(AName);
end;


initialization
  InitGLSceneColors;

finalization
	vColorManager.Free;

end.
