unit GR32_ExtImage; (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 or LGPL 2.1 with linking exception * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Alternatively, the contents of this file may be used under the terms of the * Free Pascal modified version of the GNU Lesser General Public License * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions * of this license are applicable instead of those above. * Please see the file LICENSE.txt for additional information concerning this * license. * * The Original Code is Extended Image components for Graphics32 * * The Initial Developer of the Original Code is * Mattias Andersson * * Portions created by the Initial Developer are Copyright (C) 2005-2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) interface {$include GR32.inc} uses {$IFDEF FPC} LCLIntf, LCLType, LMessages, {$ELSE} Windows, Messages, {$ENDIF} GR32, GR32_Image, GR32_Rasterizers, Classes, Controls; type TRenderThread = class; TRenderMode = (rnmFull, rnmConstrained); { TSyntheticImage32 } TSyntheticImage32 = class(TPaintBox32) private FRasterizer: TRasterizer; FAutoRasterize: Boolean; FDefaultProc: TWndMethod; FResized: Boolean; FRenderThread: TRenderThread; FOldAreaChanged: TAreaChangedEvent; FDstRect: TRect; FRenderMode: TRenderMode; FClearBuffer: Boolean; procedure SetRasterizer(const Value: TRasterizer); procedure StopRenderThread; procedure SetDstRect(const Value: TRect); procedure SetRenderMode(const Value: TRenderMode); protected procedure RasterizerChanged(Sender: TObject); procedure SetParent(AParent: TWinControl); override; {$IFDEF FPC} procedure FormWindowProc(var Message: TLMessage); {$ELSE} procedure FormWindowProc(var Message: TMessage); {$ENDIF} procedure DoRasterize; property RepaintMode; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Resize; override; procedure Rasterize; property DstRect: TRect read FDstRect write SetDstRect; published property AutoRasterize: Boolean read FAutoRasterize write FAutoRasterize; property Rasterizer: TRasterizer read FRasterizer write SetRasterizer; property ClearBuffer: Boolean read FClearBuffer write FClearBuffer; property RenderMode: TRenderMode read FRenderMode write SetRenderMode; property Color; end; { TRenderThread } TRenderThread = class(TThread) private FDest: TBitmap32; FRasterizer: TRasterizer; FOldAreaChanged: TAreaChangedEvent; FArea: TRect; FDstRect: TRect; procedure SynchronizedAreaChanged; procedure AreaChanged(Sender: TObject; const Area: TRect; const Hint: Cardinal); protected procedure Execute; override; procedure Rasterize; public constructor Create(Rasterizer: TRasterizer; Dst: TBitmap32; DstRect: TRect; Suspended: Boolean); end; procedure Rasterize(Rasterizer: TRasterizer; Dst: TBitmap32; DstRect: TRect); implementation uses Forms, SysUtils, Graphics; procedure Rasterize(Rasterizer: TRasterizer; Dst: TBitmap32; DstRect: TRect); var R: TRenderThread; begin R := TRenderThread.Create(Rasterizer, Dst, DstRect, True); R.FreeOnTerminate := True; {$IFDEF USETHREADRESUME} R.Resume; {$ELSE} R.Start; {$ENDIF} end; { TSyntheticImage32 } constructor TSyntheticImage32.Create(AOwner: TComponent); begin inherited; FRasterizer := TRegularRasterizer.Create; FRasterizer.Sampler := Buffer.Resampler; FAutoRasterize := True; FResized := False; RepaintMode := rmDirect; RenderMode := rnmFull; BufferOversize := 0; end; destructor TSyntheticImage32.Destroy; var ParentForm: TCustomForm; begin StopRenderThread; if Assigned(FRenderThread) then FRenderThread.Free; if Assigned(FDefaultProc) then begin ParentForm := GetParentForm(Self); if ParentForm <> nil then ParentForm.WindowProc := FDefaultProc; end; FRasterizer.Free; inherited; end; procedure TSyntheticImage32.DoRasterize; begin if FAutoRasterize then Rasterize; end; {$IFDEF FPC} procedure TSyntheticImage32.FormWindowProc(var Message: TLMessage); var CmdType: Integer; begin FDefaultProc(Message); case Message.Msg of 534: FResized := False; 562: begin if FResized then DoRasterize; FResized := True; end; 274: begin CmdType := Message.WParam and $FFF0; if (CmdType = SC_MAXIMIZE) or (CmdType = SC_RESTORE) then DoRasterize; end; end; end; {$ELSE} procedure TSyntheticImage32.FormWindowProc(var Message: TMessage); var CmdType: Integer; begin FDefaultProc(Message); case Message.Msg of WM_MOVING: FResized := False; WM_EXITSIZEMOVE: begin if FResized then DoRasterize; FResized := True; end; WM_SYSCOMMAND: begin CmdType := Message.WParam and $FFF0; if (CmdType = SC_MAXIMIZE) or (CmdType = SC_RESTORE) then DoRasterize; end; end; end; {$ENDIF} procedure TSyntheticImage32.Rasterize; var BackgroundColor: TColor; R: TRect; begin { Clear buffer before rasterization } if FClearBuffer then begin BackgroundColor := Color; {$ifdef FPC} if (BackgroundColor = clDefault) then BackgroundColor := GetDefaultColor(dctBrush); {$endif} Buffer.Clear(Color32(BackgroundColor)); Invalidate; end; { Create rendering thread } StopRenderThread; FOldAreaChanged := Buffer.OnAreaChanged; if FRenderMode = rnmFull then R := Rect(0, 0, Buffer.Width, Buffer.Height) else R := FDstRect; FRenderThread := TRenderThread.Create(FRasterizer, Buffer, R, False); FResized := True; end; procedure TSyntheticImage32.RasterizerChanged(Sender: TObject); begin DoRasterize; end; procedure TSyntheticImage32.Resize; begin if not FResized then StopRenderThread; inherited; end; procedure TSyntheticImage32.SetDstRect(const Value: TRect); begin FDstRect := Value; end; procedure TSyntheticImage32.SetParent(AParent: TWinControl); var ParentForm: TCustomForm; begin ParentForm := GetParentForm(Self); if ParentForm = AParent then Exit; if ParentForm <> nil then if Assigned(FDefaultProc) then ParentForm.WindowProc := FDefaultProc; inherited; if AParent <> nil then begin ParentForm := GetParentForm(Self); if ParentForm <> nil then begin FDefaultProc := ParentForm.WindowProc; ParentForm.WindowProc := FormWindowProc; end; end; end; procedure TSyntheticImage32.SetRasterizer(const Value: TRasterizer); begin if Value <> FRasterizer then begin StopRenderThread; if Assigned(FRasterizer) then FRasterizer.Free; FRasterizer := Value; FRasterizer.OnChange := RasterizerChanged; DoRasterize; Changed; end; end; procedure TSyntheticImage32.SetRenderMode(const Value: TRenderMode); begin FRenderMode := Value; end; procedure TSyntheticImage32.StopRenderThread; begin if Assigned(FRenderThread) and (not FRenderThread.Terminated) then begin FRenderThread.Synchronize(FRenderThread.Terminate); FRenderThread.WaitFor; FreeAndNil(FRenderThread); end; end; { TRenderThread } constructor TRenderThread.Create(Rasterizer: TRasterizer; Dst: TBitmap32; DstRect: TRect; Suspended: Boolean); begin {$IFDEF USETHREADRESUME} inherited Create(True); {$ELSE} inherited Create(Suspended); {$ENDIF} FRasterizer := Rasterizer; FDest := Dst; FDstRect := DstRect; {$IFDEF USETHREADRESUME} if not Suspended then Resume; {$ENDIF} end; procedure TRenderThread.Execute; begin Rasterize; end; procedure TRenderThread.Rasterize; begin FRasterizer.Lock; { Save current AreaChanged handler } FOldAreaChanged := FDest.OnAreaChanged; FDest.OnAreaChanged := AreaChanged; try FRasterizer.Rasterize(FDest, FDstRect); except on EAbort do; end; { Reset old AreaChanged handler } FDest.OnAreaChanged := FOldAreaChanged; Synchronize(FRasterizer.Unlock); end; procedure TRenderThread.AreaChanged(Sender: TObject; const Area: TRect; const Hint: Cardinal); begin if Terminated then Abort else begin FArea := Area; Synchronize(SynchronizedAreaChanged); end; end; procedure TRenderThread.SynchronizedAreaChanged; begin if Assigned(FOldAreaChanged) then FOldAreaChanged(FDest, FArea, AREAINFO_RECT); end; end.