From e7f572b55beba2f6bf21e81392ca2fc4754443e1 Mon Sep 17 00:00:00 2001 From: Olly Date: Wed, 15 Jan 2025 16:40:04 +0000 Subject: [PATCH] Fix target image freezing when a region is frozen --- Source/simba.target.pas | 39 +++++++++++++++++++++++----------- Source/simba.target_eios.pas | 4 ++-- Source/simba.target_image.pas | 4 ++-- Source/simba.target_plugin.pas | 4 ++-- Source/simba.target_window.pas | 4 ++-- Tests/target_imagefreeze.simba | 30 +++++++++++++++++++------- 6 files changed, 57 insertions(+), 28 deletions(-) diff --git a/Source/simba.target.pas b/Source/simba.target.pas index c8eb3aa89..4f2f3dac1 100644 --- a/Source/simba.target.pas +++ b/Source/simba.target.pas @@ -47,7 +47,7 @@ TSimbaTargetInfo = record Plugin: TSimbaPluginTarget; GetDimensions: procedure(Target: Pointer; out W, H: Integer); - GetImageData: function(Target: Pointer; X, Y, Width, Height: Integer; var Data: PColorBGRA; var DataWidth: Integer): Boolean; + GetImageData: function(Target: Pointer; X, Y, Width, Height: Integer; out Data: PColorBGRA; out DataWidth: Integer): Boolean; IsValid: function(Target: Pointer): Boolean; IsFocused: function(Target: Pointer): Boolean; @@ -163,7 +163,7 @@ TSimbaTarget = record procedure SetPlugin(FileName, Args: String; out DebugImage: TSimbaExternalCanvas); overload; function GetImageDataAsImage(var ABounds: TBox; out Image: TSimbaImage): Boolean; - function GetImageData(var ABounds: TBox; var Data: PColorBGRA; var DataWidth: Integer): Boolean; + function GetImageData(var ABounds: TBox; out Data: PColorBGRA; out DataWidth: Integer): Boolean; procedure FreeImageData(var Data: PColorBGRA); function IsImageFrozen: Boolean; @@ -1074,26 +1074,41 @@ function TSimbaTarget.GetImageDataAsImage(var ABounds: TBox; out Image: TSimbaIm end; end; -function TSimbaTarget.GetImageData(var ABounds: TBox; var Data: PColorBGRA; var DataWidth: Integer): Boolean; -begin - CheckMethod(FTarget.GetImageData, 'GetImageData'); - if IsImageFrozen() then - begin - Data := @FFrozen.Data[0]; - DataWidth := FFrozen.DataWidth; - ABounds := FFrozen.Bounds; +function TSimbaTarget.GetImageData(var ABounds: TBox; out Data: PColorBGRA; out DataWidth: Integer): Boolean; - Exit(True); + function GetFrozenData: Boolean; + begin + // constrain to our frozen bounds + if (ABounds.X1 = -1) and (ABounds.Y1 = -1) and (ABounds.X2 = -1) and (ABounds.Y2 = -1) then + ABounds := FFrozen.Bounds + else + ABounds := ABounds.Clip(FFrozen.Bounds); + + Result := (ABounds.Width > 0) and (ABounds.Height > 0); + if Result then + begin + Data := @FFrozen.Data[(ABounds.Y1 - FFrozen.Bounds.Y1) * FFrozen.DataWidth + (ABounds.X1 - FFrozen.Bounds.X1)]; + DataWidth := FFrozen.DataWidth; + end; end; +begin Data := nil; - Result := ValidateBounds(ABounds) and FTarget.GetImageData(FTarget.Target, ABounds.X1, ABounds.Y1, ABounds.Width, ABounds.Height, Data, DataWidth); + DataWidth := 0; + + CheckMethod(FTarget.GetImageData, 'GetImageData'); + if IsImageFrozen() then + Result := GetFrozenData() + else + Result := ValidateBounds(ABounds) and FTarget.GetImageData(FTarget.Target, ABounds.X1, ABounds.Y1, ABounds.Width, ABounds.Height, Data, DataWidth); end; procedure TSimbaTarget.FreeImageData(var Data: PColorBGRA); begin + // never free frozen data if IsImageFrozen() and (Data = @FFrozen.Data[0]) then Exit; + // Only free window since rest of targets are references to buffers or image data. if (FTarget.Kind in [ESimbaTargetKind.WINDOW]) then FreeMem(Data); end; diff --git a/Source/simba.target_eios.pas b/Source/simba.target_eios.pas index 51bad10ec..490f399ca 100644 --- a/Source/simba.target_eios.pas +++ b/Source/simba.target_eios.pas @@ -81,7 +81,7 @@ TEIOSTarget = record function LoadEIOS(FileName, Args: String): TEIOSTarget; -function EIOSTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; var Data: PColorBGRA; var DataWidth: Integer): Boolean; +function EIOSTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; out Data: PColorBGRA; out DataWidth: Integer): Boolean; procedure EIOSTarget_GetDimensions(Target: Pointer; out Width, Height: Integer); procedure EIOSTarget_KeyDown(Target: Pointer; Key: EKeyCode); @@ -155,7 +155,7 @@ function LoadEIOS(FileName, Args: String): TEIOSTarget; end; end; -function EIOSTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; var Data: PColorBGRA; var DataWidth: Integer): Boolean; +function EIOSTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; out Data: PColorBGRA; out DataWidth: Integer): Boolean; var BufferWidth, BufferHeight: Integer; begin diff --git a/Source/simba.target_image.pas b/Source/simba.target_image.pas index fca375119..61870f358 100644 --- a/Source/simba.target_image.pas +++ b/Source/simba.target_image.pas @@ -14,7 +14,7 @@ interface simba.base; procedure ImageTarget_GetDimensions(Target: Pointer; out W, H: Integer); -function ImageTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; var Data: PColorBGRA; var DataWidth: Integer): Boolean; +function ImageTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; out Data: PColorBGRA; out DataWidth: Integer): Boolean; function ImageTarget_IsValid(Target: Pointer): Boolean; implementation @@ -30,7 +30,7 @@ procedure ImageTarget_GetDimensions(Target: Pointer; out W, H: Integer); H := Image.Height; end; -function ImageTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; var Data: PColorBGRA; var DataWidth: Integer): Boolean; +function ImageTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; out Data: PColorBGRA; out DataWidth: Integer): Boolean; var Image: TSimbaImage absolute Target; begin diff --git a/Source/simba.target_plugin.pas b/Source/simba.target_plugin.pas index cb829e848..2e89377d9 100644 --- a/Source/simba.target_plugin.pas +++ b/Source/simba.target_plugin.pas @@ -47,7 +47,7 @@ function LoadPluginTarget(FileName, Args: String): TSimbaPluginTarget; overload; function LoadPluginTarget(FileName, Args: String; out DebugImage: TSimbaExternalCanvas): TSimbaPluginTarget; overload; procedure PluginTarget_GetDimensions(Target: Pointer; out W, H: Integer); -function PluginTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; var Data: PColorBGRA; var DataWidth: Integer): Boolean; +function PluginTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; out Data: PColorBGRA; out DataWidth: Integer): Boolean; function PluginTarget_MousePressed(Target: Pointer; Button: EMouseButton): Boolean; function PluginTarget_MousePosition(Target: Pointer): TPoint; @@ -190,7 +190,7 @@ procedure PluginTarget_GetDimensions(Target: Pointer; out W, H: Integer); end; end; -function PluginTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; var Data: PColorBGRA; var DataWidth: Integer): Boolean; +function PluginTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; out Data: PColorBGRA; out DataWidth: Integer): Boolean; begin with PSimbaPluginTarget(Target)^ do begin diff --git a/Source/simba.target_window.pas b/Source/simba.target_window.pas index 7d02a1c0d..dedaac472 100644 --- a/Source/simba.target_window.pas +++ b/Source/simba.target_window.pas @@ -9,7 +9,7 @@ interface simba.base; procedure WindowTarget_GetDimensions(Target: Pointer; out W, H: Integer); -function WindowTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; var Data: PColorBGRA; var DataWidth: Integer): Boolean; +function WindowTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; out Data: PColorBGRA; out DataWidth: Integer): Boolean; function WindowTarget_Focus(Target: Pointer): Boolean; function WindowTarget_IsFocused(Target: Pointer): Boolean; @@ -47,7 +47,7 @@ procedure WindowTarget_GetDimensions(Target: Pointer; out W, H: Integer); end; end; -function WindowTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; var Data: PColorBGRA; var DataWidth: Integer): Boolean; +function WindowTarget_GetImageData(Target: Pointer; X, Y, Width, Height: Integer; out Data: PColorBGRA; out DataWidth: Integer): Boolean; begin Result := SimbaNativeInterface.GetWindowImage(PWindowHandle(Target)^, X, Y, Width, Height, Data); if Result then diff --git a/Tests/target_imagefreeze.simba b/Tests/target_imagefreeze.simba index 4f21440be..618c1382c 100644 --- a/Tests/target_imagefreeze.simba +++ b/Tests/target_imagefreeze.simba @@ -2,20 +2,34 @@ var img: TImage := TImage.Create(50, 50); begin + // test entire client + img.FreeOnTerminate := True; img.Fill(Colors.RED); Target.SetImage(img); - Target.FreezeImage([5,5,25,25]); + Target.FreezeImage(); - img.Fill(Colors.GREEN); // draw green, but frozen image is still red + img.Fill(Colors.GREEN); // draw green but frozen target is still red Assert(Target.IsImageFrozen()); Assert(Target.CountColor(Colors.GREEN, 0) = 0); - Assert(Target.FindColor(Colors.RED, 0).Bounds.Area = 21*21); + Assert(Target.CountColor(Colors.RED, 0) = 50*50); - Target.UnFreezeImage(); - Assert(not Target.IsImageFrozen()); - Assert(Target.CountColor(Colors.GREEN, 0) = (50*50)); - Assert(Target.CountColor(Colors.RED, 0) = 0); + Target.UnFreezeImage(); // test unfreeze + Assert(Target.CountColor(Colors.GREEN, 0) = 50*50); - img.Free(); + // test area + img.Fill(0); + img.DrawColor := Colors.RED; + img.DrawBox([10,10,35,45]); + + Target.FreezeImage([15,15,40,50]); + img.Clear(); // clear image but target is frozen + + // search the entire frozen + Assert(Target.FindColor(Colors.RED, 0).Bounds = [15,15,35,45]); + Assert(Target.FindColor(Colors.RED, 0, [0,0,1000,1000]).Bounds = [15,15,35,45]); + + // search a sub region of frozen + Assert(Target.CountColor(Colors.RED, 0, [20,20,25,30]) = 0); + Assert(Target.FindColor(Colors.RED, 0, [20,20,45,40]).Bounds = [35,20,35,40]); end.