Changeset 521 for GraphicTest/Packages/bgrabitmap/bgragradientscanner.pas
- Timestamp:
- Apr 17, 2019, 12:58:41 AM (5 years ago)
- Location:
- GraphicTest
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
GraphicTest
- Property svn:ignore
-
old new 8 8 GraphicTest.lps 9 9 GraphicTest.dbg 10 heaptrclog.trc
-
- Property svn:ignore
-
GraphicTest/Packages/bgrabitmap/bgragradientscanner.pas
r494 r521 11 11 12 12 type 13 { TBGRASimpleGradientWithoutGammaCorrection } 14 15 TBGRASimpleGradientWithoutGammaCorrection = class(TBGRACustomGradient) 16 private 13 TBGRAColorInterpolation = (ciStdRGB, ciLinearRGB, ciLinearHSLPositive, ciLinearHSLNegative, ciGSBPositive, ciGSBNegative); 14 TBGRAGradientRepetition = (grPad, grRepeat, grReflect, grSine); 15 16 { TBGRASimpleGradient } 17 18 TBGRASimpleGradient = class(TBGRACustomGradient) 19 protected 17 20 FColor1,FColor2: TBGRAPixel; 18 21 ec1,ec2: TExpandedPixel; 22 FRepetition: TBGRAGradientRepetition; 23 constructor Create(AColor1,AColor2: TBGRAPixel; ARepetition: TBGRAGradientRepetition); overload; 24 constructor Create(AColor1,AColor2: TExpandedPixel; ARepetition: TBGRAGradientRepetition); overload; 25 function InterpolateToBGRA(position: word): TBGRAPixel; virtual; abstract; 26 function InterpolateToExpanded(position: word): TExpandedPixel; virtual; abstract; 19 27 public 20 constructor Create(Color1,Color2: TBGRAPixel); 28 class function CreateAny(AInterpolation: TBGRAColorInterpolation; AColor1,AColor2: TBGRAPixel; ARepetition: TBGRAGradientRepetition): TBGRASimpleGradient; overload; 29 class function CreateAny(AInterpolation: TBGRAColorInterpolation; AColor1,AColor2: TExpandedPixel; ARepetition: TBGRAGradientRepetition): TBGRASimpleGradient; overload; 21 30 function GetColorAt(position: integer): TBGRAPixel; override; 22 31 function GetColorAtF(position: single): TBGRAPixel; override; … … 24 33 function GetExpandedColorAtF(position: single): TExpandedPixel; override; 25 34 function GetAverageColor: TBGRAPixel; override; 26 function GetMonochrome: boolean; override;27 end;28 29 { TBGRASimpleGradientWithGammaCorrection }30 31 TBGRASimpleGradientWithGammaCorrection = class(TBGRACustomGradient)32 private33 FColor1,FColor2: TBGRAPixel;34 ec1,ec2: TExpandedPixel;35 public36 constructor Create(Color1,Color2: TBGRAPixel);37 function GetColorAt(position: integer): TBGRAPixel; override;38 function GetColorAtF(position: single): TBGRAPixel; override;39 function GetAverageColor: TBGRAPixel; override;40 function GetExpandedColorAt(position: integer): TExpandedPixel; override;41 function GetExpandedColorAtF(position: single): TExpandedPixel; override;42 35 function GetAverageExpandedColor: TExpandedPixel; override; 43 36 function GetMonochrome: boolean; override; 44 end; 45 46 THueGradientOption = (hgoRepeat, hgoPositiveDirection, hgoNegativeDirection, hgoHueCorrection, hgoLightnessCorrection); 37 property Repetition: TBGRAGradientRepetition read FRepetition write FRepetition; 38 end; 39 40 { TBGRASimpleGradientWithoutGammaCorrection } 41 42 TBGRASimpleGradientWithoutGammaCorrection = class(TBGRASimpleGradient) 43 protected 44 function InterpolateToBGRA(position: word): TBGRAPixel; override; 45 function InterpolateToExpanded(position: word): TExpandedPixel; override; 46 public 47 constructor Create(Color1,Color2: TBGRAPixel; ARepetition: TBGRAGradientRepetition = grPad); overload; 48 constructor Create(Color1,Color2: TExpandedPixel; ARepetition: TBGRAGradientRepetition = grPad); overload; 49 end; 50 51 { TBGRASimpleGradientWithGammaCorrection } 52 53 TBGRASimpleGradientWithGammaCorrection = class(TBGRASimpleGradient) 54 protected 55 function InterpolateToBGRA(position: word): TBGRAPixel; override; 56 function InterpolateToExpanded(position: word): TExpandedPixel; override; 57 public 58 constructor Create(Color1,Color2: TBGRAPixel; ARepetition: TBGRAGradientRepetition = grPad); overload; 59 constructor Create(Color1,Color2: TExpandedPixel; ARepetition: TBGRAGradientRepetition = grPad); overload; 60 end; 61 62 THueGradientOption = (hgoRepeat, hgoReflect, //repetition 63 hgoPositiveDirection, hgoNegativeDirection, //hue orientation 64 hgoHueCorrection, hgoLightnessCorrection); //color interpolation 47 65 THueGradientOptions = set of THueGradientOption; 48 66 49 67 { TBGRAHueGradient } 50 68 51 TBGRAHueGradient = class(TBGRA CustomGradient)69 TBGRAHueGradient = class(TBGRASimpleGradient) 52 70 private 53 FColor1,FColor2: TBGRAPixel;54 ec1,ec2: TExpandedPixel;55 71 hsla1,hsla2: THSLAPixel; 56 72 hue1,hue2: longword; 57 73 FOptions: THueGradientOptions; 58 74 procedure Init(c1,c2: THSLAPixel; AOptions: THueGradientOptions); 59 function GetColorNoBoundCheck(position: integer): THSLAPixel; 75 function InterpolateToHSLA(position: word): THSLAPixel; 76 protected 77 function InterpolateToBGRA(position: word): TBGRAPixel; override; 78 function InterpolateToExpanded(position: word): TExpandedPixel; override; 60 79 public 61 80 constructor Create(Color1,Color2: TBGRAPixel; options: THueGradientOptions); overload; 81 constructor Create(Color1,Color2: TExpandedPixel; options: THueGradientOptions); overload; 62 82 constructor Create(Color1,Color2: THSLAPixel; options: THueGradientOptions); overload; 63 83 constructor Create(AHue1,AHue2: Word; Saturation,Lightness: Word; options: THueGradientOptions); overload; 64 function GetColorAt(position: integer): TBGRAPixel; override;65 function GetColorAtF(position: single): TBGRAPixel; override;66 function GetAverageColor: TBGRAPixel; override;67 function GetExpandedColorAt(position: integer): TExpandedPixel; override;68 function GetExpandedColorAtF(position: single): TExpandedPixel; override;69 function GetAverageExpandedColor: TExpandedPixel; override;70 84 function GetMonochrome: boolean; override; 71 85 end; … … 96 110 end; 97 111 112 TBGRAGradientScannerInternalScanNextFunc = function():single of object; 113 TBGRAGradientScannerInternalScanAtFunc = function(const p: TPointF):single of object; 114 98 115 { TBGRAGradientScanner } 99 116 … … 101 118 protected 102 119 FGradientType: TGradientType; 103 FOrigin1,FOrigin2: TPointF; 120 FOrigin,FDir1,FDir2: TPointF; 121 FRelativeFocal: TPointF; 122 FRadius, FFocalRadius: single; 123 FTransform, FHiddenTransform: TAffineMatrix; 104 124 FSinus: Boolean; 105 u: TPointF;106 len,aFactor,aFactorF: single;107 mergedColor: TBGRAPixel;108 mergedExpandedColor: TExpandedPixel;109 125 FGradient: TBGRACustomGradient; 110 126 FGradientOwner: boolean; 127 FFlipGradient: boolean; 128 129 FMatrix: TAffineMatrix; 130 FRepeatHoriz, FIsAverage: boolean; 131 FAverageColor: TBGRAPixel; 132 FAverageExpandedColor: TExpandedPixel; 133 FScanNextFunc: TBGRAGradientScannerInternalScanNextFunc; 134 FScanAtFunc: TBGRAGradientScannerInternalScanAtFunc; 135 FFocalDistance: single; 136 FFocalDirection, FFocalNormal: TPointF; 137 FRadialDenominator, FRadialDeltaSign, maxW1, maxW2: single; 138 139 FPosition: TPointF; 111 140 FHorizColor: TBGRAPixel; 112 141 FHorizExpandedColor: TExpandedPixel; 113 FVertical: boolean; 114 FDotProduct,FDotProductPerp: Single; 115 procedure Init(gtype: TGradientType; o1, o2: TPointF; Sinus: Boolean=False); 116 procedure InitScanInline(x,y: integer); 142 143 procedure Init(AGradientType: TGradientType; AOrigin, d1: TPointF; ATransform: TAffineMatrix; Sinus: Boolean=False); overload; 144 procedure Init(AGradientType: TGradientType; AOrigin, d1, d2: TPointF; ATransform: TAffineMatrix; Sinus: Boolean=False); overload; 145 procedure Init(AOrigin: TPointF; ARadius: single; AFocal: TPointF; AFocalRadius: single; ATransform: TAffineMatrix; AHiddenTransform: TAffineMatrix); overload; 146 147 procedure InitGradientType; 148 procedure InitTransform; 149 procedure InitGradient; 150 151 function ComputeRadialFocal(const p: TPointF): single; 152 153 function ScanNextLinear: single; 154 function ScanNextReflected: single; 155 function ScanNextDiamond: single; 156 function ScanNextRadial: single; 157 function ScanNextRadial2: single; 158 function ScanNextRadialFocal: single; 159 function ScanNextAngular: single; 160 161 function ScanAtLinear(const p: TPointF): single; 162 function ScanAtReflected(const p: TPointF): single; 163 function ScanAtDiamond(const p: TPointF): single; 164 function ScanAtRadial(const p: TPointF): single; 165 function ScanAtRadial2(const p: TPointF): single; 166 function ScanAtRadialFocal(const p: TPointF): single; 167 function ScanAtAngular(const p: TPointF): single; 168 117 169 function ScanNextInline: TBGRAPixel; inline; 118 170 function ScanNextExpandedInline: TExpandedPixel; inline; 171 procedure SetTransform(AValue: TAffineMatrix); 172 procedure SetFlipGradient(AValue: boolean); 173 function GetGradientColor(a: single): TBGRAPixel; 174 function GetGradientExpandedColor(a: single): TExpandedPixel; 119 175 public 120 constructor Create(c1, c2: TBGRAPixel; gtype: TGradientType; o1, o2: TPointF; 121 gammaColorCorrection: boolean = True; Sinus: Boolean=False); 122 constructor Create(gradient: TBGRACustomGradient; gtype: TGradientType; o1, o2: TPointF; Sinus: Boolean=False; AGradientOwner: Boolean=False); 176 constructor Create(AGradientType: TGradientType; AOrigin, d1: TPointF); overload; 177 constructor Create(AGradientType: TGradientType; AOrigin, d1, d2: TPointF); overload; 178 constructor Create(AOrigin, d1, d2, AFocal: TPointF; ARadiusRatio: single = 1; AFocalRadiusRatio: single = 0); overload; 179 constructor Create(AOrigin: TPointF; ARadius: single; AFocal: TPointF; AFocalRadius: single); overload; 180 181 constructor Create(c1, c2: TBGRAPixel; AGradientType: TGradientType; AOrigin, d1: TPointF; 182 gammaColorCorrection: boolean = True; Sinus: Boolean=False); overload; 183 constructor Create(c1, c2: TBGRAPixel; AGradientType: TGradientType; AOrigin, d1, d2: TPointF; 184 gammaColorCorrection: boolean = True; Sinus: Boolean=False); overload; 185 186 constructor Create(gradient: TBGRACustomGradient; AGradientType: TGradientType; AOrigin, d1: TPointF; 187 Sinus: Boolean=False; AGradientOwner: Boolean=False); overload; 188 constructor Create(gradient: TBGRACustomGradient; AGradientType: TGradientType; AOrigin, d1, d2: TPointF; 189 Sinus: Boolean=False; AGradientOwner: Boolean=False); overload; 190 constructor Create(gradient: TBGRACustomGradient; AOrigin: TPointF; ARadius: single; AFocal: TPointF; 191 AFocalRadius: single; AGradientOwner: Boolean=False); overload; 192 193 procedure SetGradient(c1,c2: TBGRAPixel; AGammaCorrection: boolean = true); overload; 194 procedure SetGradient(AGradient: TBGRACustomGradient; AOwner: boolean); overload; 123 195 destructor Destroy; override; 124 196 procedure ScanMoveTo(X, Y: Integer); override; … … 129 201 procedure ScanPutPixels(pdest: PBGRAPixel; count: integer; mode: TDrawMode); override; 130 202 function IsScanPutPixelsDefined: boolean; override; 203 property Transform: TAffineMatrix read FTransform write SetTransform; 204 property Gradient: TBGRACustomGradient read FGradient; 205 property FlipGradient: boolean read FFlipGradient write SetFlipGradient; 206 property Sinus: boolean Read FSinus write FSinus; 131 207 end; 132 208 … … 143 219 FOpacity: byte; 144 220 FGrayscale: boolean; 221 FRandomBuffer, FRandomBufferCount: integer; 145 222 public 146 223 constructor Create(AGrayscale: Boolean; AOpacity: byte); … … 213 290 private 214 291 FTexture: IBGRAScanner; 292 FOwnedScanner: TBGRACustomScanner; 215 293 FGlobalOpacity: Byte; 216 294 FScanNext : TScanNextPixelFunction; … … 219 297 public 220 298 constructor Create(ATexture: IBGRAScanner; AGlobalOpacity: Byte = 255); 299 constructor Create(ATexture: TBGRACustomScanner; AGlobalOpacity: Byte; AOwned: boolean); 221 300 destructor Destroy; override; 222 301 function IsScanPutPixelsDefined: boolean; override; … … 231 310 uses BGRABlend, Math; 232 311 312 { TBGRASimpleGradient } 313 314 constructor TBGRASimpleGradient.Create(AColor1, AColor2: TBGRAPixel; ARepetition: TBGRAGradientRepetition); 315 begin 316 FColor1 := AColor1; 317 FColor2 := AColor2; 318 ec1 := GammaExpansion(AColor1); 319 ec2 := GammaExpansion(AColor2); 320 FRepetition:= ARepetition; 321 end; 322 323 constructor TBGRASimpleGradient.Create(AColor1, AColor2: TExpandedPixel; 324 ARepetition: TBGRAGradientRepetition); 325 begin 326 FColor1 := GammaCompression(AColor1); 327 FColor2 := GammaCompression(AColor2); 328 ec1 := AColor1; 329 ec2 := AColor2; 330 FRepetition:= ARepetition; 331 end; 332 333 class function TBGRASimpleGradient.CreateAny(AInterpolation: TBGRAColorInterpolation; 334 AColor1, AColor2: TBGRAPixel; ARepetition: TBGRAGradientRepetition): TBGRASimpleGradient; 335 begin 336 case AInterpolation of 337 ciStdRGB: result := TBGRASimpleGradientWithoutGammaCorrection.Create(AColor1,AColor2); 338 ciLinearRGB: result := TBGRASimpleGradientWithGammaCorrection.Create(AColor1,AColor2); 339 ciLinearHSLPositive: result := TBGRAHueGradient.Create(AColor1,AColor2,[hgoPositiveDirection]); 340 ciLinearHSLNegative: result := TBGRAHueGradient.Create(AColor1,AColor2,[hgoNegativeDirection]); 341 ciGSBPositive: result := TBGRAHueGradient.Create(AColor1,AColor2,[hgoPositiveDirection, hgoHueCorrection, hgoLightnessCorrection]); 342 ciGSBNegative: result := TBGRAHueGradient.Create(AColor1,AColor2,[hgoNegativeDirection, hgoHueCorrection, hgoLightnessCorrection]); 343 end; 344 result.Repetition := ARepetition; 345 end; 346 347 class function TBGRASimpleGradient.CreateAny(AInterpolation: TBGRAColorInterpolation; 348 AColor1, AColor2: TExpandedPixel; ARepetition: TBGRAGradientRepetition): TBGRASimpleGradient; 349 begin 350 case AInterpolation of 351 ciStdRGB: result := TBGRASimpleGradientWithoutGammaCorrection.Create(AColor1,AColor2); 352 ciLinearRGB: result := TBGRASimpleGradientWithGammaCorrection.Create(AColor1,AColor2); 353 ciLinearHSLPositive: result := TBGRAHueGradient.Create(AColor1,AColor2,[hgoPositiveDirection]); 354 ciLinearHSLNegative: result := TBGRAHueGradient.Create(AColor1,AColor2,[hgoNegativeDirection]); 355 ciGSBPositive: result := TBGRAHueGradient.Create(AColor1,AColor2,[hgoPositiveDirection, hgoHueCorrection, hgoLightnessCorrection]); 356 ciGSBNegative: result := TBGRAHueGradient.Create(AColor1,AColor2,[hgoNegativeDirection, hgoHueCorrection, hgoLightnessCorrection]); 357 end; 358 result.Repetition := ARepetition; 359 end; 360 361 function TBGRASimpleGradient.GetAverageColor: TBGRAPixel; 362 begin 363 result := InterpolateToBGRA(32768); 364 end; 365 366 function TBGRASimpleGradient.GetAverageExpandedColor: TExpandedPixel; 367 begin 368 Result:= InterpolateToExpanded(32768); 369 end; 370 371 function TBGRASimpleGradient.GetColorAt(position: integer): TBGRAPixel; 372 begin 373 case FRepetition of 374 grSine: begin 375 position := Sin65536(position and $ffff); 376 if position = 65536 then 377 result := FColor2 378 else 379 result := InterpolateToBGRA(position); 380 end; 381 grRepeat: result := InterpolateToBGRA(position and $ffff); 382 grReflect: 383 begin 384 position := position and $1ffff; 385 if position >= $10000 then 386 begin 387 if position = $10000 then 388 result := FColor2 389 else 390 result := InterpolateToBGRA($20000 - position); 391 end 392 else 393 result := InterpolateToBGRA(position); 394 end; 395 else 396 begin 397 if position <= 0 then 398 result := FColor1 else 399 if position >= 65536 then 400 result := FColor2 else 401 result := InterpolateToBGRA(position); 402 end; 403 end; 404 end; 405 406 function TBGRASimpleGradient.GetColorAtF(position: single): TBGRAPixel; 407 begin 408 if FRepetition <> grPad then 409 result := GetColorAt(round(frac(position*0.5)*131072)) else //divided by 2 for reflected repetition 410 begin 411 if position <= 0 then 412 result := FColor1 else 413 if position >= 1 then 414 result := FColor2 else 415 result := GetColorAt(round(position*65536)); 416 end; 417 end; 418 419 function TBGRASimpleGradient.GetExpandedColorAt(position: integer 420 ): TExpandedPixel; 421 begin 422 case FRepetition of 423 grSine: begin 424 position := Sin65536(position and $ffff); 425 if position = 65536 then 426 result := ec2 427 else 428 result := InterpolateToExpanded(position); 429 end; 430 grRepeat: result := InterpolateToExpanded(position and $ffff); 431 grReflect: 432 begin 433 position := position and $1ffff; 434 if position >= $10000 then 435 begin 436 if position = $10000 then 437 result := ec2 438 else 439 result := InterpolateToExpanded($20000 - position); 440 end 441 else 442 result := InterpolateToExpanded(position); 443 end; 444 else 445 begin 446 if position <= 0 then 447 result := ec1 else 448 if position >= 65536 then 449 result := ec2 else 450 result := InterpolateToExpanded(position); 451 end; 452 end; 453 end; 454 455 function TBGRASimpleGradient.GetExpandedColorAtF(position: single 456 ): TExpandedPixel; 457 begin 458 if FRepetition <> grPad then 459 result := GetExpandedColorAt(round(frac(position*0.5)*131072)) else //divided by 2 for reflected repetition 460 begin 461 if position <= 0 then 462 result := ec1 else 463 if position >= 1 then 464 result := ec2 else 465 result := GetExpandedColorAt(round(position*65536)); 466 end; 467 end; 468 469 function TBGRASimpleGradient.GetMonochrome: boolean; 470 begin 471 Result:= (FColor1 = FColor2); 472 end; 473 233 474 { TBGRAConstantScanner } 234 475 … … 244 485 FGrayscale:= AGrayscale; 245 486 FOpacity:= AOpacity; 487 FRandomBufferCount := 0; 246 488 end; 247 489 … … 252 494 253 495 function TBGRARandomScanner.ScanNextPixel: TBGRAPixel; 496 var rgb: integer; 254 497 begin 255 498 if FGrayscale then 256 499 begin 257 result.red := random(256); 500 if FRandomBufferCount = 0 then 501 begin 502 FRandomBuffer := random(256*256*256); 503 FRandomBufferCount := 3; 504 end; 505 result.red := FRandomBuffer and 255; 506 FRandomBuffer:= FRandomBuffer shr 8; 507 FRandomBufferCount -= 1; 258 508 result.green := result.red; 259 509 result.blue := result.red; 260 510 result.alpha:= FOpacity; 261 511 end else 262 Result:= BGRA(random(256),random(256),random(256),FOpacity); 512 begin 513 rgb := random(256*256*256); 514 Result:= BGRA(rgb and 255,(rgb shr 8) and 255,(rgb shr 16) and 255,FOpacity); 515 end; 263 516 end; 264 517 … … 272 525 procedure TBGRAHueGradient.Init(c1, c2: THSLAPixel; AOptions: THueGradientOptions); 273 526 begin 274 FColor1 := HSLAToBGRA(c1);275 FColor2 := HSLAToBGRA(c2);276 ec1 := GammaExpansion(FColor1);277 ec2 := GammaExpansion(FColor2);278 527 FOptions:= AOptions; 279 528 if (hgoLightnessCorrection in AOptions) then 280 529 begin 281 hsla1 := BGRAToGSBA(FColor1);282 hsla2 := BGRAToGSBA(FColor2);530 hsla1 := ExpandedToGSBA(ec1); 531 hsla2 := ExpandedToGSBA(ec2); 283 532 end else 284 533 begin … … 305 554 end; 306 555 307 function TBGRAHueGradient. GetColorNoBoundCheck(position: integer): THSLAPixel;556 function TBGRAHueGradient.InterpolateToHSLA(position: word): THSLAPixel; 308 557 var b,b2: LongWord; 309 558 begin … … 325 574 end; 326 575 576 function TBGRAHueGradient.InterpolateToBGRA(position: word): TBGRAPixel; 577 begin 578 if hgoLightnessCorrection in FOptions then 579 result := GSBAToBGRA(InterpolateToHSLA(position)) 580 else 581 result := HSLAToBGRA(InterpolateToHSLA(position)); 582 end; 583 584 function TBGRAHueGradient.InterpolateToExpanded(position: word): TExpandedPixel; 585 begin 586 if hgoLightnessCorrection in FOptions then 587 result := GSBAToExpanded(InterpolateToHSLA(position)) 588 else 589 result := HSLAToExpanded(InterpolateToHSLA(position)); 590 end; 591 327 592 constructor TBGRAHueGradient.Create(Color1, Color2: TBGRAPixel;options: THueGradientOptions); 328 593 begin 594 if hgoReflect in options then 595 inherited Create(Color1,Color2,grReflect) 596 else if hgoRepeat in options then 597 inherited Create(Color1,Color2,grRepeat) 598 else 599 inherited Create(Color1,Color2,grPad); 600 329 601 Init(BGRAToHSLA(Color1),BGRAToHSLA(Color2),options); 330 602 end; 331 603 604 constructor TBGRAHueGradient.Create(Color1, Color2: TExpandedPixel; 605 options: THueGradientOptions); 606 begin 607 if hgoReflect in options then 608 inherited Create(Color1,Color2,grReflect) 609 else if hgoRepeat in options then 610 inherited Create(Color1,Color2,grRepeat) 611 else 612 inherited Create(Color1,Color2,grPad); 613 614 Init(ExpandedToHSLA(Color1),ExpandedToHSLA(Color2),options); 615 end; 616 332 617 constructor TBGRAHueGradient.Create(Color1, Color2: THSLAPixel; options: THueGradientOptions); 333 618 begin 619 if hgoReflect in options then 620 inherited Create(Color1.ToExpanded,Color2.ToExpanded,grReflect) 621 else if hgoRepeat in options then 622 inherited Create(Color1.ToExpanded,Color2.ToExpanded,grRepeat) 623 else 624 inherited Create(Color1.ToExpanded,Color2.ToExpanded,grPad); 625 334 626 Init(Color1,Color2, options); 335 627 end; … … 338 630 Lightness: Word; options: THueGradientOptions); 339 631 begin 340 Init(HSLA(AHue1,saturation,lightness), HSLA(AHue2,saturation,lightness), options); 341 end; 342 343 function TBGRAHueGradient.GetColorAt(position: integer): TBGRAPixel; 344 var interm: THSLAPixel; 345 begin 346 if hgoRepeat in FOptions then 347 begin 348 position := position and $ffff; 349 if position = 0 then 350 begin 351 result := FColor1; 352 exit; 353 end; 354 end else 355 begin 356 if position <= 0 then 357 begin 358 result := FColor1; 359 exit 360 end else 361 if position >= 65536 then 362 begin 363 result := FColor2; 364 exit 365 end; 366 end; 367 interm := GetColorNoBoundCheck(position); 368 if hgoLightnessCorrection in FOptions then 369 result := GSBAToBGRA(interm) 370 else 371 result := HSLAToBGRA(interm); 372 end; 373 374 function TBGRAHueGradient.GetColorAtF(position: single): TBGRAPixel; 375 var interm: THSLAPixel; 376 begin 377 if hgoRepeat in FOptions then 378 begin 379 position := frac(position); 380 if position = 0 then 381 begin 382 result := FColor1; 383 exit; 384 end; 385 end else 386 begin 387 if position <= 0 then 388 begin 389 result := FColor1; 390 exit; 391 end else 392 if position >= 1 then 393 begin 394 result := FColor2; 395 exit 396 end; 397 end; 398 interm := GetColorNoBoundCheck(round(position*65536)); 399 if hgoLightnessCorrection in FOptions then 400 result := GSBAToBGRA(interm) 401 else 402 result := HSLAToBGRA(interm); 403 end; 404 405 function TBGRAHueGradient.GetAverageColor: TBGRAPixel; 406 begin 407 Result:= GetColorAt(32768); 408 end; 409 410 function TBGRAHueGradient.GetExpandedColorAt(position: integer): TExpandedPixel; 411 var interm: THSLAPixel; 412 begin 413 if hgoRepeat in FOptions then 414 begin 415 position := position and $ffff; 416 if position = 0 then 417 begin 418 result := ec1; 419 exit; 420 end; 421 end else 422 begin 423 if position <= 0 then 424 begin 425 result := ec1; 426 exit 427 end else 428 if position >= 65536 then 429 begin 430 result := ec2; 431 exit 432 end; 433 end; 434 interm := GetColorNoBoundCheck(position); 435 if hgoLightnessCorrection in FOptions then 436 result := GSBAToExpanded(interm) 437 else 438 result := HSLAToExpanded(interm); 439 end; 440 441 function TBGRAHueGradient.GetExpandedColorAtF(position: single): TExpandedPixel; 442 var interm: THSLAPixel; 443 begin 444 if hgoRepeat in FOptions then 445 begin 446 position := frac(position); 447 if position = 0 then 448 begin 449 result := ec1; 450 exit; 451 end; 452 end else 453 begin 454 if position <= 0 then 455 begin 456 result := ec1; 457 exit; 458 end else 459 if position >= 1 then 460 begin 461 result := ec2; 462 exit 463 end; 464 end; 465 interm := GetColorNoBoundCheck(round(position*65536)); 466 if hgoLightnessCorrection in FOptions then 467 result := GSBAToExpanded(interm) 468 else 469 result := HSLAToExpanded(interm); 470 end; 471 472 function TBGRAHueGradient.GetAverageExpandedColor: TExpandedPixel; 473 begin 474 Result:= GetExpandedColorAt(32768); 632 Create(HSLA(AHue1,saturation,lightness), HSLA(AHue2,saturation,lightness), options); 475 633 end; 476 634 … … 670 828 { TBGRASimpleGradientWithGammaCorrection } 671 829 672 constructor TBGRASimpleGradientWithGammaCorrection.Create(Color1, 673 Color2: TBGRAPixel); 674 begin 675 FColor1 := Color1; 676 FColor2 := Color2; 677 ec1 := GammaExpansion(Color1); 678 ec2 := GammaExpansion(Color2); 679 end; 680 681 function TBGRASimpleGradientWithGammaCorrection.GetColorAt(position: integer 830 function TBGRASimpleGradientWithGammaCorrection.InterpolateToBGRA(position: word 682 831 ): TBGRAPixel; 683 832 var b,b2: cardinal; 684 833 ec: TExpandedPixel; 685 834 begin 686 if position <= 0 then 687 result := FColor1 else 688 if position >= 65536 then 689 result := FColor2 else 690 begin 691 b := position; 692 b2 := 65536-b; 693 ec.red := (ec1.red * b2 + ec2.red * b + 32767) shr 16; 694 ec.green := (ec1.green * b2 + ec2.green * b + 32767) shr 16; 695 ec.blue := (ec1.blue * b2 + ec2.blue * b + 32767) shr 16; 696 ec.alpha := (ec1.alpha * b2 + ec2.alpha * b + 32767) shr 16; 697 result := GammaCompression(ec); 698 end; 699 end; 700 701 function TBGRASimpleGradientWithGammaCorrection.GetColorAtF(position: single): TBGRAPixel; 835 b := position; 836 b2 := 65536-b; 837 ec.red := (ec1.red * b2 + ec2.red * b + 32767) shr 16; 838 ec.green := (ec1.green * b2 + ec2.green * b + 32767) shr 16; 839 ec.blue := (ec1.blue * b2 + ec2.blue * b + 32767) shr 16; 840 ec.alpha := (ec1.alpha * b2 + ec2.alpha * b + 32767) shr 16; 841 result := GammaCompression(ec); 842 end; 843 844 function TBGRASimpleGradientWithGammaCorrection.InterpolateToExpanded( 845 position: word): TExpandedPixel; 702 846 var b,b2: cardinal; 703 ec: TExpandedPixel; 704 begin 705 if position <= 0 then 706 result := FColor1 else 707 if position >= 1 then 708 result := FColor2 else 709 begin 710 b := round(position*65536); 711 b2 := 65536-b; 712 ec.red := (ec1.red * b2 + ec2.red * b + 32767) shr 16; 713 ec.green := (ec1.green * b2 + ec2.green * b + 32767) shr 16; 714 ec.blue := (ec1.blue * b2 + ec2.blue * b + 32767) shr 16; 715 ec.alpha := (ec1.alpha * b2 + ec2.alpha * b + 32767) shr 16; 716 result := GammaCompression(ec); 717 end; 718 end; 719 720 function TBGRASimpleGradientWithGammaCorrection.GetAverageColor: TBGRAPixel; 721 begin 722 result := GammaCompression(MergeBGRA(ec1,ec2)); 723 end; 724 725 function TBGRASimpleGradientWithGammaCorrection.GetExpandedColorAt( 726 position: integer): TExpandedPixel; 847 begin 848 b := position; 849 b2 := 65536-b; 850 result.red := (ec1.red * b2 + ec2.red * b + 32767) shr 16; 851 result.green := (ec1.green * b2 + ec2.green * b + 32767) shr 16; 852 result.blue := (ec1.blue * b2 + ec2.blue * b + 32767) shr 16; 853 result.alpha := (ec1.alpha * b2 + ec2.alpha * b + 32767) shr 16; 854 end; 855 856 constructor TBGRASimpleGradientWithGammaCorrection.Create(Color1, 857 Color2: TBGRAPixel; ARepetition: TBGRAGradientRepetition); 858 begin 859 inherited Create(Color1,Color2,ARepetition); 860 end; 861 862 constructor TBGRASimpleGradientWithGammaCorrection.Create(Color1, 863 Color2: TExpandedPixel; ARepetition: TBGRAGradientRepetition); 864 begin 865 inherited Create(Color1,Color2,ARepetition); 866 end; 867 868 { TBGRASimpleGradientWithoutGammaCorrection } 869 870 function TBGRASimpleGradientWithoutGammaCorrection.InterpolateToBGRA( 871 position: word): TBGRAPixel; 727 872 var b,b2: cardinal; 728 873 begin 729 if position <= 0 then 730 result := ec1 else 731 if position >= 65536 then 732 result := ec2 else 733 begin 734 b := position; 735 b2 := 65536-b; 736 result.red := (ec1.red * b2 + ec2.red * b + 32767) shr 16; 737 result.green := (ec1.green * b2 + ec2.green * b + 32767) shr 16; 738 result.blue := (ec1.blue * b2 + ec2.blue * b + 32767) shr 16; 739 result.alpha := (ec1.alpha * b2 + ec2.alpha * b + 32767) shr 16; 740 end; 741 end; 742 743 function TBGRASimpleGradientWithGammaCorrection.GetExpandedColorAtF( 744 position: single): TExpandedPixel; 745 var b,b2: cardinal; 746 begin 747 if position <= 0 then 748 result := ec1 else 749 if position >= 1 then 750 result := ec2 else 751 begin 752 b := round(position*65536); 753 b2 := 65536-b; 754 result.red := (ec1.red * b2 + ec2.red * b + 32767) shr 16; 755 result.green := (ec1.green * b2 + ec2.green * b + 32767) shr 16; 756 result.blue := (ec1.blue * b2 + ec2.blue * b + 32767) shr 16; 757 result.alpha := (ec1.alpha * b2 + ec2.alpha * b + 32767) shr 16; 758 end; 759 end; 760 761 function TBGRASimpleGradientWithGammaCorrection.GetAverageExpandedColor: TExpandedPixel; 762 begin 763 result := MergeBGRA(ec1,ec2); 764 end; 765 766 function TBGRASimpleGradientWithGammaCorrection.GetMonochrome: boolean; 767 begin 768 Result:= (FColor1 = FColor2); 769 end; 770 771 { TBGRASimpleGradientWithoutGammaCorrection } 772 773 constructor TBGRASimpleGradientWithoutGammaCorrection.Create(Color1, 774 Color2: TBGRAPixel); 775 begin 776 FColor1 := Color1; 777 FColor2 := Color2; 778 ec1 := GammaExpansion(Color1); 779 ec2 := GammaExpansion(Color2); 780 end; 781 782 function TBGRASimpleGradientWithoutGammaCorrection.GetColorAt(position: integer 783 ): TBGRAPixel; 784 var b,b2: cardinal; 785 begin 786 if position <= 0 then 787 result := FColor1 else 788 if position >= 65536 then 789 result := FColor2 else 790 begin 791 b := position shr 6; 792 b2 := 1024-b; 793 result.red := (FColor1.red * b2 + FColor2.red * b + 511) shr 10; 794 result.green := (FColor1.green * b2 + FColor2.green * b + 511) shr 10; 795 result.blue := (FColor1.blue * b2 + FColor2.blue * b + 511) shr 10; 796 result.alpha := (FColor1.alpha * b2 + FColor2.alpha * b + 511) shr 10; 797 end; 798 end; 799 800 function TBGRASimpleGradientWithoutGammaCorrection.GetColorAtF(position: single): TBGRAPixel; 801 begin 802 if position <= 0 then 803 result := FColor1 else 804 if position >= 1 then 805 result := FColor2 else 806 result := GetColorAt(round(position*65536)); 807 end; 808 809 function TBGRASimpleGradientWithoutGammaCorrection.GetExpandedColorAt( 810 position: integer): TExpandedPixel; 874 b := position shr 6; 875 b2 := 1024-b; 876 result.red := (FColor1.red * b2 + FColor2.red * b + 511) shr 10; 877 result.green := (FColor1.green * b2 + FColor2.green * b + 511) shr 10; 878 result.blue := (FColor1.blue * b2 + FColor2.blue * b + 511) shr 10; 879 result.alpha := (FColor1.alpha * b2 + FColor2.alpha * b + 511) shr 10; 880 end; 881 882 function TBGRASimpleGradientWithoutGammaCorrection.InterpolateToExpanded( 883 position: word): TExpandedPixel; 811 884 var b,b2: cardinal; 812 885 rw,gw,bw: word; 813 886 begin 814 if position <= 0 then 815 result := ec1 else 816 if position >= 65536 then 817 result := ec2 else 818 begin 819 b := position shr 6; 820 b2 := 1024-b; 821 rw := (FColor1.red * b2 + FColor2.red * b + 511) shr 2; 822 gw := (FColor1.green * b2 + FColor2.green * b + 511) shr 2; 823 bw := (FColor1.blue * b2 + FColor2.blue * b + 511) shr 2; 824 887 b := position shr 6; 888 b2 := 1024-b; 889 rw := (FColor1.red * b2 + FColor2.red * b + 511) shr 2; 890 gw := (FColor1.green * b2 + FColor2.green * b + 511) shr 2; 891 bw := (FColor1.blue * b2 + FColor2.blue * b + 511) shr 2; 892 893 if rw >= $ff00 then 894 result.red := 65535 895 else 825 896 result.red := (GammaExpansionTab[rw shr 8]*NativeUInt(255 - (rw and 255)) + GammaExpansionTab[(rw shr 8)+1]*NativeUInt(rw and 255)) shr 8; 897 898 if gw >= $ff00 then 899 result.green := 65535 900 else 826 901 result.green := (GammaExpansionTab[gw shr 8]*NativeUInt(255 - (gw and 255)) + GammaExpansionTab[(gw shr 8)+1]*NativeUInt(gw and 255)) shr 8; 902 903 if bw >= $ff00 then 904 result.blue := 65535 905 else 827 906 result.blue := (GammaExpansionTab[bw shr 8]*NativeUInt(255 - (bw and 255)) + GammaExpansionTab[(bw shr 8)+1]*NativeUInt(bw and 255)) shr 8; 828 result.alpha := (FColor1.alpha * b2 + FColor2.alpha * b + 511) shr 2; 829 end; 830 end; 831 832 function TBGRASimpleGradientWithoutGammaCorrection.GetExpandedColorAtF( 833 position: single): TExpandedPixel; 834 begin 835 if position <= 0 then 836 result := ec1 else 837 if position >= 1 then 838 result := ec2 else 839 result := GetExpandedColorAt(round(position*65536)); 840 end; 841 842 function TBGRASimpleGradientWithoutGammaCorrection.GetAverageColor: TBGRAPixel; 843 begin 844 result := MergeBGRA(FColor1,FColor2); 845 end; 846 847 function TBGRASimpleGradientWithoutGammaCorrection.GetMonochrome: boolean; 848 begin 849 Result:= (FColor1 = FColor2); 907 908 result.alpha := (FColor1.alpha * b2 + FColor2.alpha * b + 511) shr 2; 909 end; 910 911 constructor TBGRASimpleGradientWithoutGammaCorrection.Create(Color1, 912 Color2: TBGRAPixel; ARepetition: TBGRAGradientRepetition); 913 begin 914 inherited Create(Color1,Color2,ARepetition); 915 end; 916 917 constructor TBGRASimpleGradientWithoutGammaCorrection.Create(Color1, 918 Color2: TExpandedPixel; ARepetition: TBGRAGradientRepetition); 919 begin 920 inherited Create(Color1,Color2,ARepetition); 850 921 end; 851 922 … … 946 1017 { TBGRAGradientScanner } 947 1018 948 procedure TBGRAGradientScanner.Init(gtype: TGradientType; o1, o2: TPointF; 949 Sinus: Boolean); 950 begin 951 FGradientType:= gtype; 952 FOrigin1 := o1; 953 FOrigin2 := o2; 1019 procedure TBGRAGradientScanner.SetTransform(AValue: TAffineMatrix); 1020 begin 1021 if FTransform=AValue then Exit; 1022 FTransform:=AValue; 1023 InitTransform; 1024 end; 1025 1026 constructor TBGRAGradientScanner.Create(AGradientType: TGradientType; AOrigin, d1: TPointF); 1027 begin 1028 FGradient := nil; 1029 SetGradient(BGRABlack,BGRAWhite,False); 1030 Init(AGradientType,AOrigin,d1,AffineMatrixIdentity,False); 1031 end; 1032 1033 constructor TBGRAGradientScanner.Create(AGradientType: TGradientType; AOrigin, d1,d2: TPointF); 1034 begin 1035 FGradient := nil; 1036 SetGradient(BGRABlack,BGRAWhite,False); 1037 Init(AGradientType,AOrigin,d1,d2,AffineMatrixIdentity,False); 1038 end; 1039 1040 constructor TBGRAGradientScanner.Create(AOrigin, 1041 d1, d2, AFocal: TPointF; ARadiusRatio: single; AFocalRadiusRatio: single); 1042 var 1043 m, mInv: TAffineMatrix; 1044 focalInv: TPointF; 1045 begin 1046 FGradient := nil; 1047 SetGradient(BGRABlack,BGRAWhite,False); 1048 1049 m := AffineMatrix((d1-AOrigin).x, (d2-AOrigin).x, AOrigin.x, 1050 (d1-AOrigin).y, (d2-AOrigin).y, AOrigin.y); 1051 if IsAffineMatrixInversible(m) then 1052 begin 1053 mInv := AffineMatrixInverse(m); 1054 focalInv := mInv*AFocal; 1055 end else 1056 focalInv := PointF(0,0); 1057 1058 Init(PointF(0,0), ARadiusRatio, focalInv, AFocalRadiusRatio, AffineMatrixIdentity, m); 1059 end; 1060 1061 constructor TBGRAGradientScanner.Create(AOrigin: TPointF; ARadius: single; 1062 AFocal: TPointF; AFocalRadius: single); 1063 begin 1064 FGradient := nil; 1065 SetGradient(BGRABlack,BGRAWhite,False); 1066 1067 Init(AOrigin, ARadius, AFocal, AFocalRadius, AffineMatrixIdentity, AffineMatrixIdentity); 1068 end; 1069 1070 procedure TBGRAGradientScanner.SetFlipGradient(AValue: boolean); 1071 begin 1072 if FFlipGradient=AValue then Exit; 1073 FFlipGradient:=AValue; 1074 end; 1075 1076 function TBGRAGradientScanner.GetGradientColor(a: single): TBGRAPixel; 1077 begin 1078 if a = EmptySingle then 1079 result := BGRAPixelTransparent 1080 else 1081 begin 1082 if FFlipGradient then a := 1-a; 1083 if FSinus then 1084 begin 1085 a := a*65536; 1086 if (a <= low(int64)) or (a >= high(int64)) then 1087 result := FAverageColor 1088 else 1089 result := FGradient.GetColorAt(Sin65536(round(a) and 65535)); 1090 end else 1091 result := FGradient.GetColorAtF(a); 1092 end; 1093 end; 1094 1095 function TBGRAGradientScanner.GetGradientExpandedColor(a: single): TExpandedPixel; 1096 begin 1097 if a = EmptySingle then 1098 QWord(result) := 0 1099 else 1100 begin 1101 if FFlipGradient then a := 1-a; 1102 if FSinus then 1103 begin 1104 a *= 65536; 1105 if (a <= low(int64)) or (a >= high(int64)) then 1106 result := FAverageExpandedColor 1107 else 1108 result := FGradient.GetExpandedColorAt(Sin65536(round(a) and 65535)); 1109 end else 1110 result := FGradient.GetExpandedColorAtF(a); 1111 end; 1112 end; 1113 1114 procedure TBGRAGradientScanner.Init(AGradientType: TGradientType; AOrigin, d1: TPointF; 1115 ATransform: TAffineMatrix; Sinus: Boolean); 1116 var d2: TPointF; 1117 begin 1118 with (d1-AOrigin) do 1119 d2 := PointF(AOrigin.x+y,AOrigin.y-x); 1120 Init(AGradientType,AOrigin,d1,d2,ATransform,Sinus); 1121 end; 1122 1123 procedure TBGRAGradientScanner.Init(AGradientType: TGradientType; AOrigin, d1, d2: TPointF; 1124 ATransform: TAffineMatrix; Sinus: Boolean); 1125 begin 1126 FGradientType:= AGradientType; 1127 FFlipGradient:= false; 1128 FOrigin := AOrigin; 1129 FDir1 := d1; 1130 FDir2 := d2; 954 1131 FSinus := Sinus; 955 956 //compute vector 957 u.x := o2.x - o1.x; 958 u.y := o2.y - o1.y; 959 len := sqrt(sqr(u.x) + sqr(u.y)); 960 if len <> 0 then 961 begin 962 u.x /= len; 963 u.y /= len; 964 aFactor := 65536/len; 965 aFactorF := 1/len; 966 end 967 else 968 begin 969 aFactor := 0; 970 aFactorF := 0; 971 end; 972 973 FVertical := (((gtype =gtLinear) or (gtype=gtReflected)) and (o1.x=o2.x)) or FGradient.Monochrome; 974 mergedColor := FGradient.GetAverageColor; 975 mergedExpandedColor := FGradient.GetAverageExpandedColor; 976 end; 977 978 procedure TBGRAGradientScanner.InitScanInline(x, y: integer); 979 var p: TPointF; 980 begin 981 p.x := X - FOrigin1.x; 982 p.y := Y - FOrigin1.y; 983 FDotProduct := p.x * u.x + p.y * u.y; 984 FDotProductPerp := p.x * u.y - p.y * u.x; 985 end; 986 987 function TBGRAGradientScanner.ScanNextInline: TBGRAPixel; 988 var 989 a,a2: single; 990 ai: integer; 991 begin 992 if FGradientType >= gtDiamond then 993 begin 994 if FGradientType = gtRadial then 1132 FTransform := ATransform; 1133 FHiddenTransform := AffineMatrixIdentity; 1134 1135 FRadius := 1; 1136 FRelativeFocal := PointF(0,0); 1137 FFocalRadius := 0; 1138 1139 InitGradientType; 1140 InitTransform; 1141 end; 1142 1143 procedure TBGRAGradientScanner.Init(AOrigin: TPointF; ARadius: single; 1144 AFocal: TPointF; AFocalRadius: single; ATransform: TAffineMatrix; AHiddenTransform: TAffineMatrix); 1145 var maxRadius: single; 1146 begin 1147 FGradientType:= gtRadial; 1148 FFlipGradient:= false; 1149 FOrigin := AOrigin; 1150 ARadius := abs(ARadius); 1151 AFocalRadius := abs(AFocalRadius); 1152 maxRadius := max(ARadius,AFocalRadius); 1153 FDir1 := AOrigin+PointF(maxRadius,0); 1154 FDir2 := AOrigin+PointF(0,maxRadius); 1155 FSinus := False; 1156 FTransform := ATransform; 1157 FHiddenTransform := AHiddenTransform; 1158 1159 FRadius := ARadius/maxRadius; 1160 FRelativeFocal := (AFocal - AOrigin)*(1/maxRadius); 1161 FFocalRadius := AFocalRadius/maxRadius; 1162 1163 InitGradientType; 1164 InitTransform; 1165 end; 1166 1167 procedure TBGRAGradientScanner.InitGradientType; 1168 begin 1169 case FGradientType of 1170 gtReflected: begin 1171 FScanNextFunc:= @ScanNextReflected; 1172 FScanAtFunc:= @ScanAtReflected; 1173 end; 1174 gtDiamond: begin 1175 FScanNextFunc:= @ScanNextDiamond; 1176 FScanAtFunc:= @ScanAtDiamond; 1177 end; 1178 gtRadial: if (FRelativeFocal.x = 0) and (FRelativeFocal.y = 0) then 995 1179 begin 996 a := sqrt(sqr(FDotProduct) + sqr(FDotProductPerp)); 997 FDotProduct += u.x; 998 FDotProductPerp += u.y; 1180 if (FFocalRadius = 0) and (FRadius = 1) then 1181 begin 1182 FScanNextFunc:= @ScanNextRadial; 1183 FScanAtFunc:= @ScanAtRadial; 1184 end else 1185 begin 1186 FScanNextFunc:= @ScanNextRadial2; 1187 FScanAtFunc:= @ScanAtRadial2; 1188 end; 999 1189 end else 1000 1190 begin 1001 a := abs(FDotProduct); 1002 a2 := abs(FDotProductPerp); 1003 if a2 > a then a := a2; 1004 FDotProduct += u.x; 1005 FDotProductPerp += u.y; 1191 FScanNextFunc:= @ScanNextRadialFocal; 1192 FScanAtFunc:= @ScanAtRadialFocal; 1193 1194 FFocalDirection := FRelativeFocal; 1195 FFocalDistance := VectLen(FFocalDirection); 1196 if FFocalDistance > 0 then FFocalDirection *= 1/FFocalDistance; 1197 FFocalNormal := PointF(-FFocalDirection.y,FFocalDirection.x); 1198 FRadialDenominator := sqr(FRadius-FFocalRadius)-sqr(FFocalDistance); 1199 1200 //case in which the second circle is bigger and the first circle is within the second 1201 if (FRadius < FFocalRadius) and (FFocalDistance <= FFocalRadius-FRadius) then 1202 FRadialDeltaSign := -1 1203 else 1204 FRadialDeltaSign := 1; 1205 1206 //clipping afer the apex 1207 if (FFocalRadius < FRadius) and (FFocalDistance > FRadius-FFocalRadius) then 1208 begin 1209 maxW1 := FRadius/(FRadius-FFocalRadius)*FFocalDistance; 1210 maxW2 := MaxSingle; 1211 end else 1212 if (FRadius < FFocalRadius) and (FFocalDistance > FFocalRadius-FRadius) then 1213 begin 1214 maxW1 := MaxSingle; 1215 maxW2 := FFocalRadius/(FFocalRadius-FRadius)*FFocalDistance; 1216 end else 1217 begin 1218 maxW1 := MaxSingle; 1219 maxW2 := MaxSingle; 1220 end; 1006 1221 end; 1007 end else 1008 if FGradientType = gtReflected then 1009 begin 1010 a := abs(FDotProduct); 1011 FDotProduct += u.x; 1012 end else 1013 begin 1014 a := FDotProduct; 1015 FDotProduct += u.x; 1016 end; 1017 1018 if FSinus then 1019 begin 1020 a *= aFactor; 1021 if a <= low(int64) then 1022 result := FGradient.GetAverageColor 1023 else 1024 if a >= high(int64) then 1025 result := FGradient.GetAverageColor 1026 else 1027 begin 1028 ai := Sin65536(round(a)); 1029 result := FGradient.GetColorAt(ai); 1222 gtAngular: begin 1223 FScanNextFunc:= @ScanNextAngular; 1224 FScanAtFunc:= @ScanAtAngular; 1030 1225 end; 1031 end else 1032 result := FGradient.GetColorAtF(a*aFactorF); 1033 end; 1034 1035 function TBGRAGradientScanner.ScanNextExpandedInline: TExpandedPixel; 1036 var 1037 a,a2: single; 1038 ai: integer; 1039 begin 1040 if FGradientType >= gtDiamond then 1041 begin 1042 if FGradientType = gtRadial then 1043 begin 1044 a := sqrt(sqr(FDotProduct) + sqr(FDotProductPerp)); 1045 FDotProduct += u.x; 1046 FDotProductPerp += u.y; 1047 end else 1048 begin 1049 a := abs(FDotProduct); 1050 a2 := abs(FDotProductPerp); 1051 if a2 > a then a := a2; 1052 FDotProduct += u.x; 1053 FDotProductPerp += u.y; 1226 else 1227 {gtLinear:} begin 1228 FScanNextFunc:= @ScanNextLinear; 1229 FScanAtFunc:= @ScanAtLinear; 1054 1230 end; 1055 end else 1056 if FGradientType = gtReflected then 1057 begin 1058 a := abs(FDotProduct); 1059 FDotProduct += u.x; 1060 end else 1061 begin 1062 a := FDotProduct; 1063 FDotProduct += u.x; 1064 end; 1065 1066 if FSinus then 1067 begin 1068 a *= aFactor; 1069 if a <= low(int64) then 1070 result := FGradient.GetAverageExpandedColor 1071 else 1072 if a >= high(int64) then 1073 result := FGradient.GetAverageExpandedColor 1074 else 1075 begin 1076 ai := Sin65536(round(a)); 1077 result := FGradient.GetExpandedColorAt(ai); 1078 end; 1079 end else 1080 result := FGradient.GetExpandedColorAtF(a*aFactorF); 1081 end; 1082 1083 constructor TBGRAGradientScanner.Create(c1, c2: TBGRAPixel; 1084 gtype: TGradientType; o1, o2: TPointF; gammaColorCorrection: boolean; 1085 Sinus: Boolean); 1086 begin 1231 end; 1232 end; 1233 1234 procedure TBGRAGradientScanner.SetGradient(c1, c2: TBGRAPixel; 1235 AGammaCorrection: boolean); 1236 begin 1237 if Assigned(FGradient) and FGradientOwner then FreeAndNil(FGradient); 1238 1087 1239 //transparent pixels have no color so 1088 1240 //take it from other color 1089 if c1.alpha = 0 then 1090 begin 1091 c1.red := c2.red; 1092 c1.green := c2.green; 1093 c1.blue := c2.blue; 1094 end 1095 else 1096 if c2.alpha = 0 then 1097 begin 1098 c2.red := c1.red; 1099 c2.green := c1.green; 1100 c2.blue := c1.blue; 1101 end; 1102 1103 if gammaColorCorrection then 1104 begin 1105 FGradient := TBGRASimpleGradientWithGammaCorrection.Create(c1,c2); 1106 FGradientOwner := true; 1241 if c1.alpha = 0 then c1 := BGRA(c2.red,c2.green,c2.blue,0); 1242 if c2.alpha = 0 then c2 := BGRA(c1.red,c1.green,c1.blue,0); 1243 1244 if AGammaCorrection then 1245 FGradient := TBGRASimpleGradientWithGammaCorrection.Create(c1,c2) 1246 else 1247 FGradient := TBGRASimpleGradientWithoutGammaCorrection.Create(c1,c2); 1248 FGradientOwner := true; 1249 InitGradient; 1250 end; 1251 1252 procedure TBGRAGradientScanner.SetGradient(AGradient: TBGRACustomGradient; 1253 AOwner: boolean); 1254 begin 1255 if Assigned(FGradient) and FGradientOwner then FreeAndNil(FGradient); 1256 FGradient := AGradient; 1257 FGradientOwner := AOwner; 1258 InitGradient; 1259 end; 1260 1261 procedure TBGRAGradientScanner.InitTransform; 1262 var u,v: TPointF; 1263 begin 1264 u := FDir1-FOrigin; 1265 if FGradientType in[gtLinear,gtReflected] then 1266 v := PointF(u.y, -u.x) 1267 else 1268 v := FDir2-FOrigin; 1269 1270 FMatrix := FTransform * FHiddenTransform * AffineMatrix(u.x, v.x, FOrigin.x, 1271 u.y, v.y, FOrigin.y); 1272 if IsAffineMatrixInversible(FMatrix) then 1273 begin 1274 FMatrix := AffineMatrixInverse(FMatrix); 1275 FIsAverage:= false; 1107 1276 end else 1108 1277 begin 1109 FGradient := TBGRASimpleGradientWithoutGammaCorrection.Create(c1,c2); 1110 FGradientOwner := true; 1111 end; 1112 Init(gtype,o1,o2,Sinus); 1278 FMatrix := AffineMatrixIdentity; 1279 FIsAverage:= true; 1280 end; 1281 1282 case FGradientType of 1283 gtReflected: FRepeatHoriz := (FMatrix[1,1]=0); 1284 gtDiamond,gtAngular: FRepeatHoriz:= FIsAverage; 1285 gtRadial: begin 1286 if FFocalRadius = FRadius then FIsAverage:= true; 1287 FRepeatHoriz:= FIsAverage; 1288 end 1289 else 1290 {gtLinear:} FRepeatHoriz := (FMatrix[1,1]=0); 1291 end; 1292 1293 if FGradient.Monochrome then 1294 begin 1295 FRepeatHoriz:= true; 1296 FIsAverage:= true; 1297 end; 1298 1299 FPosition := PointF(0,0); 1300 end; 1301 1302 procedure TBGRAGradientScanner.InitGradient; 1303 begin 1304 FAverageColor := FGradient.GetAverageColor; 1305 FAverageExpandedColor := FGradient.GetAverageExpandedColor; 1306 end; 1307 1308 function TBGRAGradientScanner.ComputeRadialFocal(const p: TPointF): single; 1309 var 1310 w1,w2,h,d1,d2,delta,num: single; 1311 begin 1312 w1 := p*FFocalDirection; 1313 w2 := FFocalDistance-w1; 1314 if (w1 < maxW1) and (w2 < maxW2) then 1315 begin 1316 //vertical position and distances 1317 h := sqr(p*FFocalNormal); 1318 d1 := sqr(w1)+h; 1319 d2 := sqr(w2)+h; 1320 //finding t 1321 delta := sqr(FFocalRadius)*d1 + 2*FRadius*FFocalRadius*(p*(FRelativeFocal-p))+ 1322 sqr(FRadius)*d2 - sqr(VectDet(p,FRelativeFocal)); 1323 if delta >= 0 then 1324 begin 1325 num := -FFocalRadius*(FRadius-FFocalRadius)-(FRelativeFocal*(FRelativeFocal-p)); 1326 result := (num+FRadialDeltaSign*sqrt(delta))/FRadialDenominator; 1327 end else 1328 result := EmptySingle; 1329 end else 1330 result := EmptySingle; 1331 end; 1332 1333 function TBGRAGradientScanner.ScanNextLinear: single; 1334 begin 1335 result := FPosition.x; 1336 end; 1337 1338 function TBGRAGradientScanner.ScanNextReflected: single; 1339 begin 1340 result := abs(FPosition.x); 1341 end; 1342 1343 function TBGRAGradientScanner.ScanNextDiamond: single; 1344 begin 1345 result := max(abs(FPosition.x), abs(FPosition.y)); 1346 end; 1347 1348 function TBGRAGradientScanner.ScanNextRadial: single; 1349 begin 1350 result := sqrt(sqr(FPosition.x) + sqr(FPosition.y)); 1351 end; 1352 1353 function TBGRAGradientScanner.ScanNextRadial2: single; 1354 begin 1355 result := (sqrt(sqr(FPosition.x) + sqr(FPosition.y))-FFocalRadius)/(FRadius-FFocalRadius); 1356 end; 1357 1358 function TBGRAGradientScanner.ScanNextRadialFocal: single; 1359 begin 1360 result := ComputeRadialFocal(FPosition); 1361 end; 1362 1363 function TBGRAGradientScanner.ScanNextAngular: single; 1364 begin 1365 if FPosition.y >= 0 then 1366 result := arctan2(FPosition.y,FPosition.x)/(2*Pi) 1367 else 1368 result := 1-arctan2(-FPosition.y,FPosition.x)/(2*Pi) 1369 end; 1370 1371 function TBGRAGradientScanner.ScanAtLinear(const p: TPointF): single; 1372 begin 1373 with (FMatrix*p) do 1374 result := x; 1375 end; 1376 1377 function TBGRAGradientScanner.ScanAtReflected(const p: TPointF): single; 1378 begin 1379 with (FMatrix*p) do 1380 result := abs(x); 1381 end; 1382 1383 function TBGRAGradientScanner.ScanAtDiamond(const p: TPointF): single; 1384 begin 1385 with (FMatrix*p) do 1386 result := max(abs(x), abs(y)); 1387 end; 1388 1389 function TBGRAGradientScanner.ScanAtRadial(const p: TPointF): single; 1390 begin 1391 with (FMatrix*p) do 1392 result := sqrt(sqr(x) + sqr(y)); 1393 end; 1394 1395 function TBGRAGradientScanner.ScanAtRadial2(const p: TPointF): single; 1396 begin 1397 with (FMatrix*p) do 1398 result := (sqrt(sqr(x) + sqr(y))-FFocalRadius)/(FRadius-FFocalRadius); 1399 end; 1400 1401 function TBGRAGradientScanner.ScanAtRadialFocal(const p: TPointF): single; 1402 begin 1403 result := ComputeRadialFocal(FMatrix*p); 1404 end; 1405 1406 function TBGRAGradientScanner.ScanAtAngular(const p: TPointF): single; 1407 begin 1408 with (FMatrix*p) do 1409 begin 1410 if y >= 0 then 1411 result := arctan2(y,x)/(2*Pi) 1412 else 1413 result := 1-arctan2(-y,x)/(2*Pi) 1414 end; 1415 end; 1416 1417 function TBGRAGradientScanner.ScanNextInline: TBGRAPixel; 1418 begin 1419 if FIsAverage then 1420 result := FAverageColor 1421 else 1422 begin 1423 result := GetGradientColor(FScanNextFunc()); 1424 FPosition += PointF(FMatrix[1,1],FMatrix[2,1]); 1425 end; 1426 end; 1427 1428 function TBGRAGradientScanner.ScanNextExpandedInline: TExpandedPixel; 1429 begin 1430 if FIsAverage then 1431 result := FAverageExpandedColor 1432 else 1433 begin 1434 result := GetGradientExpandedColor(FScanNextFunc()); 1435 FPosition += PointF(FMatrix[1,1],FMatrix[2,1]); 1436 end; 1437 end; 1438 1439 constructor TBGRAGradientScanner.Create(c1, c2: TBGRAPixel; 1440 AGradientType: TGradientType; AOrigin, d1: TPointF; gammaColorCorrection: boolean; 1441 Sinus: Boolean); 1442 begin 1443 FGradient := nil; 1444 SetGradient(c1,c2,gammaColorCorrection); 1445 Init(AGradientType,AOrigin,d1,AffineMatrixIdentity,Sinus); 1446 end; 1447 1448 constructor TBGRAGradientScanner.Create(c1, c2: TBGRAPixel; 1449 AGradientType: TGradientType; AOrigin, d1, d2: TPointF; gammaColorCorrection: boolean; 1450 Sinus: Boolean); 1451 begin 1452 FGradient := nil; 1453 if AGradientType in[gtLinear,gtReflected] then raise EInvalidArgument.Create('Two directions are not required for linear and reflected gradients'); 1454 SetGradient(c1,c2,gammaColorCorrection); 1455 Init(AGradientType,AOrigin,d1,d2,AffineMatrixIdentity,Sinus); 1113 1456 end; 1114 1457 1115 1458 constructor TBGRAGradientScanner.Create(gradient: TBGRACustomGradient; 1116 gtype: TGradientType; o1, o2: TPointF; Sinus: Boolean; AGradientOwner: Boolean=False);1459 AGradientType: TGradientType; AOrigin, d1: TPointF; Sinus: Boolean; AGradientOwner: Boolean=False); 1117 1460 begin 1118 1461 FGradient := gradient; 1119 1462 FGradientOwner := AGradientOwner; 1120 Init(gtype,o1,o2,Sinus); 1463 Init(AGradientType,AOrigin,d1,AffineMatrixIdentity,Sinus); 1464 end; 1465 1466 constructor TBGRAGradientScanner.Create(gradient: TBGRACustomGradient; 1467 AGradientType: TGradientType; AOrigin, d1, d2: TPointF; Sinus: Boolean; 1468 AGradientOwner: Boolean); 1469 begin 1470 if AGradientType in[gtLinear,gtReflected] then raise EInvalidArgument.Create('Two directions are not required for linear and reflected gradients'); 1471 FGradient := gradient; 1472 FGradientOwner := AGradientOwner; 1473 Init(AGradientType,AOrigin,d1,d2,AffineMatrixIdentity,Sinus); 1474 end; 1475 1476 constructor TBGRAGradientScanner.Create(gradient: TBGRACustomGradient; 1477 AOrigin: TPointF; ARadius: single; AFocal: TPointF; AFocalRadius: single; 1478 AGradientOwner: Boolean); 1479 begin 1480 FGradient := gradient; 1481 FGradientOwner := AGradientOwner; 1482 Init(AOrigin, ARadius, AFocal, AFocalRadius, AffineMatrixIdentity, AffineMatrixIdentity); 1121 1483 end; 1122 1484 … … 1130 1492 procedure TBGRAGradientScanner.ScanMoveTo(X, Y: Integer); 1131 1493 begin 1132 InitScanInline(X,Y);1133 if F Verticalthen1494 FPosition := FMatrix*PointF(x,y); 1495 if FRepeatHoriz then 1134 1496 begin 1135 1497 FHorizColor := ScanNextInline; … … 1140 1502 function TBGRAGradientScanner.ScanNextPixel: TBGRAPixel; 1141 1503 begin 1142 if F Verticalthen1504 if FRepeatHoriz then 1143 1505 result := FHorizColor 1144 1506 else … … 1148 1510 function TBGRAGradientScanner.ScanNextExpandedPixel: TExpandedPixel; 1149 1511 begin 1150 if F Verticalthen1512 if FRepeatHoriz then 1151 1513 result := FHorizExpandedColor 1152 1514 else … … 1155 1517 1156 1518 function TBGRAGradientScanner.ScanAt(X, Y: Single): TBGRAPixel; 1157 var p: TPointF; 1158 a,a2: single; 1159 ai: integer; 1160 begin 1161 if len = 0 then 1162 begin 1163 result := mergedColor; 1164 exit; 1165 end; 1166 1167 p.x := X - FOrigin1.x; 1168 p.y := Y - FOrigin1.y; 1169 case FGradientType of 1170 gtLinear: a := p.x * u.x + p.y * u.y; 1171 gtReflected: a := abs(p.x * u.x + p.y * u.y); 1172 gtDiamond: 1173 begin 1174 a := abs(p.x * u.x + p.y * u.y); 1175 a2 := abs(p.x * u.y - p.y * u.x); 1176 if a2 > a then a := a2; 1177 end; 1178 gtRadial: a := sqrt(sqr(p.x * u.x + p.y * u.y) + sqr(p.x * u.y - p.y * u.x)); 1179 end; 1180 1181 if FSinus then 1182 begin 1183 a := a*aFactor; 1184 if (a <= low(int64)) or (a >= high(int64)) then 1185 result := mergedColor 1186 else 1187 begin 1188 ai := Sin65536(round(a)); 1189 result := FGradient.GetColorAt(ai); 1190 end; 1191 end else 1192 result := FGradient.GetColorAtF(a*aFactorF); 1519 begin 1520 if FIsAverage then 1521 result := FAverageColor 1522 else 1523 result := GetGradientColor(FScanAtFunc(PointF(X,Y))); 1193 1524 end; 1194 1525 1195 1526 function TBGRAGradientScanner.ScanAtExpanded(X, Y: Single): TExpandedPixel; 1196 var p: TPointF; 1197 a,a2: single; 1198 ai: integer; 1199 begin 1200 if len = 0 then 1201 begin 1202 result := mergedExpandedColor; 1203 exit; 1204 end; 1205 1206 p.x := X - FOrigin1.x; 1207 p.y := Y - FOrigin1.y; 1208 case FGradientType of 1209 gtLinear: a := p.x * u.x + p.y * u.y; 1210 gtReflected: a := abs(p.x * u.x + p.y * u.y); 1211 gtDiamond: 1212 begin 1213 a := abs(p.x * u.x + p.y * u.y); 1214 a2 := abs(p.x * u.y - p.y * u.x); 1215 if a2 > a then a := a2; 1216 end; 1217 gtRadial: a := sqrt(sqr(p.x * u.x + p.y * u.y) + sqr(p.x * u.y - p.y * u.x)); 1218 end; 1219 1220 if FSinus then 1221 begin 1222 a := a*aFactor; 1223 if (a <= low(int64)) or (a >= high(int64)) then 1224 result := mergedExpandedColor 1225 else 1226 begin 1227 ai := Sin65536(round(a)); 1228 result := FGradient.GetExpandedColorAt(ai); 1229 end; 1230 end else 1231 result := FGradient.GetExpandedColorAtF(a*aFactorF); 1527 begin 1528 if FIsAverage then 1529 result := FAverageExpandedColor 1530 else 1531 result := GetGradientExpandedColor(FScanAtFunc(PointF(X,Y))); 1232 1532 end; 1233 1533 … … 1236 1536 var c: TBGRAPixel; 1237 1537 begin 1238 if FVertical or (len = 0) then 1239 begin 1240 if FVertical then c := FHorizColor 1241 else c := mergedColor; 1538 if FRepeatHoriz then 1539 begin 1540 c := FHorizColor; 1242 1541 case mode of 1243 1542 dmDrawWithTransparency: DrawPixelsInline(pdest,c,count); … … 1573 1872 FScanAt := @FTexture.ScanAt; 1574 1873 FGlobalOpacity:= AGlobalOpacity; 1874 FOwnedScanner := nil; 1875 end; 1876 1877 constructor TBGRAOpacityScanner.Create(ATexture: TBGRACustomScanner; 1878 AGlobalOpacity: Byte; AOwned: boolean); 1879 begin 1880 FTexture := ATexture; 1881 FScanNext := @FTexture.ScanNextPixel; 1882 FScanAt := @FTexture.ScanAt; 1883 FGlobalOpacity:= AGlobalOpacity; 1884 if AOwned then 1885 FOwnedScanner := ATexture 1886 else 1887 FOwnedScanner := nil; 1575 1888 end; 1576 1889 … … 1578 1891 begin 1579 1892 fillchar(FTexture,sizeof(FTexture),0); 1893 FOwnedScanner.Free; 1580 1894 inherited Destroy; 1581 1895 end;
Note:
See TracChangeset
for help on using the changeset viewer.