Changeset 19 for trunk/UCore.pas


Ignore:
Timestamp:
Sep 27, 2011, 10:16:41 PM (13 years ago)
Author:
george
Message:
  • Added: Helping threading unit.
  • Added: Now drawing and engine handling are executed in separated thread.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/UCore.pas

    r17 r19  
    77uses
    88  Dialogs, Classes, SysUtils, Contnrs, Graphics, SpecializedMatrix, SpecializedList,
    9   IntfGraphics, FPImage, LCLType, SpecializedBitmap, GraphType, Math, URectangle;
     9  IntfGraphics, FPImage, LCLType, SpecializedBitmap, GraphType, Math, URectangle,
     10  Syncobjs, UThreading;
    1011
    1112const
     
    126127  end;
    127128
     129  { TSystemThread }
     130
     131  TSystemThread = class(TListedThread)
     132    Engine: TEngine;
     133    procedure Execute; override;
     134  end;
     135
     136  { TDrawThread }
     137
     138  TDrawThread = class(TListedThread)
     139    Engine: TEngine;
     140    procedure Execute; override;
     141  end;
     142
    128143  { TEngine }
    129144
    130145  TEngine = class
    131146  private
     147    FActive: Boolean;
    132148    FBitmap: TBitmap;
     149    FBitmapLock: TCriticalSection;
    133150    FRedrawPending: Boolean;
    134151    FBitmapLower: TBitmapTColor;
     152    FDrawThread: TDrawThread;
     153    FSystemThread: TSystemThread;
    135154    IntfImage: TLazIntfImage;
    136155    function GetPlayerCount: Integer;
     156    procedure SetActive(const AValue: Boolean);
    137157    procedure SetBitmap(const AValue: TBitmap);
    138158    procedure SetPlayerCount(const AValue: Integer);
    139159    procedure Redraw;
    140160    function IsInsideHouses(Pos: TPoint): Boolean;
     161    procedure DoDrawToBitmap;
    141162  public
    142163    Keyboard: TKeyboard;
    143164    World: TWorld;
    144165    Players: TObjectList; // <TPlayer>
     166    Lock: TCriticalSection;
    145167    constructor Create;
    146168    destructor Destroy; override;
     
    148170    procedure Tick;
    149171    procedure Draw;
     172    procedure NewGame;
    150173    property PlayerCount: Integer read GetPlayerCount write SetPlayerCount;
    151174    property Bitmap: TBitmap read FBitmap write SetBitmap;
    152     procedure NewGame;
     175    property Active: Boolean read FActive write SetActive;
    153176  end;
    154177
     
    171194function SwapBRComponent(Value: Integer): Integer; inline;
    172195
     196
    173197implementation
    174198
     
    179203  TFastBitmapPixelComponents(Result).R := TFastBitmapPixelComponents(Value).B;
    180204  TFastBitmapPixelComponents(Result).B := TFastBitmapPixelComponents(Value).R;
     205end;
     206
     207{ TSystemThread }
     208
     209procedure TSystemThread.Execute;
     210begin
     211  repeat
     212    Engine.Tick;
     213    Sleep(50);
     214  until Terminated;
     215end;
     216
     217{ TDrawThread }
     218
     219procedure TDrawThread.Execute;
     220begin
     221  repeat
     222    Engine.Draw;
     223    Sleep(50);
     224  until Terminated;
    181225end;
    182226
     
    580624function TPlayer.ShowTankProc(Item1, Item2: Byte): Byte;
    581625begin
    582   if Item2 > 0 then Result := Item2 else Result := Item1;
     626  if Item2 > 0 then Result := Item2
     627    else Result := Item1;
    583628end;
    584629
     
    596641  with Engine.World do begin
    597642    Surface.Merge(Surface.CreateIndex(Position.X - TTank(Tanks[Direction]).Image.Count.X div 2,
    598       Position.Y - TTank(Tanks[Direction]).Image.Count.Y div 2), TTank(Tanks[Direction]).Image, ShowTankProc);
     643      Position.Y - TTank(Tanks[Direction]).Image.Count.Y div 2),
     644      TTank(Tanks[Direction]).Image, ShowTankProc);
    599645  end;
    600646end;
     
    761807end;
    762808
     809procedure TEngine.SetActive(const AValue: Boolean);
     810begin
     811  if FActive = AValue then Exit;
     812  FActive := AValue;
     813  if AValue then begin
     814    FDrawThread := TDrawThread.Create(True);
     815    FDrawThread.Engine := Self;
     816    FDrawThread.FreeOnTerminate := False;
     817    FDrawThread.Name := 'Draw';
     818    FDrawThread.Start;
     819    FSystemThread := TSystemThread.Create(True);
     820    FSystemThread.Engine := Self;
     821    FSystemThread.FreeOnTerminate := False;
     822    FSystemThread.Name := 'Engine';
     823    FSystemThread.Start;
     824  end else begin
     825    FreeAndNil(FDrawThread);
     826    FreeAndNil(FSystemThread);
     827  end;
     828end;
     829
    763830procedure TEngine.SetBitmap(const AValue: TBitmap);
    764831begin
     
    805872end;
    806873
    807 procedure TEngine.ResizePlayerFrames;
    808 var
    809   HorizFrameCount: Integer;
    810   VertFrameCount: Integer;
    811   I: Integer;
    812 begin
    813   if Assigned(FBitmapLower) then begin
    814     if Players.Count > 1 then begin
    815       if Players.Count > 2 then VertFrameCount := 2
    816         else VertFrameCount := 1;
    817       HorizFrameCount := Round(Players.Count / VertFrameCount);
    818     end else begin
    819       VertFrameCount := 1;
    820       HorizFrameCount := 1;
    821     end;
    822     FBitmapLower.Count := FBitmapLower.CreateIndex(80 * HorizFrameCount, 60 * VertFrameCount);
    823     for I := 0 to Players.Count - 1 do begin
    824       TPlayer(Players[I]).ScreenFrame.AsTRect := Rect(
    825         (I mod HorizFrameCount) * (FBitmapLower.Count.X div HorizFrameCount),
    826         (I div HorizFrameCount) * (FBitmapLower.Count.Y div VertFrameCount),
    827         ((I mod HorizFrameCount) + 1) * (FBitmapLower.Width div HorizFrameCount),
    828         ((I div HorizFrameCount) + 1) * (FBitmapLower.Height div VertFrameCount));
    829     end;
    830   end;
    831   Redraw;
    832 end;
    833 
    834 constructor TEngine.Create;
    835 begin
    836   FBitmapLower := TBitmapTColor.Create;
    837   IntfImage := TLazIntfImage.Create(1, 1);
    838   Players := TObjectList.Create;
    839   Keyboard := TKeyboard.Create;
    840   World := TWorld.Create;
    841   World.Engine := Self;
    842   Redraw;
    843 end;
    844 
    845 destructor TEngine.Destroy;
    846 begin
    847   FBitmapLower.Free;
    848   IntfImage.Free;
    849   Players.Free;
    850   Keyboard.Free;
    851   World.Free;
    852   inherited Destroy;
    853 end;
    854 
    855 procedure TEngine.Tick;
    856 var
    857   I: Integer;
    858 begin
    859   for I := 0 to Players.Count - 1 do begin
    860     TPlayer(Players[I]).Control;
    861     TPlayer(Players[I]).Tick;
    862   end;
    863 end;
    864 
    865 procedure TEngine.Draw;
     874procedure TEngine.DoDrawToBitmap;
    866875var
    867876  I: Integer;
     
    885894  TargetWidth: Integer;
    886895begin
     896  if Assigned(FBitmap) then
     897  try
     898    Bitmap.BeginUpdate;
     899    RawImage := Bitmap.RawImage;
     900    BytePerPixel := RawImage.Description.BitsPerPixel div 8;
     901    BytePerRow := RawImage.Description.BytesPerLine;
     902    FillChar(RawImage.Data^, Bitmap.Height * BytePerRow, 0);
     903
     904    if (FBitmap.Width / FBitmapLower.Width) < (FBitmap.Height / FBitmapLower.Height) then
     905      Ratio := FBitmap.Width / FBitmapLower.Width
     906      else Ratio := FBitmap.Height / FBitmapLower.Height;
     907
     908    // Preserve aspect ratio
     909    TargetWidth := Trunc(FBitmapLower.Width * Ratio);
     910    TargetHeight := Trunc(FBitmapLower.Height * Ratio);
     911
     912    Shift.X := Trunc((Bitmap.Width - TargetWidth) / 2);
     913    Shift.Y := Trunc((Bitmap.Height - TargetHeight) / 2);
     914
     915    XDiv := TargetWidth div FBitmapLower.Width;
     916    XMod := TargetWidth mod FBitmapLower.Width;
     917    YDiv := TargetHeight div FBitmapLower.Height;
     918    YMod := TargetHeight mod FBitmapLower.Height;
     919
     920    PixelRowPtr := PInteger(RawImage.Data + BytePerRow * Shift.Y);
     921    YAcc := FBitmapLower.Height div 2;
     922    for Y := 0 to FBitmapLower.Height - 1 do begin
     923      SubPixelSizeY := YDiv;
     924      Inc(YAcc, YMod);
     925      if YAcc >= FBitmapLower.Height then begin
     926        Dec(YAcc, FBitmapLower.Height);
     927        Inc(SubPixelSizeY);
     928      end;
     929
     930      PixelPtr := PixelRowPtr + Shift.X;
     931      XAcc := FBitmapLower.Width div 2;
     932      for X := 0 to FBitmapLower.Width - 1 do begin
     933        SubPixelSizeX := XDiv;
     934        Inc(XAcc, XMod);
     935        if XAcc >= FBitmapLower.Width then begin
     936          Dec(XAcc, FBitmapLower.Width);
     937          Inc(SubPixelSizeX);
     938        end;
     939
     940        Color := SwapBRComponent(FBitmapLower.Pixels[X, Y]);
     941
     942        // Draw large pixel
     943        SubPixelRowPtr := PixelPtr;
     944        for PixelY := 0 to SubPixelSizeY - 1 do begin
     945          SubPixelPtr := SubPixelRowPtr;
     946          for PixelX := 0 to SubPixelSizeX - 1 do begin
     947            SubPixelPtr^ := Color;
     948            Inc(PByte(SubPixelPtr), BytePerPixel);
     949          end;
     950          Inc(PByte(SubPixelRowPtr), BytePerRow);
     951        end;
     952        Inc(PByte(PixelPtr), BytePerPixel * SubPixelSizeX);
     953      end;
     954      Inc(PByte(PixelRowPtr), BytePerRow * SubPixelSizeY);
     955    end;
     956  finally
     957    FBitmap.EndUpdate;
     958  end;
     959end;
     960
     961procedure TEngine.ResizePlayerFrames;
     962var
     963  HorizFrameCount: Integer;
     964  VertFrameCount: Integer;
     965  I: Integer;
     966begin
     967  if Assigned(FBitmapLower) then begin
     968    if Players.Count > 1 then begin
     969      if Players.Count > 2 then VertFrameCount := 2
     970        else VertFrameCount := 1;
     971      HorizFrameCount := Round(Players.Count / VertFrameCount);
     972    end else begin
     973      VertFrameCount := 1;
     974      HorizFrameCount := 1;
     975    end;
     976    FBitmapLower.Count := FBitmapLower.CreateIndex(80 * HorizFrameCount, 60 * VertFrameCount);
     977    for I := 0 to Players.Count - 1 do begin
     978      TPlayer(Players[I]).ScreenFrame.AsTRect := Rect(
     979        (I mod HorizFrameCount) * (FBitmapLower.Count.X div HorizFrameCount),
     980        (I div HorizFrameCount) * (FBitmapLower.Count.Y div VertFrameCount),
     981        ((I mod HorizFrameCount) + 1) * (FBitmapLower.Width div HorizFrameCount),
     982        ((I div HorizFrameCount) + 1) * (FBitmapLower.Height div VertFrameCount));
     983    end;
     984  end;
     985  Redraw;
     986end;
     987
     988constructor TEngine.Create;
     989begin
     990  Lock := TCriticalSection.Create;
     991  FBitmapLower := TBitmapTColor.Create;
     992  FBitmapLock := TCriticalSection.Create;
     993  IntfImage := TLazIntfImage.Create(1, 1);
     994  Players := TObjectList.Create;
     995  Keyboard := TKeyboard.Create;
     996  World := TWorld.Create;
     997  World.Engine := Self;
     998  Redraw;
     999end;
     1000
     1001destructor TEngine.Destroy;
     1002begin
     1003  Active := False;
     1004  FBitmapLower.Free;
     1005  FBitmapLock.Free;
     1006  IntfImage.Free;
     1007  Players.Free;
     1008  Keyboard.Free;
     1009  World.Free;
     1010  Lock.Free;
     1011  inherited Destroy;
     1012end;
     1013
     1014procedure TEngine.Tick;
     1015var
     1016  I: Integer;
     1017begin
     1018  try
     1019    Lock.Acquire;
     1020    for I := 0 to Players.Count - 1 do begin
     1021      TPlayer(Players[I]).Control;
     1022      TPlayer(Players[I]).Tick;
     1023    end;
     1024  finally
     1025    Lock.Release;
     1026  end;
     1027end;
     1028
     1029procedure TEngine.Draw;
     1030var
     1031  I: Integer;
     1032begin
    8871033  if FRedrawPending then
    8881034  begin
    8891035    FRedrawPending := False;
    890     //FBitmapLower.FillAll(0);
    891     for I := 0 to Players.Count - 1 do begin
    892       TPlayer(Players[I]).Paint;
    893     end;
    894 
    895     if Assigned(FBitmap) then
    8961036    try
    897       Bitmap.BeginUpdate;
    898       RawImage := Bitmap.RawImage;
    899       BytePerPixel := RawImage.Description.BitsPerPixel div 8;
    900       BytePerRow := RawImage.Description.BytesPerLine;
    901       //FillChar(RawImage.Data^, Bitmap.Height * BytePerRow, 0);
    902 
    903       if (FBitmap.Width / FBitmapLower.Width) < (FBitmap.Height / FBitmapLower.Height) then
    904         Ratio := FBitmap.Width / FBitmapLower.Width
    905         else Ratio := FBitmap.Height / FBitmapLower.Height;
    906 
    907       // Preserve aspect ratio
    908       TargetWidth := Trunc(FBitmapLower.Width * Ratio);
    909       TargetHeight := Trunc(FBitmapLower.Height * Ratio);
    910 
    911       Shift.X := Trunc((Bitmap.Width - TargetWidth) / 2);
    912       Shift.Y := Trunc((Bitmap.Height - TargetHeight) / 2);
    913 
    914       XDiv := TargetWidth div FBitmapLower.Width;
    915       XMod := TargetWidth mod FBitmapLower.Width;
    916       YDiv := TargetHeight div FBitmapLower.Height;
    917       YMod := TargetHeight mod FBitmapLower.Height;
    918 
    919       PixelRowPtr := PInteger(RawImage.Data + BytePerRow * Shift.Y);
    920       YAcc := FBitmapLower.Height div 2;
    921       for Y := 0 to FBitmapLower.Height - 1 do begin
    922         SubPixelSizeY := YDiv;
    923         Inc(YAcc, YMod);
    924         if YAcc >= FBitmapLower.Height then begin
    925           Dec(YAcc, FBitmapLower.Height);
    926           Inc(SubPixelSizeY);
    927         end;
    928 
    929         PixelPtr := PixelRowPtr + Shift.X;
    930         XAcc := FBitmapLower.Width div 2;
    931         for X := 0 to FBitmapLower.Width - 1 do begin
    932           SubPixelSizeX := XDiv;
    933           Inc(XAcc, XMod);
    934           if XAcc >= FBitmapLower.Width then begin
    935             Dec(XAcc, FBitmapLower.Width);
    936             Inc(SubPixelSizeX);
    937           end;
    938 
    939           Color := SwapBRComponent(FBitmapLower.Pixels[X, Y]);
    940 
    941           // Draw large pixel
    942           SubPixelRowPtr := PixelPtr;
    943           for PixelY := 0 to SubPixelSizeY - 1 do begin
    944             SubPixelPtr := SubPixelRowPtr;
    945             for PixelX := 0 to SubPixelSizeX - 1 do begin
    946               SubPixelPtr^ := Color;
    947               Inc(PByte(SubPixelPtr), BytePerPixel);
    948             end;
    949             Inc(PByte(SubPixelRowPtr), BytePerRow);
    950           end;
    951           Inc(PByte(PixelPtr), BytePerPixel * SubPixelSizeX);
    952         end;
    953         Inc(PByte(PixelRowPtr), BytePerRow * SubPixelSizeY);
     1037      Lock.Acquire;
     1038      //FBitmapLower.FillAll(0);
     1039      for I := 0 to Players.Count - 1 do begin
     1040        TPlayer(Players[I]).Paint;
    9541041      end;
    9551042    finally
    956       FBitmap.EndUpdate;
    957     end;
     1043      Lock.Release;
     1044    end;
     1045    Synchronize(DoDrawToBitmap);
    9581046  end;
    9591047end;
Note: See TracChangeset for help on using the changeset viewer.