Difference between revisions of "BGRABitmap tutorial 11"

From Lazarus wiki
Jump to navigationJump to search
(→‎Run the program: multiply gradient)
(link to AggPas sample)
 
(8 intermediate revisions by 6 users not shown)
Line 3: Line 3:
 
{{BGRABitmap_tutorial_index}}
 
{{BGRABitmap_tutorial_index}}
  
This tutorial shows how to combine transformations.
+
This tutorial shows how to combine transformations. A sample project can be found in [[BGRABitmap AggPas#Alpha gradient|BGRABitmap AggPas]].
  
 
=== Create a new project ===
 
=== Create a new project ===
Line 11: Line 11:
 
=== Affine transformation of a radial gradient ===
 
=== Affine transformation of a radial gradient ===
  
Here is an affine transformation applied on a gradient like we did with textures :
+
Here is an affine transformation applied on a gradient like we did with textures:
<delphi>uses BGRAGradientScanner, BGRATransform;   
+
 
 +
<syntaxhighlight lang="pascal">
 +
uses BGRAGradientScanner, BGRATransform;   
  
 
procedure TForm1.FormPaint(Sender: TObject);
 
procedure TForm1.FormPaint(Sender: TObject);
Line 35: Line 37:
 
   image.Draw(Canvas,0,0,True);
 
   image.Draw(Canvas,0,0,True);
 
   image.free;
 
   image.free;
end;  </delphi>
+
end;   
 +
</syntaxhighlight>
  
 
The base gradient is radial, centered at origin (0,0), of radius 1.
 
The base gradient is radial, centered at origin (0,0), of radius 1.
  
The affine transformations does the following :
+
The affine transformation does the following:
 +
 
 
* stretch the gradient to a size of 150x80
 
* stretch the gradient to a size of 150x80
 
* rotate 30 degrees in counterclockwise direction
 
* rotate 30 degrees in counterclockwise direction
Line 54: Line 58:
 
=== Combine with a twirl ===
 
=== Combine with a twirl ===
  
We can add another transformation to it like this :
+
We can add another transformation to it like this:
<delphi>var image: TBGRABitmap;
+
 
 +
<syntaxhighlight lang="pascal">
 +
var image: TBGRABitmap;
 
     grad: TBGRAGradientScanner;
 
     grad: TBGRAGradientScanner;
 
     affine: TBGRAAffineScannerTransform;
 
     affine: TBGRAAffineScannerTransform;
     twirl: TTwirl;
+
     twirl: TBGRATwirlScanner;
 
begin
 
begin
 
   image := TBGRABitmap.Create(ClientWidth,ClientHeight, BGRABlack );
 
   image := TBGRABitmap.Create(ClientWidth,ClientHeight, BGRABlack );
Line 69: Line 75:
 
   affine.Translate(ClientWidth/2, ClientHeight/2);
 
   affine.Translate(ClientWidth/2, ClientHeight/2);
  
   twirl := TTwirl.Create(affine,Point(ClientWidth div 2, ClientHeight div 2),100);
+
   twirl := TBGRATwirlScanner.Create(affine,Point(ClientWidth div 2, ClientHeight div 2),100);
 
   image.Fill(twirl);
 
   image.Fill(twirl);
 
   twirl.Free;
 
   twirl.Free;
Line 78: Line 84:
 
   image.Draw(Canvas,0,0,True);
 
   image.Draw(Canvas,0,0,True);
 
   image.free;
 
   image.free;
end; </delphi>
+
end;  
 +
</syntaxhighlight>
  
 
Here, we simply create a twirl transformation applied to the previous one, and fill with it.
 
Here, we simply create a twirl transformation applied to the previous one, and fill with it.
Line 90: Line 97:
 
=== Use a custom scanner ===
 
=== Use a custom scanner ===
  
We may want to create our one gradient generator. Here is for example a multiply gradient :
+
We may want to create our own gradient generator. Here is for example a multiply gradient:
<delphi>type
+
 
 +
<syntaxhighlight lang="pascal">
 +
type
 
   { TBGRAMultiplyScanner }
 
   { TBGRAMultiplyScanner }
  
Line 112: Line 121:
 
   mul := cycle512(round(x*y));
 
   mul := cycle512(round(x*y));
 
   result := BGRA(mul,mul,mul,255);
 
   result := BGRA(mul,mul,mul,255);
end; </delphi>
+
end;  
 +
</syntaxhighlight>
  
It is derived from TBGRACustomScanner to be used for filling, and the ScanAt function is overriden. It computes the product of both coordinates and make a cycle of 512 with it (from 0 to 255 and then from 255 down to 0).
+
It is derived from TBGRACustomScanner to be used for filling, and the ScanAt function is overridden. It computes the product of both coordinates and make a cycle of 512 with it (from 0 to 255 and then from 255 down to 0).
  
Let's draw it on the screen with a simple affine transformation :
+
Let's draw it on the screen with a simple affine transformation:
<delphi>var image: TBGRABitmap;
+
 
 +
<syntaxhighlight lang="pascal">
 +
var image: TBGRABitmap;
 
     grad: TBGRAMultiplyScanner;
 
     grad: TBGRAMultiplyScanner;
 
     affine: TBGRAAffineScannerTransform;
 
     affine: TBGRAAffineScannerTransform;
Line 126: Line 138:
 
   affine := TBGRAAffineScannerTransform.Create(grad);
 
   affine := TBGRAAffineScannerTransform.Create(grad);
 
   affine.Scale(6,4);
 
   affine.Scale(6,4);
  affine.RotateDeg(-30);
 
 
   affine.Translate(ClientWidth/2, ClientHeight/2);
 
   affine.Translate(ClientWidth/2, ClientHeight/2);
 
   image.Fill(affine);
 
   image.Fill(affine);
Line 134: Line 145:
 
   image.Draw(Canvas,0,0,True);
 
   image.Draw(Canvas,0,0,True);
 
   image.free;
 
   image.free;
end; </delphi>
+
end;  
 +
</syntaxhighlight>
  
 
=== Run the program ===
 
=== Run the program ===
  
It should look like this :
+
It should look like this:
  
 
[[Image:BGRATutorial11c.png]]
 
[[Image:BGRATutorial11c.png]]
Line 144: Line 156:
 
=== Make it beautiful ===
 
=== Make it beautiful ===
  
Add some colors by modifying the ScanAt procedure of the multiply gradient :
+
Add some colors by modifying the ScanAt procedure of the multiply gradient:
<delphi>var
+
 
 +
<syntaxhighlight lang="pascal">
 +
var
 
   mul: integer;
 
   mul: integer;
 
begin
 
begin
 
   mul := round(x*y);
 
   mul := round(x*y);
 
   result := BGRA(cycle512(round(x*10)),cycle512(mul),cycle512(round(y*10)),255);
 
   result := BGRA(cycle512(round(x*10)),cycle512(mul),cycle512(round(y*10)),255);
end;  </delphi>
+
end;   
 +
</syntaxhighlight>
  
 
The red and blue intensities are filled with a cycle of x and y positions.
 
The red and blue intensities are filled with a cycle of x and y positions.
  
And add some rotation :
+
And add some rotation:
<delphi> affine := TBGRAAffineScannerTransform.Create(grad);
+
 
 +
<syntaxhighlight lang="pascal">
 +
  affine := TBGRAAffineScannerTransform.Create(grad);
 
   affine.Scale(6,4);
 
   affine.Scale(6,4);
 
   affine.RotateDeg(-30);
 
   affine.RotateDeg(-30);
   affine.Translate(ClientWidth/2, ClientHeight/2); </delphi>
+
   affine.Translate(ClientWidth/2, ClientHeight/2);  
 +
</syntaxhighlight>
  
 
[[Image:BGRATutorial11d.png]]
 
[[Image:BGRATutorial11d.png]]
  
[[BGRABitmap tutorial 10|Previous tutorial (texture mapping)]]
+
[[BGRABitmap tutorial 10|Previous tutorial (texture mapping)]] [[BGRABitmap tutorial 12|Next tutorial (text functions)]]
 +
 
 +
[[Category:Graphics]]
 +
[[Category: BGRABitmap]]

Latest revision as of 11:48, 20 May 2023

Deutsch (de) English (en) español (es) français (fr)


Home | Tutorial 1 | Tutorial 2 | Tutorial 3 | Tutorial 4 | Tutorial 5 | Tutorial 6 | Tutorial 7 | Tutorial 8 | Tutorial 9 | Tutorial 10 | Tutorial 11 | Tutorial 12 | Tutorial 13 | Tutorial 14 | Tutorial 15 | Tutorial 16 | Edit

This tutorial shows how to combine transformations. A sample project can be found in BGRABitmap AggPas.

Create a new project

Create a new project and add a reference to BGRABitmap, the same way as in the first tutorial.

Affine transformation of a radial gradient

Here is an affine transformation applied on a gradient like we did with textures:

uses BGRAGradientScanner, BGRATransform;   

procedure TForm1.FormPaint(Sender: TObject);
var image: TBGRABitmap;
    grad: TBGRAGradientScanner;
    affine: TBGRAAffineScannerTransform;
begin
  image := TBGRABitmap.Create(ClientWidth,ClientHeight, BGRABlack );

  grad := TBGRAGradientScanner.Create(BGRA(0,0,255),BGRAWhite,gtRadial,PointF(0,0),PointF(1,0),True,True);

  affine := TBGRAAffineScannerTransform.Create(grad);
  affine.Scale(150,80);
  affine.RotateDeg(-30);
  affine.Translate(ClientWidth/2, ClientHeight/2);

  image.Fill(affine);

  affine.free;
  grad.free;

  image.Draw(Canvas,0,0,True);
  image.free;
end;

The base gradient is radial, centered at origin (0,0), of radius 1.

The affine transformation does the following:

  • stretch the gradient to a size of 150x80
  • rotate 30 degrees in counterclockwise direction
  • center it in the form

The Fill instruction draws the result into the image.

Run the program

You should obtain a blue and white ellipse gradient.

BGRATutorial11a.png

Combine with a twirl

We can add another transformation to it like this:

var image: TBGRABitmap;
    grad: TBGRAGradientScanner;
    affine: TBGRAAffineScannerTransform;
    twirl: TBGRATwirlScanner;
begin
  image := TBGRABitmap.Create(ClientWidth,ClientHeight, BGRABlack );

  grad := TBGRAGradientScanner.Create(BGRA(0,0,255),BGRAWhite,gtRadial,PointF(0,0),PointF(1,0),True,True);

  affine := TBGRAAffineScannerTransform.Create(grad);
  affine.Scale(150,80);
  affine.RotateDeg(-30);
  affine.Translate(ClientWidth/2, ClientHeight/2);

  twirl := TBGRATwirlScanner.Create(affine,Point(ClientWidth div 2, ClientHeight div 2),100);
  image.Fill(twirl);
  twirl.Free;

  affine.free;
  grad.free;

  image.Draw(Canvas,0,0,True);
  image.free;
end;

Here, we simply create a twirl transformation applied to the previous one, and fill with it.

Run the program

Now the center of the gradient is twirled.

BGRATutorial11b.png

Use a custom scanner

We may want to create our own gradient generator. Here is for example a multiply gradient:

type
  { TBGRAMultiplyScanner }

  TBGRAMultiplyScanner = class(TBGRACustomScanner)
    function ScanAt(X, Y: Single): TBGRAPixel; override;
  end;

{ TBGRAMultiplyScanner }

function TBGRAMultiplyScanner.ScanAt(X, Y: Single): TBGRAPixel;
  function cycle512(value: integer): integer; inline;
  begin
    result := value and 511;
    if result >= 256 then result := 511-result;
  end;

var
  mul: integer;
begin
  mul := cycle512(round(x*y));
  result := BGRA(mul,mul,mul,255);
end;

It is derived from TBGRACustomScanner to be used for filling, and the ScanAt function is overridden. It computes the product of both coordinates and make a cycle of 512 with it (from 0 to 255 and then from 255 down to 0).

Let's draw it on the screen with a simple affine transformation:

var image: TBGRABitmap;
    grad: TBGRAMultiplyScanner;
    affine: TBGRAAffineScannerTransform;
begin
  image := TBGRABitmap.Create(ClientWidth,ClientHeight, BGRABlack );

  grad := TBGRAMultiplyScanner.Create;
  affine := TBGRAAffineScannerTransform.Create(grad);
  affine.Scale(6,4);
  affine.Translate(ClientWidth/2, ClientHeight/2);
  image.Fill(affine);
  affine.free;
  grad.free;

  image.Draw(Canvas,0,0,True);
  image.free;
end;

Run the program

It should look like this:

BGRATutorial11c.png

Make it beautiful

Add some colors by modifying the ScanAt procedure of the multiply gradient:

var
  mul: integer;
begin
  mul := round(x*y);
  result := BGRA(cycle512(round(x*10)),cycle512(mul),cycle512(round(y*10)),255);
end;

The red and blue intensities are filled with a cycle of x and y positions.

And add some rotation:

  affine := TBGRAAffineScannerTransform.Create(grad);
  affine.Scale(6,4);
  affine.RotateDeg(-30);
  affine.Translate(ClientWidth/2, ClientHeight/2);

BGRATutorial11d.png

Previous tutorial (texture mapping) Next tutorial (text functions)