Difference between revisions of "BGRABitmap tutorial 11"

From Lazarus wiki
Jump to navigationJump to search
m (→‎Use a custom scanner: rotation later)
m (Text replace - "delphi>" to "syntaxhighlight>")
Line 12: Line 12:
  
 
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>uses BGRAGradientScanner, BGRATransform;   
  
 
procedure TForm1.FormPaint(Sender: TObject);
 
procedure TForm1.FormPaint(Sender: TObject);
Line 35: Line 35:
 
   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.
Line 55: Line 55:
  
 
We can add another transformation to it like this :
 
We can add another transformation to it like this :
<delphi>var image: TBGRABitmap;
+
<syntaxhighlight>var image: TBGRABitmap;
 
     grad: TBGRAGradientScanner;
 
     grad: TBGRAGradientScanner;
 
     affine: TBGRAAffineScannerTransform;
 
     affine: TBGRAAffineScannerTransform;
Line 78: Line 78:
 
   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 91: Line 91:
  
 
We may want to create our own 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>type
 
   { TBGRAMultiplyScanner }
 
   { TBGRAMultiplyScanner }
  
Line 112: Line 112:
 
   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 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).
 
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>var image: TBGRABitmap;
 
     grad: TBGRAMultiplyScanner;
 
     grad: TBGRAMultiplyScanner;
 
     affine: TBGRAAffineScannerTransform;
 
     affine: TBGRAAffineScannerTransform;
Line 133: Line 133:
 
   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 ===
Line 144: Line 144:
  
 
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>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>  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]]

Revision as of 14:52, 24 March 2012

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.

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)