123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- unit fGradLines;
- (* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1 or LGPL 2.1 with linking exception
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * Alternatively, the contents of this file may be used under the terms of the
- * Free Pascal modified version of the GNU Lesser General Public License
- * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
- * of this license are applicable instead of those above.
- * Please see the file LICENSE.txt for additional information concerning this
- * license.
- *
- * The Original Code is Gradient Lines Example
- *
- * The Initial Developer of the Original Code is
- * Alex A. Denisov
- *
- * Portions created by the Initial Developer are Copyright (C) 2000-2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** *)
- interface
- {$I GR32.inc}
- uses
- {$IFDEF FPC} LCLIntf, LResources, Buttons, {$ENDIF} SysUtils, Classes,
- Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
- {$IFDEF COMPILERXE2_UP}Types, {$ENDIF}
- GR32, GR32_Blend, GR32_Image, GR32_LowLevel;
- type
- TVector2f = record
- X, Y: Single;
- end;
- TLine = class
- public
- Bitmap: TBitmap32;
- P1, P2: TVector2f; // positions
- V1, V2: TVector2f; // velocities
- C1, C2, C3: TColor32; // colors that define gradient pattern
- t1, t2, t3: Single;
- MaxVelocity: Single;
- constructor Create(ABitmap: TBitmap32);
- procedure Advance(DeltaT: Single);
- function GetLength: Single;
- procedure Paint;
- end;
- { TFormGradientLines }
- TFormGradientLines = class(TForm)
- BtnAddOne: TButton;
- BtnAddTen: TButton;
- BtnClear: TButton;
- LblTotal: TLabel;
- Memo: TMemo;
- PaintBox: TPaintBox32;
- PnlTotalLines: TPanel;
- RgpDraw: TRadioGroup;
- RgpFade: TRadioGroup;
- RepaintOpt: TCheckBox;
- procedure FormCreate(Sender: TObject);
- procedure RepaintOptClick(Sender: TObject);
- procedure BtnAddOneClick(Sender: TObject);
- procedure BtnAddTenClick(Sender: TObject);
- procedure BtnClearClick(Sender: TObject);
- procedure RgpFadeClick(Sender: TObject);
- procedure RgpDrawClick(Sender: TObject);
- protected
- Lines: array of TLine;
- P: TPoint; // mouse shift
- M: Boolean; // mouse down flag
- FadeCount: Integer;
- Pass: Integer;
- DrawPasses: Integer;
- procedure AppEventsIdle(Sender: TObject; var Done: Boolean);
- public
- procedure AddLine;
- procedure AddLines(N: Integer);
- end;
- var
- FormGradientLines: TFormGradientLines;
- implementation
- {$IFDEF FPC}
- {$R *.lfm}
- {$ELSE}
- {$R *.dfm}
- {$ENDIF}
- uses Math;
- function VectorAdd(const A, B: TVector2f): TVector2f;
- begin
- Result.X := A.X + B.X;
- Result.Y := A.Y + B.Y;
- end;
- function VectorSub(const A, B: TVector2f): TVector2f;
- begin
- Result.X := A.X - B.X;
- Result.Y := A.Y - B.Y;
- end;
- function VectorLen(const A: TVector2f): Single;
- begin
- Result := SqRt(SqR(A.X) + SqR(A.Y));
- end;
- function VectorDot(const A, B: TVector2f): Single;
- begin
- Result := A.X * B.X + A.Y * B.Y;
- end;
- function VectorScale(const A: TVector2f; Factor: Single): TVector2f;
- begin
- Result.X := A.X * Factor;
- Result.Y := A.Y * Factor;
- end;
- { TLine }
- constructor TLine.Create(ABitmap: TBitmap32);
- begin
- Bitmap := ABitmap;
- MaxVelocity := 1;
- end;
- procedure TLine.Advance(DeltaT: Single);
- const
- COne400 : Single = 1 / 400;
- COne300 : Single = 1 / 300;
- procedure AdvancePoint(var P, V: TVector2f; t: Single);
- begin
- { apply velocities }
- P := VectorAdd(P, VectorScale(V, t));
- { reflect from walls }
- if P.X < 0 then
- begin
- P.X := 0;
- V.X := -V.X;
- end;
- if P.X >= FormGradientLines.PaintBox.Width then
- begin
- P.X := FormGradientLines.PaintBox.Width - 1;
- V.X := - V.X;
- end;
- if P.Y < 0 then
- begin
- P.Y := 0;
- V.Y := -V.Y;
- end;
- if P.Y >= FormGradientLines.PaintBox.Height then
- begin
- P.Y := FormGradientLines.PaintBox.Height - 1;
- V.Y := - V.Y
- end;
- { change velocity a little bit }
- V.X := V.X + t * (Random - 0.5) * 0.25;
- V.Y := V.Y + t * (Random - 0.5) * 0.25;
- { limit velocity }
- if VectorLen(V) > MaxVelocity then
- V := VectorScale(V, 1 / VectorLen(V));
- end;
- begin
- AdvancePoint(P1, V1, DeltaT);
- AdvancePoint(P2, V2, DeltaT);
- C1 := HSLtoRGB(t1, Sin(t1 * 0.55) * 0.4 + 0.6, 0.5);
- C1 := SetAlpha(C1, Round(Sin(t1) * 25 + 50));
- t1 := t1 + Random * COne300;
- C2 := HSLtoRGB(t2, Sin(t2 * 0.55) * 0.4 + 0.6, 0.5);
- C2 := SetAlpha(C2, Round(Sin(t2) * 25 + 50));
- t2 := t2 + Random * COne400;
- C3 := HSLtoRGB(t3, Sin(t3 * 0.55) * 0.4 + 0.6, 0.5);
- C3 := SetAlpha(C3, Round(Sin(t3) * 25 + 50));
- t3 := t3 + Random * COne400;
- end;
- function TLine.GetLength: Single;
- begin
- Result := VectorLen(VectorSub(P1, P2));
- end;
- procedure TLine.Paint;
- var
- L: Single;
- begin
- // this shows how to draw a gradient line
- L := GetLength;
- if L < 1 then Exit;
- Bitmap.SetStipple([C1, C2, C3]);
- Bitmap.StippleStep := 2 / L; {2 = 3 - 1 = Number of colors in a pattern - 1}
- Bitmap.StippleCounter := 0;
- Bitmap.LineFSP(P1.X, P1.Y, P2.X, P2.Y);
- end;
- { TFormGradientLines }
- procedure TFormGradientLines.FormCreate(Sender: TObject);
- begin
- FadeCount := 0;
- DrawPasses := 2;
- Application.OnIdle := AppEventsIdle;
- end;
- procedure TFormGradientLines.AddLine;
- var
- L: TLine;
- begin
- SetLength(Lines, Length(Lines) + 1);
- L := TLine.Create(PaintBox.Buffer);
- Lines[High(Lines)] := L;
- L.t1 := Random * 3;
- L.t2 := Random * 3;
- L.t3 := Random * 3;
- L.P1.X := Random(PaintBox.Buffer.Width div 2 - 1);
- L.P2.X := Random(PaintBox.Buffer.Width div 2 - 1);
- L.P1.Y := Random(PaintBox.Buffer.Height div 2 - 1);
- L.P2.Y := Random(PaintBox.Buffer.Height div 2 - 1);
- PnlTotalLines.Caption := IntToStr(Length(Lines));
- end;
- procedure TFormGradientLines.AddLines(N: Integer);
- var
- Index: Integer;
- begin
- for Index := 0 to N - 1 do AddLine;
- end;
- procedure TFormGradientLines.AppEventsIdle(Sender: TObject; var Done: Boolean);
- var
- I, J: Integer;
- P: PColor32;
- begin
- for J := 0 to DrawPasses - 1 do
- for I := 0 to High(Lines) do
- begin
- Lines[I].Advance(1);
- Lines[I].Paint;
- end;
- if FadeCount > 0 then
- begin
- if Pass = 0 then with PaintBox.Buffer do
- begin
- P := @Bits[0];
- for I := 0 to Width * Height -1 do
- begin
- BlendMem($10000000, P^);
- Inc(P);
- end;
- EMMS;
- end;
- Dec(Pass);
- if (Pass < 0) or (Pass > FadeCount) then Pass := FadeCount;
- // we're doing unsafe operations above, so force a complete invalidation
- // so that wrong output of repaint optimizer doesn't show.
- PaintBox.ForceFullInvalidate;
- end
- else
- PaintBox.Invalidate;
- end;
- procedure TFormGradientLines.BtnAddOneClick(Sender: TObject);
- begin
- AddLine;
- end;
- procedure TFormGradientLines.BtnAddTenClick(Sender: TObject);
- begin
- AddLines(10);
- end;
- procedure TFormGradientLines.BtnClearClick(Sender: TObject);
- var
- Index: Integer;
- begin
- for Index := High(Lines) downto 0 do Lines[Index].Free;
- Lines := nil;
- PaintBox.Buffer.Clear;
- PnlTotalLines.Caption := '0';
- end;
-
- procedure TFormGradientLines.RgpFadeClick(Sender: TObject);
- const
- FC: array [0..2] of Integer = (0, 7, 1);
- begin
- FadeCount := FC[RgpFade.ItemIndex];
- end;
- procedure TFormGradientLines.RgpDrawClick(Sender: TObject);
- begin
- DrawPasses := (RgpDraw.ItemIndex + 1) * 3 - 2;
- end;
- procedure TFormGradientLines.RepaintOptClick(Sender: TObject);
- begin
- if RepaintOpt.Checked then
- PaintBox.RepaintMode := rmOptimizer
- else
- PaintBox.RepaintMode := rmFull;
- end;
- end.
|