unit scanline_mask;
//типа сам придумал, оказывается сканлине довольно шустро рисует.
//хотя надо было оставить с pixels[] :)
interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, dialogs;

const
  MaxPixelCount = MaxInt div SizeOf(TRGBTriple);


type
  PRGBArray = ^TRGBArray;
  TRGBArray = array[0..MaxPixelCount-1] of TRGBTriple;

  TShadow_sprite = class
  private
   _F_out:TBitmap; //для вывода
   _F_shadow_Bitmap:Tbitmap; //mask
   _F_prep:TBitmap;  //копим из реса
   
   procedure Shadow;
   procedure ShadowEXT;
   procedure ShadowDark;
  protected
  public
   _shadow:boolean;
   _Rect:TRECT;
   procedure Init;
   procedure Fill_shadow(s:string);
   procedure Draw_shadow(canvas,canvas_s:Tcanvas;  x,y:integer);
   procedure Draw_shadow_EXT(canvas,canvas_s:Tcanvas;  x,y:integer);
   procedure Draw_shadow_Dark(canvas,canvas_s:Tcanvas;  x,y:integer);
  end;

implementation


procedure TShadow_sprite.Init;
begin
  _F_out:=Tbitmap.Create;
  _F_out.PixelFormat := pf24bit;
  _F_prep:=Tbitmap.Create;
  _F_prep.PixelFormat:=pf24bit;
  _F_shadow_Bitmap:=Tbitmap.Create;
  _F_shadow_Bitmap.PixelFormat:=pf24bit;
  _shadow:=false;
end;


procedure TShadow_sprite.Shadow;
var x, y: Integer; Row1,Row2, DestRow: PRGBArray;  z1,z2,z3:integer;
begin
  for Y := 0 to _F_shadow_Bitmap.Height - 1 do begin
     Row1:= _F_shadow_Bitmap.ScanLine[y];
     DestRow := _F_prep.ScanLine[y];
     Row2:=_F_out.ScanLine[y];
    for x := 0 to _F_shadow_Bitmap.Width - 1 do begin
          z1:=round(DestRow[x].rgbtRed+DestRow[x].rgbtRed*(Row1[x].rgbtRed/255)); if z1>255 then z1:=255;
          Row2[x].rgbtRed:=z1;
          z2:=round(DestRow[x].rgbtGreen+DestRow[x].rgbtGreen*(Row1[x].rgbtGreen/255)); if z2>255 then z2:=255;
          Row2[x].rgbtGreen:=z2;
          z3:=round(DestRow[x].rgbtBlue+DestRow[x].rgbtBlue*(Row1[x].rgbtBlue/255)); if z3>255 then z3:=255;
          Row2[x].rgbtBlue:=z3;
    end;
  end
end;

procedure TShadow_sprite.ShadowEXT;
var x, y: Integer; Row1,Row2, DestRow: PRGBArray; z1,z2,z3:integer;
begin
  for Y := 0 to _F_shadow_Bitmap.Height - 1 do begin
     Row1:= _F_shadow_Bitmap.ScanLine[y];
     DestRow := _F_prep.ScanLine[y];
     Row2:=_F_out.ScanLine[y];
    for x := 0 to _F_shadow_Bitmap.Width - 1 do begin
          z1:=round(DestRow[x].rgbtRed+DestRow[x].rgbtRed*(Row1[x].rgbtRed/80)); if z1>255 then z1:=255;
          Row2[x].rgbtRed:=z1;
          z2:=round(DestRow[x].rgbtGreen+DestRow[x].rgbtGreen*(Row1[x].rgbtGreen/80)); if z2>255 then z2:=255;
          Row2[x].rgbtGreen:=z2;
          z3:=round(DestRow[x].rgbtBlue+DestRow[x].rgbtBlue*(Row1[x].rgbtBlue/80)); if z3>255 then z3:=255;
          Row2[x].rgbtBlue:=z3;
    end;
  end
end;


procedure TShadow_sprite.ShadowDark;
var x, y: Integer; Row1,Row2, DestRow: PRGBArray;  z1,z2,z3:integer;
begin
  for Y := 0 to _F_shadow_Bitmap.Height - 1 do begin
     Row1:= _F_shadow_Bitmap.ScanLine[y];
     DestRow := _F_prep.ScanLine[y];
     Row2:=_F_out.ScanLine[y];
    for x := 0 to _F_shadow_Bitmap.Width - 1 do begin
          z1:=round(DestRow[x].rgbtRed-DestRow[x].rgbtRed*(Row1[x].rgbtRed/255)); if z1<0 then z1:=0;
          Row2[x].rgbtRed:=z1;
          z2:=round(DestRow[x].rgbtGreen-DestRow[x].rgbtGreen*(Row1[x].rgbtGreen/255)); if z2<0 then z2:=0;
          Row2[x].rgbtGreen:=z2;
          z3:=round(DestRow[x].rgbtBlue-DestRow[x].rgbtBlue*(Row1[x].rgbtBlue/255)); if z3<0 then z3:=0;
          Row2[x].rgbtBlue:=z3;
    end;
  end
end;

procedure TShadow_sprite.Fill_shadow(s:string);
var Bt:Tbitmap;
begin
 bt:=Tbitmap.Create;
 try
 bt.LoadFromFile(s);

_F_shadow_Bitmap.Width:=bt.Width;
_F_shadow_Bitmap.Height:=bt.Height;
_F_shadow_Bitmap.Canvas.CopyRect(_F_shadow_Bitmap.Canvas.ClipRect,bt.Canvas,bt.Canvas.ClipRect);

_Rect.Right:=_F_shadow_Bitmap.Width; _Rect.Bottom:=_F_shadow_Bitmap.Height;
_F_prep.Width:=_Rect.Right; _F_prep.Height:=_Rect.Bottom;
_F_out.Width:=_Rect.Right; _F_out.Height:=_Rect.Bottom;
 finally
  bt.Free;
 end;
end;

procedure TShadow_sprite.Draw_shadow(canvas,canvas_s:Tcanvas;  x,y:integer);
begin
_F_prep.Canvas.CopyRect(_Rect,canvas,classes.rect(_rect.Left+x,_rect.Top+y,_rect.Right+x,_rect.Bottom+y));
Shadow;
canvas_s.CopyRect(classes.rect(_rect.Left+x,_rect.Top+y,_rect.Right+x,_rect.Bottom+y),_F_out.canvas,_rect);
end;

procedure TShadow_sprite.Draw_shadow_EXT(canvas,canvas_s:Tcanvas;  x,y:integer);
begin
_F_prep.Canvas.CopyRect(_Rect,canvas,classes.rect(_rect.Left+x,_rect.Top+y,_rect.Right+x,_rect.Bottom+y));
ShadowEXT;
canvas_s.CopyRect(classes.rect(_rect.Left+x,_rect.Top+y,_rect.Right+x,_rect.Bottom+y),_F_out.canvas,_rect);
end;

procedure TShadow_sprite.Draw_shadow_Dark(canvas,canvas_s:Tcanvas;  x,y:integer);
begin
_F_prep.Canvas.CopyRect(_Rect,canvas,classes.rect(_rect.Left+x,_rect.Top+y,_rect.Right+x,_rect.Bottom+y));
ShadowDark;
canvas_s.CopyRect(classes.rect(_rect.Left+x,_rect.Top+y,_rect.Right+x,_rect.Bottom+y),_F_out.canvas,_rect);
end;

end.
