Ignore:
Timestamp:
Dec 22, 2016, 8:49:19 PM (8 years ago)
Author:
chronos
Message:
  • Modified: Updated BGRABitmap package.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest/Packages/bgrabitmap/blurfast.inc

    r472 r494  
    11
    22var
    3   blurRow: array of UInt32or64;
     3  blurRowY,blurRowX: packed array of NativeUInt;
     4  iRadiusX,iRadiusY: NativeInt;
     5  weightFactor: NativeUInt;
    46
    57  { Compute weights of pixels in a row }
    68  procedure ComputeBlurRow;
    79  var
    8     i: Integer;
    9   begin
    10     SetLength(blurRow, 2*radius+1);
    11     for i := 0 to radius do
    12     begin
    13       blurRow[i] := i+1;
    14       blurRow[high(blurRow)-i] := blurRow[i];
     10    i: NativeInt;
     11    ofs: single;
     12  begin
     13    SetLength(blurRowX, 2*iRadiusX+1);
     14    if frac(radiusX)=0 then ofs := 1 else ofs := frac(radiusX);
     15    for i := 0 to iRadiusX do
     16    begin
     17      blurRowX[i] := round((i+ofs)*weightFactor);
     18      blurRowX[high(blurRowX)-i] := blurRowX[i];
     19    end;
     20    SetLength(blurRowY, 2*iRadiusY+1);
     21    if frac(radiusY)=0 then ofs := 1 else ofs := frac(radiusY);
     22    for i := 0 to iRadiusY do
     23    begin
     24      blurRowY[i] := round((i+ofs)*weightFactor);
     25      blurRowY[high(blurRowY)-i] := blurRowY[i];
    1526    end;
    1627  end;
     
    1930var
    2031  srcDelta,
    21   verticalWeightShift, horizontalWeightShift: integer;
     32  verticalWeightShift, horizontalWeightShift: NativeInt;
     33  ys1,ys2: NativeInt;
    2234
    2335  { Compute blur result in a vertical direction }
    24   procedure ComputeVerticalRow(psrc: PBGRAPixel; var sums: TRowSum; ys1,ys2: integer); inline;
    25   var ys: integer;
    26       c: TBGRAPixel;
    27       w,aw: cardinal;
    28   begin
    29     for ys := ys1 to ys2 do
     36  procedure ComputeVerticalRow(psrc: PBGRAPixel; var sums: TRowSum; pw: PNativeUInt; count: NativeInt);
     37  var w: NativeUInt;
     38      c: DWord;
     39  begin
     40    while count > 0 do
    3041    with sums do
    3142    begin
    32       c := psrc^;
    33       w := blurRow[ys]; //apply pixel weight
    34       aw := c.alpha*w;
    35       sumA += aw;
     43      dec(count);
     44      w := pw^; //apply pixel weight
     45      inc(pw);
     46      c := PDWord(psrc)^;
     47      inc(PByte(psrc),srcDelta);
    3648      aDiv += w;
    37 
    38       aw := aw shr verticalWeightShift;
     49      w *= ((c shr TBGRAPixel_AlphaShift) and $ff);
     50      sumA += w;
     51      w := w shr verticalWeightShift;
     52      rgbDiv += w;
    3953      {$hints off}
    40       sumR += c.red*aw;
    41       sumG += c.green*aw;
    42       sumB += c.blue*aw;
    43       rgbDiv += aw;
     54      sumR += ((c shr TBGRAPixel_RedShift) and $ff)*w;
     55      sumG += ((c shr TBGRAPixel_GreenShift) and $ff)*w;
     56      sumB += ((c shr TBGRAPixel_BlueShift) and $ff)*w;
    4457      {$hints on}
    45       inc(psrc,srcDelta);
    4658    end;
    4759  end;
    4860
    4961var
    50   sums: array of TRowSum;
    51   sumStartIndex,curIndex: integer;
     62  psum, psumEnd: PRowSum;
     63  sums: packed array of TRowSum;
     64  sumStartIndex: NativeInt;
    5265  total: TRowSum;
    5366  extendedTotal: TExtendedRowSum;
    54   yb,xb,xs,ys1,ys2,x: integer;
    55   w: cardinal;
    56   pdest: PBGRAPixel;
    57   bmpWidth,bmpHeight : integer;
     67  yb,xb,xs,x,xEnd: NativeInt;
     68  w: NativeUInt;
     69  pw: PNativeUInt;
     70  psrc,pdest: PBGRAPixel;
     71  bmpWidth,bmpHeight : NativeInt;
    5872  accumulationFactor: double;
    5973  bounds: TRect;
     74  highSum: NativeInt;
     75  tempDest: TBGRACustomBitmap;
    6076
    6177begin
    62   if radius = 0 then
     78  radiusX := round(radiusX*10)*0.1;
     79  radiusY := round(radiusY*10)*0.1;
     80  if (radiusX <= 0) and (radiusY <= 0) then
    6381  begin
    6482    ADestination.PutImage(0,0,bmp,dmSet);
    6583    exit;
    6684  end;
     85  iRadiusX := ceil(radiusX);
     86  iRadiusY := ceil(radiusY);
     87  if (frac(radiusX)=0) and (frac(radiusY)=0) then
     88    weightFactor:= 1
     89  else
     90    weightFactor:= 10;
    6791  bmpWidth := bmp.Width;
    6892  bmpHeight := bmp.Height;
     
    7296  bounds := bmp.GetImageBounds;
    7397  if IsRectEmpty(bounds) then exit;
    74   bounds.Left   := max(0, bounds.Left - radius);
    75   bounds.Top    := max(0, bounds.Top - radius);
    76   bounds.Right  := min(bmp.Width, bounds.Right + radius);
    77   bounds.Bottom := min(bmp.Height, bounds.Bottom + radius);
     98  bounds.Left   := max(0, bounds.Left - iRadiusX);
     99  bounds.Top    := max(0, bounds.Top - iRadiusY);
     100  bounds.Right  := min(bmp.Width, bounds.Right + iRadiusX);
     101  bounds.Bottom := min(bmp.Height, bounds.Bottom + iRadiusY);
    78102  if not IntersectRect(bounds,bounds,ABounds) then exit;
    79103
    80   accumulationFactor := (radius+2)*(radius+1) div 2 + (radius+1)*radius div 2;
     104  if radiusX*radiusY >= 100 then
     105  begin
     106    tempDest := ADestination.NewBitmap(ADestination.Width,ADestination.Height);
     107    FilterBlurBox(bmp,bounds,radiusX/3.2,radiusY/3.2,tempDest);
     108    FilterBlurBox(tempDest,bounds,radiusX/2.9,radiusY/2.9,ADestination);
     109    FilterBlurBox(ADestination,bounds,radiusX/3.2,radiusY/3.2,tempDest);
     110    FilterBlurBox(tempDest,bounds,radiusX/2.3,radiusY/2.3,ADestination, ACheckShouldStop);
     111    tempDest.Free;
     112    exit;
     113  end;
     114
     115  accumulationFactor := (iRadiusY+2)*(iRadiusY+1) div 2 + (iRadiusY+1)*iRadiusY div 2;
     116  accumulationFactor *= sqr(weightFactor);
    81117  verticalWeightShift := 0;
    82   while accumulationFactor > (high(UInt32or64) shr 16) + 1 do
     118  while accumulationFactor > (high(NativeUInt) shr 16) + 1 do
    83119  begin
    84120    inc(verticalWeightShift);
     
    86122  end;
    87123  horizontalWeightShift:= 0;
    88   accumulationFactor *= ((radius+2)*(radius+1) div 2 + (radius+1)*radius div 2);
    89   while accumulationFactor > (high(UInt32or64) shr 16) + 1 do
     124  accumulationFactor *= ((iRadiusX+2)*(iRadiusX+1) div 2 + (iRadiusX+1)*iRadiusX div 2);
     125  accumulationFactor *= sqr(weightFactor);
     126  while accumulationFactor > (high(NativeUInt) shr 16) + 1 do
    90127  begin
    91128    inc(horizontalWeightShift);
     
    94131  ComputeBlurRow;
    95132  //current vertical sums
    96   setlength(sums, 2*radius+1);
     133  setlength(sums, 2*iRadiusX+1);
     134  highSum := high(Sums);
     135  psumEnd := @sums[highSum];
     136  inc(psumEnd);
    97137  if bmp.LineOrder = riloTopToBottom then
    98     srcDelta := bmpWidth else
    99       srcDelta := -bmpWidth;
     138    srcDelta := bmpWidth*sizeof(TBGRAPixel) else
     139      srcDelta := -bmpWidth*sizeof(TBGRAPixel);
     140
     141  xEnd := bounds.left-iRadiusX+highSum;
     142  if xEnd >= bmpWidth then xEnd := bmpWidth-1;
    100143  //loop through destination bitmap
    101144  for yb := bounds.top to bounds.bottom-1 do
     
    103146    if (ACheckShouldStop <> nil) and ACheckShouldStop(yb) then break;
    104147    //evalute available vertical range
    105     if yb - radius < 0 then
    106       ys1 := radius - yb
     148    if yb - iRadiusY < 0 then
     149      ys1 := iRadiusY - yb
    107150    else
    108151      ys1 := 0;
    109     if yb + radius >= bmpHeight then
    110       ys2 := bmpHeight - yb + radius - 1
     152    if yb + iRadiusY >= bmpHeight then
     153      ys2 := bmpHeight-1 - yb + iRadiusY
    111154    else
    112       ys2 := high(sums);
     155      ys2 := 2*iRadiusY;
    113156
    114157    { initial vertical rows are computed here. Later,
    115158      for each pixel, vertical sums are shifted, so there
    116159      is only one vertical sum to calculate }
    117     for xs := 0 to high(sums) do
    118     begin
    119       fillchar(sums[xs],sizeof(TRowSum),0);
    120       x := bounds.left-radius+xs;
    121       if (x >= 0) and (x < bmpWidth) then
    122         ComputeVerticalRow(bmp.ScanLine[yb-radius+ys1]+x,sums[xs],ys1,ys2);
     160    fillchar(sums[0],sizeof(TRowSum)*length(sums),0);
     161    x := bounds.left-iRadiusX;
     162    if x < 0 then
     163    begin
     164      xs := -x;
     165      x := 0;
     166    end else
     167      xs := 0;
     168    psrc := bmp.ScanLine[yb-iRadiusY+ys1]+x;
     169    psum := @sums[xs];
     170    pw := @blurRowY[ys1];
     171    while true do
     172    begin
     173      ComputeVerticalRow(psrc,psum^,pw,ys2-ys1+1);
     174      inc(x);
     175      inc(psrc);
     176      if x > xEnd then break;
     177      inc(psum);
    123178    end;
    124179    sumStartIndex := 0;
     
    128183    begin
    129184      //add vertical rows
    130       curIndex:= sumStartIndex;
     185      pw := @blurRowX[0];
     186      psum := @sums[sumStartIndex];
    131187      if horizontalWeightShift > 4 then
    132188      begin //we don't want to loose too much precision
    133         {$hints off}
    134         fillchar(extendedTotal,sizeof(extendedTotal),0);
    135         {$hints on}
    136         for xs := 0 to high(sums) do
    137         with sums[curIndex] do
     189        fillchar({%H-}extendedTotal,sizeof(extendedTotal),0);
     190        for xs := highSum downto 0 do
     191        with psum^ do
    138192        begin
    139           w := blurRow[xs];
     193          w := pw^;
     194          inc(pw);
    140195          extendedTotal.sumA += TExtendedRowValue(sumA)*w;
    141196          extendedTotal.aDiv += TExtendedRowValue(aDiv)*w;
     
    144199          extendedTotal.sumB += TExtendedRowValue(sumB)*w;
    145200          extendedTotal.rgbDiv += TExtendedRowValue(rgbDiv)*w;
    146           inc(curIndex);
    147           if curIndex = length(sums) then curIndex := 0;
     201          inc(psum);
     202          if psum >= psumEnd then pSum := @sums[0];
    148203        end;
    149204        if (extendedTotal.aDiv > 0) and (extendedTotal.rgbDiv > 0) then
     
    154209      if horizontalWeightShift > 0 then
    155210      begin //lossy but efficient way
    156         {$hints off}
    157         fillchar(total,sizeof(total),0);
    158         {$hints on}
    159         for xs := 0 to high(sums) do
    160         with sums[curIndex] do
     211        fillchar({%H-}total,sizeof(total),0);
     212        for xs := highSum downto 0 do
     213        with psum^ do
    161214        begin
    162           w := blurRow[xs];
     215          w := pw^;
     216          inc(pw);
    163217          total.sumA += sumA*w shr horizontalWeightShift;
    164218          total.aDiv += aDiv*w shr horizontalWeightShift;
     
    167221          total.sumB += sumB*w shr horizontalWeightShift;
    168222          total.rgbDiv += rgbDiv*w shr horizontalWeightShift;
    169           inc(curIndex);
    170           if curIndex = length(sums) then curIndex := 0;
     223          inc(psum);
     224          if psum >= psumEnd then pSum := @sums[0];
    171225        end;
    172226        if (total.aDiv > 0) and (total.rgbDiv > 0) then
     
    179233        fillchar(total,sizeof(total),0);
    180234        {$hints on}
    181         for xs := 0 to high(sums) do
    182         with sums[curIndex] do
     235        for xs := highSum downto 0 do
     236        with psum^ do
    183237        begin
    184           w := blurRow[xs];
     238          w := pw^;
     239          inc(pw);
    185240          total.sumA += sumA*w;
    186241          total.aDiv += aDiv*w;
     
    189244          total.sumB += sumB*w;
    190245          total.rgbDiv += rgbDiv*w;
    191           inc(curIndex);
    192           if curIndex = length(sums) then curIndex := 0;
     246          inc(psum);
     247          if psum >= psumEnd then pSum := @sums[0];
    193248        end;
    194249        if (total.aDiv > 0) and (total.rgbDiv > 0) then
    195           pdest^:= ComputeAverage(total)
     250          pdest^ := ComputeAverage(total)
    196251        else
    197252          pdest^:= BGRAPixelTransparent;
     
    199254      inc(pdest);
    200255      //shift vertical rows
    201       fillchar(sums[sumStartIndex],sizeof(TRowSum),0);
    202       x := xb+1-radius+high(sums);
    203       if (x >= 0) and (x < bmpWidth) then
    204         ComputeVerticalRow(bmp.ScanLine[yb-radius+ys1]+x,sums[sumStartIndex],ys1,ys2);
     256      psum := @sums[sumStartIndex];
     257      fillchar(psum^,sizeof(TRowSum),0);
     258      if x < bmpWidth then
     259      begin
     260        ComputeVerticalRow(psrc,psum^,@blurRowY[ys1],ys2-ys1+1);
     261        inc(x);
     262        inc(psrc);
     263      end;
    205264      inc(sumStartIndex);
    206       if sumStartIndex = length(sums) then sumStartIndex := 0;
     265      if sumStartIndex > highSum then sumStartIndex := 0;
    207266    end;
    208267  end;
Note: See TracChangeset for help on using the changeset viewer.