I have done it this way that the window class has several methods which are used to render different window elements (not directly — they just call the appropriate methods of the appropriate renderers, passing the window canvas reference in the parameter):
type
TMainForm = class(TForm)
procedure FormPaint(ASender: TObject);
{..}
public
procedure InvalidateBody();
procedure InvalidateHeader();
procedure InvalidateFooter();
procedure InvalidateVersion();
public
procedure InvalidateFrameRate();
procedure InvalidateFrameLoad();
{$IFDEF MODE_DEBUG}
procedure InvalidateSceneKind();
procedure InvalidateInputMouse();
procedure InvalidateInputKeyboard();
{$ENDIF}
private
{$IFDEF MODE_RELEASE}
FShowFrameRate: Boolean;
{$ENDIF}
end;
The
OnPaint event triggers all of them, so that the entire window surface is repainted (black fill, background graphic, three buffers, and debug information):
procedure TMainForm.FormPaint(ASender: TObject);
begin
Core.Renderers.Ground.RenderGround(Canvas);
if Core.Looper.Started then
begin
InvalidateBody();
InvalidateHeader();
InvalidateFooter();
InvalidateVersion();
InvalidateFrameRate();
InvalidateFrameLoad();
{$IFDEF MODE_DEBUG}
InvalidateSceneKind();
InvalidateInputMouse();
InvalidateInputKeyboard();
{$ENDIF}
end;
end;
In contrast, the thread only calls methods that render three buffers and debug information.
procedure TLooper.Invalidate();
begin
MainForm.InvalidateFrameRate();
MainForm.InvalidateFrameLoad();
{$IFDEF MODE_DEBUG}
if Core.Scanner.Scene.Changed then
MainForm.InvalidateSceneKind();
{$ENDIF}
MainForm.InvalidateBody();
MainForm.InvalidateHeader();
MainForm.InvalidateFooter();
MainForm.InvalidateVersion();
{$IFDEF MODE_DEBUG}
MainForm.InvalidateInputMouse();
MainForm.InvalidateInputKeyboard();
{$ENDIF}
end;
Due to the fact that only some parts of the window are repainted, rendering a given frame in the window is on average 5-10% faster than repainting the entire window (i.e. calling the
OnPaint event using the built-in
Invalidate method).
If you want to see how big these three buffers are and where in the window they are rendered, check out the screenshot (attachment). What needs to be repainted in each frame are
header,
body and
footer (the debug data at the top and bottom of the window is not rendered in the release version). Currently, these three buffers are painted on the window canvas simply with
Form.Canvas.Draw, then (in debug mode) the frames are painted with
Form.Canvas.FrameRect and the text with
Form.Canvas.TextOut.
In debug mode, when white frames with titles are also rendered, these frames will flicker occasionally. They are flickering because they are not painted on the back buffer — it is natural. This is no problem (it's just debug mode after all), but it does show that painting anything on the canvas of the window repaints it on the screen. If so, painting three back buffers within one frame (header, body, and footer) repaints the window three times instead of once.
So I am looking for a solution that will block the window repaint option while painting these buffers, because maybe thanks to this I will save some computing power. It would be nice if the lock allows me to paint three buffers and then only repaints the area that has changed.
BeginPaint and
EndPaint sound interesting.