Recent

Author Topic: Accessing scan lines (TBGRABitmap.ScanLine)  (Read 459 times)

Tibb

  • New Member
  • *
  • Posts: 26
Accessing scan lines (TBGRABitmap.ScanLine)
« on: December 13, 2019, 09:29:24 pm »
Hello,

I'm trying to draw a grid in perspective using BGRABitmap.

Code: Pascal  [Select]
  1. procedure Trender.render;
  2. begin
  3.   calc_projection;     //<< calculating 2D screen points for 3D grid points
  4.   make_fastBitmap;     //<< making bitmap (Trender.FfastBitmap) using the output of calc_projection
  5.   Fdisplay.ReDraw(FfastBitmap);   //<< drawing the bitmap on screen (see below)
  6. end;

Code: Pascal  [Select]
  1. procedure TDisplay.ReDraw(AfastBitmap: TfastBitmap);
  2. var
  3.   x, y: Integer;
  4.   p: PBGRAPixel;
  5. begin
  6.   for y := 0 to AfastBitmap.Size.y-1 do begin
  7.     p := fbgra.ScanLine[y];            
  8.     for x := 0 to AfastBitmap.Size.x-1 do begin
  9.       PInteger(p)^ := AfastBitmap.Pixels[x, y];
  10.       Inc(p);
  11.     end;
  12.   end;
  13.   Fbgra.InvalidateBitmap;
  14.   Fbgra.draw(image.Canvas, 0, 0, false);      //image >> TImage  
  15. end;

After calling 'TDisplay.Redraw' method, i can see the grid but after recalculating the 2D coordinates of the grid ('calc_projection') using new eye coordinates, nothing happens. Is there anything wrong with calling this method the second time without any re-initialization process? Any idea? Thank You.


« Last Edit: December 14, 2019, 12:16:56 am by Tibb »

winni

  • Hero Member
  • *****
  • Posts: 716
Re: Accessing scan lines (TBGRABitmap.ScanLine)
« Reply #1 on: December 13, 2019, 10:27:50 pm »
Hi!

Hard to say without your code, but

* Is AfastBitmap a TBGRABitmap???
* Do you draw to the bitmap again (make_fastBitmap) after your recalculation ( calc_projection) ??

And for ReDraw your doing too much work:

Code: Pascal  [Select]
  1. procedure TDisplay.ReDraw(AfastBitmap: TfastBitmap);
  2. begin
  3. AfastBitmap.Draw(image.canvas,0,0, false);
  4. end;
  5.  


Winni
« Last Edit: December 13, 2019, 10:30:52 pm by winni »

Tibb

  • New Member
  • *
  • Posts: 26
Re: Accessing scan lines (TBGRABitmap.ScanLine)
« Reply #2 on: December 14, 2019, 12:07:49 am »
Hello winni

TFastBitmap (from 'https://wiki.freepascal.org/Fast_direct_pixel_access'):

Code: Pascal  [Select]
  1.   TFastBitmap = class
  2.   private
  3.     FPixelsData: PByte;
  4.     FSize: TPoint;
  5.     function GetPixel(X, Y: Integer): TFastBitmapPixel; inline;
  6.     procedure SetPixel(X, Y: Integer; const AValue: TFastBitmapPixel); inline;
  7.     procedure SetSize(const AValue: TPoint);
  8.   public
  9.     constructor Create;
  10.     destructor Destroy; override;
  11.     property Size: TPoint read FSize write SetSize;
  12.     property Pixels[X, Y: Integer]: TFastBitmapPixel read GetPixel write SetPixel;
  13.   end;

Code: Pascal  [Select]
  1. function TFastBitmap.GetPixel(x, y: Integer): TFastBitmapPixel;
  2. begin
  3.   Result := PFastBitmapPixel(FPixelsData + (y * FSize.x + x) * SizeOf(TFastBitmapPixel))^;
  4. end;
  5.  
  6. procedure TFastBitmap.SetPixel(x, y: Integer; const AValue: TFastBitmapPixel);
  7. begin
  8.   PFastBitmapPixel(FPixelsData + (y * FSize.x + x) * SizeOf(TFastBitmapPixel))^ := AValue;
  9. end;
  10.  
  11. procedure TFastBitmap.SetSize(const AValue: TPoint);
  12. begin
  13.   if (FSize.x = AValue.x) and (FSize.y = AValue.x) then
  14.     exit;
  15.   FSize := AValue;
  16.   FPixelsData := ReAllocMem(FPixelsData, FSize.x * FSize.y * SizeOf(TFastBitmapPixel));
  17. end;
  18.  
  19. constructor TFastBitmap.Create;
  20. begin
  21.   Size := Point(0, 0);
  22. end;
  23.  
  24. destructor TFastBitmap.Destroy;
  25. begin
  26.   FreeMem(FPixelsData);
  27.   inherited Destroy;
  28. end;

Do you draw to the bitmap again (make_fastBitmap) after your recalculation ( calc_projection) ??
Yes, a call Trender.render every time i change the 'eye' level.

And for ReDraw your doing too much work:
Is that a faster method (just calling TBGRABitmap.Draw)? I have read about scan lines access from the above web page (and from here: https://wiki.freepascal.org/BGRABitmap_tutorial_4#Add_a_painting_handler) as a method for fast pixel access.

Thank You!

winni

  • Hero Member
  • *****
  • Posts: 716
Re: Accessing scan lines (TBGRABitmap.ScanLine)
« Reply #3 on: December 14, 2019, 12:54:25 am »
Hi!

Too much different types and classes.

Don't mix FastBitmap and BGRABitmaps -  it only might confuse a newbie.

Use BGRABitmap in all cases.

* Compute your 3D-Points
* Draw them with the desired eye position an a BGRABitmap
* Draw the BGRABitmap on the Image.canvas

And then change the points or the perspective. And again.

And about chapter 4 of the BGRABitmap tutorial:  The do my step 2 and 3 in one step.
Your case is a little bit more complicated, so draw on a BGRAbitmap in a separate step/procedure. It is easier to keep control.

So my idea is: Forget about FastBitmap and use BGRAbitmap. (Or vice versa)

Winni

circular

  • Hero Member
  • *****
  • Posts: 3078
    • Personal webpage
Re: Accessing scan lines (TBGRABitmap.ScanLine)
« Reply #4 on: December 14, 2019, 10:27:40 am »
Hi

Assigning with PInteger(p)^ is ambiguous. The alpha channel might not be set. If then you draw the image as not opaque, it might show nothing.
What is exactly the type of the color? Rather use explicit conversion.
Or use only TBGRABitmap which provide SetPixel and GetPixel (and much more).
Conscience is the debugger of the mind

Tibb

  • New Member
  • *
  • Posts: 26
Re: Accessing scan lines (TBGRABitmap.ScanLine)
« Reply #5 on: December 14, 2019, 11:54:35 am »
I changed tFastbitmap to TBGRAbitmap. Now, when i try to set pixels by

Code: Pascal  [Select]
  1. Fbgra.pixels[round(x), round(y)] := fp;  //fp >> TBGRApixel

I get 'No palette available' on this line.

Tibb

  • New Member
  • *
  • Posts: 26
Re: Accessing scan lines (TBGRABitmap.ScanLine)
« Reply #6 on: December 14, 2019, 12:11:33 pm »
Ok now i'm using:

Code: Pascal  [Select]
  1. Fbgra.SetPixel(round(x), round(y), clRed);
  2. //Fbgra.InvalidateBitmap;  //<< Should i use this?
  3. Fbgra.draw(image.Canvas, 0, 0, false);

I see the grid and not getting the 'No palette available' message.

But,
1: Is not the scanline method faster?
2: What is the fastest method to clear the 'display' before i redraw the 'scene'?

Thank You!
« Last Edit: December 14, 2019, 12:13:41 pm by Tibb »

winni

  • Hero Member
  • *****
  • Posts: 716
Re: Accessing scan lines (TBGRABitmap.ScanLine)
« Reply #7 on: December 14, 2019, 01:31:54 pm »
Hi!

BGRAbitmap.setpixel (and getpixel)  use internal scanline. Only if your implementation is more intelligent than the BGRA it will be faster.

To clear a complete BGRAbitmap use

MyBitmap.Fill (clWhite); // or green or blue or .....
OR
MyBitmap.fill (BGRAPixelTransparent);

Winni

Tibb

  • New Member
  • *
  • Posts: 26
Re: Accessing scan lines (TBGRABitmap.ScanLine)
« Reply #8 on: December 15, 2019, 12:52:51 pm »
Hi!

BGRAbitmap.setpixel (and getpixel)  use internal scanline. Only if your implementation is more intelligent than the BGRA it will be faster.

To clear a complete BGRAbitmap use

MyBitmap.Fill (clWhite); // or green or blue or .....
OR
MyBitmap.fill (BGRAPixelTransparent);

Winni

All is fine for now, thank you!