Recent

Author Topic: Application.processmessages does not seem to work  (Read 10890 times)

Kostas

  • New Member
  • *
  • Posts: 30
Application.processmessages does not seem to work
« on: June 14, 2012, 08:25:51 am »
Hi!
I have managed to run Graphics32 in Android and the speed for stretching etc is very good!!

Now i have the following problem:
I am trying to do some animations.
I am calling for every frame of the animation 'Application.processmessages'.
But the GUI is not getting refreshed.
The code is the following:

  for i := 1 to 40 do
  begin
    aDice.Roll;
    DrawDice(aDice); // This will draw the correct Dice bitmaps (TBitmap32) on a Graphics32 Image
    Application.ProcessMessages;
    sleep(25); // Wait 25 ms for this frame
  end;

The animation works right in Custom Drawn Interface when running on Win32

Am i doing something wrong?
How to get the Gui refreshed in android?

2. Is it possible to play sounds in Android and how?


Thanks in advance

« Last Edit: June 14, 2012, 08:39:57 am by Kostas »

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: Application.processmessages does not seem to work
« Reply #1 on: June 14, 2012, 08:54:30 am »
Android does not support Application.ProcessMessages by design, so it cannot be implemented in the LCL. In general you cannot take too long to exit a event handler in Android or else it will ask the user to kill the process as it is not responding, so using Sleep() in the main thread is a bad idea.

What you should do instead is handle the OnPaint event of your form, or other control, and draw 1 frame there.

Add a TTimer which calls Form.Invalidate or Control.Invalidate periodically to get an animation.

About sound, first research which APIs are available in the SDK and NDK. You can access SDK Java APIs via JNI. NDK APIs can be accessed via C headers converted to Pascal.

meanderix

  • Jr. Member
  • **
  • Posts: 50
Re: Application.processmessages does not seem to work
« Reply #2 on: June 14, 2012, 03:00:37 pm »
Hi Kostas,

Now i have the following problem:
I am trying to do some animations.
I am calling for every frame of the animation 'Application.processmessages'.

As Felipe suggested, you need to use timers for animations. If you're using a TPaintBox32 instance then you can call TPaintBox32.Repaint inside the OnTimer event handler (and then you can redraw your frame in the TPaintBox32.OnPaint handler.)

A different option, which might be slightly faster (if you want to control the whole screen via Graphics32), would be to use TForm.OnPaint and a separate paint buffer. Below are some of the changes I did to Graphics32's GradLinesEx example in order to get good performance:

Code: [Select]
uses
  LazCanvas, customdrawnint, LCLProc, ... ;

procedure TFormGradientLines.FormPaint(Sender: TObject);
var
  LazCanvas: TLazCanvas;
  W, H: Integer;
begin
  LazCanvas := TLazCanvas(Canvas.Handle);
  W := LazCanvas.Width;
  H := LazCanvas.Height;
  Buffer.SetSize(W, H);
  RepaintBuffer;
  Buffer.DrawTo(Canvas.Handle, 0, 0);
end;

procedure TFormGradientLines.Timer1Timer(Sender: TObject);
begin
  Repaint;
end;

function TFormGradientLines.MyDisableFormBackgroundDrawingProc(AForm: TCustomForm): Boolean;
begin
  Result := AForm = Self; // disable drawing only for self
end;

procedure TFormGradientLines.FormCreate(Sender: TObject);
begin
  Buffer := TBitmap32.Create;
  FadeCount := 0;
  DrawPasses := 2;
  CDWidgetset.DisableFormBackgroundDrawingProc := @MyDisableFormBackgroundDrawingProc;
end;

procedure TFormGradientLines.RepaintBuffer;
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 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;
  end;
end;

Edit: I also made some changes to GR32_Backends_LCL_CustomDrawn. The problem here is that you get the wrong colors (BGRA instead of ARGB.) This has been discussed a bit in the GR32 newsgroups and it seems this is a problem with some other backends as well. A solution might be to have conditional defines that would adjust the TColor32Entry record to either ARGB or BGRA memory layout.

Code: [Select]
procedure TransferBits(Src, Dst: TLazIntfImage; X, Y, XSrc, YSrc,
  SrcWidth, SrcHeight: Integer); overload;
var
  I, H: Integer;
  Depth: Integer;
  X1, Y1, X2, Y2, SrcLine, DstLine, CopyBytes: Integer;
  PSrc, PDst: PByte;
begin
  Depth := Src.DataDescription.Depth shr 3;
  SrcLine := Src.Width * Depth;
  DstLine := Dst.Width * Depth;
  PSrc := Src.PixelData;
  PDst := Dst.PixelData;

  if (X >= Dst.Width) or (Y >= Dst.Height) then Exit;

  X1 := X;
  Y1 := Y;
  X2 := Min(X + SrcWidth, Dst.Width);
  Y2 := Min(Y + SrcHeight, Dst.Height);
  CopyBytes := (X2 - X1) * Depth;

  Inc(PSrc, XSrc * Depth + SrcLine * YSrc);
  Inc(PDst, X * Depth + DstLine * Y);
  for I := 0 to SrcHeight - 1 do
  begin
    System.Move(PSrc^, PDst^, CopyBytes);
    Inc(PSrc, SrcLine);
    Inc(PDst, DstLine);
  end;
end;

procedure TransferBits(Src, Dst: TLazIntfImage); overload;
begin
  TransferBits(Src, Dst, 0, 0, 0, 0, Src.Width, Src.Height);
end;

procedure TLCLBackend.DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList;
  ACanvas: TCanvas; APaintBox: TCustomPaintBox32);
var
  Src, Dst: TLazCanvas;
begin
  Dst := TLazCanvas(ACanvas.Handle);
  Src := TLazCanvas(Canvas.Handle);
  if Dst.Image is TLazIntfImage then
    TransferBits(TLazIntfImage(Src.Image), TLazIntfImage(Dst.Image))
  else
    Dst.CopyRect(0, 0, Src, Rect(0,0,Src.Width,Src.Height));
end;
« Last Edit: June 14, 2012, 03:23:03 pm by meanderix »

Kostas

  • New Member
  • *
  • Posts: 30
Re: Application.processmessages does not seem to work
« Reply #3 on: June 14, 2012, 07:26:59 pm »
Thanks a lot for your detailed answer!!
I will look at a later point at your changes to Graphics32.
I have actually no problem with the library.
Everything seems to draw right and also alpha blending works fine.
Also on my Smartphone. And it is really fast... :)

A different option, which might be slightly faster (if you want to control the whole screen via Graphics32), would be to use TForm.OnPaint and a separate paint buffer.
Yes i already was into this way.
My Problem for the moment is that my OnPaint handler of my Form is never called...
Invalidate or Repaint does not call the FormPaint handler...
Neither on Win32 nor on Android.
I am still on testing and looking around in order to find the problem.

Any idea?
« Last Edit: June 14, 2012, 07:31:36 pm by Kostas »

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: Application.processmessages does not seem to work
« Reply #4 on: June 14, 2012, 08:28:13 pm »
My Problem for the moment is that my OnPaint handler of my Form is never called...
Invalidate or Repaint does not call the FormPaint handler...
Neither on Win32 nor on Android.
I am still on testing and looking around in order to find the problem.

Any idea?

Do you have controls which completely cover the form? LCL-CustomDrawn will attempt to auto-detect this situation and if it is so, it will skip drawing the form (or for that matter any completely covered control).

Kostas

  • New Member
  • *
  • Posts: 30
Re: Application.processmessages does not seem to work
« Reply #5 on: June 14, 2012, 08:56:29 pm »
Do you have controls which completely cover the form? LCL-CustomDrawn will attempt to auto-detect this situation and if it is so, it will skip drawing the form (or for that matter any completely covered control).

Exactly this was the problem!
Thank you!

Kostas

  • New Member
  • *
  • Posts: 30
Re: Application.processmessages does not seem to work
« Reply #6 on: June 26, 2012, 11:17:53 pm »
I have now the problem that the TBitmap32 of Graphics32 needs around 350ms to draw itsself on the LazCanvas.
This is too slow for doing any kind of animations.
I get about 2 to 3 frames per second.

The code part is in GR32_Backends_LCL_CustomDrawn in TLCLBackend.DoPaint:
    ACanvas.Draw(0, 0, FBitmap);
This needs as i said around 350ms to draw on my Smartphone.

I tried the changes as suggested from meanderix in his post above but the application crashes immediately and does not start.

Any idea what i could have done wrong or how to make the drawing part faster?

Kostas

meanderix

  • Jr. Member
  • **
  • Posts: 50
Re: Application.processmessages does not seem to work
« Reply #7 on: June 26, 2012, 11:59:41 pm »
Hi Kostas,

I tried the changes as suggested from meanderix in his post above but the application crashes immediately and does not start.

I'm attaching a patch that can be applied to the current SVN version of GR32_Backends_LCL_CustomDrawn.pas. Note that I have added a conditional define ASSUME_ABGR. When this is enabled it should be a lot faster, but colors now use the ABGR pixel format (you could redefine TColor32Entry in GR32.pas to reflect this.)

Cheers,
Mattias

 

TinyPortal © 2005-2018