Browse Source

* made floodfill a *LOT* faster (better DrawnPoints management)

Jonas Maebe 25 years ago
parent
commit
0e4fe19488
1 changed files with 89 additions and 50 deletions
  1. 89 50
      rtl/inc/graph/fills.inc

+ 89 - 50
rtl/inc/graph/fills.inc

@@ -95,7 +95,7 @@ type
         If (frac(x)<0) then dec(t);
         floor := t;
   end;
-
+(*
   { simple descriptive name }
   function max(a, b : graph_int) : graph_int;
   begin
@@ -109,7 +109,7 @@ type
         if (a <= b) then min := a
         else min := b;
   end;
-
+*)
   { needed for the compare functions; should NOT be used for anything else }
 var
         ptable : ppointarray; { pointer to points list }
@@ -273,19 +273,24 @@ begin
     DrawPoly(NumPoints, PolyPoints);
 end;
 
-
+{ maximum supported Y resultion }
+const
+  MaxYRes = 2048;
+  { changing this to 1 or 2 doesn't improve performance noticably }
+  YResDiv = 4;
 
 type
+  PFloodLine = ^TFloodLine;
   TFloodLine = record
+    next: PFloodLine;
     x1 : smallint;
     x2 : smallint;
     y  : smallint;
   end;
 
-  TDrawnList  = Array[0..StdBuffersize] of TFloodLine;
+  TDrawnList  = Array[0..(MaxYRes - 1) div 4] of PFloodLine;
 
 var
-   DrawnIndex : Word;
    DrawnList : TDrawnList;
    Buffer : Record                         { Union for byte and word addressing of buffer }
      ByteIndex : Word;
@@ -346,11 +351,14 @@ var
   { Y axis, from the x1 to x2 coordinates.                 }
   {********************************************************}
   Procedure AddLinePoints(x1,x2,y: smallint);
+   var temp: PFloodLine;
    begin
-     DrawnList[DrawnIndex].x1 := x1;
-     DrawnList[DrawnIndex].x2 := x2;
-     DrawnList[DrawnIndex].y := y;
-     Inc(DrawnIndex);
+     new(temp);
+     temp^.x1 := x1;
+     temp^.x2 := x2;
+     temp^.y := y;
+     temp^.next := DrawnList[y div YResDiv];
+     DrawnList[y div YResDiv] := temp;
    end;
 
   {********************************************************}
@@ -366,28 +374,46 @@ var
   { to draw, otherwise returns FALSE.                      }
   {********************************************************}
   Function AlreadyDrawn(x, y: smallint): boolean;
-   var
-    LocalIndex : smallint;
+  var
+    temp : PFloodLine;
    begin
-    AlreadyDrawn := FALSE;
-    LocalIndex := 0;
-    while LocalIndex < DrawnIndex do
-     Begin
-       { if vertical val is equal to our y point ... }
-       if DrawnList[LocalIndex].y = y then
-         Begin
-           { then check if x >< ... }
-           if (x >= DrawnList[LocalIndex].x1) and
-               (x <= DrawnList[LocalIndex].x2) then
-                 Begin
-                   AlreadyDrawn := TRUE;
-                   exit;
-                 end;
-         end;
-       Inc(LocalIndex);
-     end;
+    AlreadyDrawn := false;
+    temp := DrawnList[y div YResDiv];
+    while assigned(temp) do
+      begin
+        if (temp^.y = y) and
+           (temp^.x1 <= x) and
+           (temp^.x2 >= x) then
+          begin
+            AlreadyDrawn := true;
+            exit;
+          end;
+        temp := temp^.next;
+      end;
    end;
 
+  {********************************************************}
+  { Procedure CleanUpDrawnList                             }
+  {--------------------------------------------------------}
+  { removes all elements from the DrawnList. Doesn't init  }
+  { elements of it with NILL                               }
+  {********************************************************}
+  Procedure CleanUpDrawnList;
+  var
+    l: longint;
+    temp1, temp2: PFloodLine;
+  begin
+    for l := 0 to high(DrawnList) do
+      begin
+        temp1 := DrawnList[l];
+        while assigned(temp1) do
+          begin
+            temp2 := temp1;
+            temp1 := temp1^.next;
+            dispose(temp2);
+          end;
+      end;
+  end;
 
   Procedure FloodFill (x, y : smallint; Border: word);
   {********************************************************}
@@ -407,6 +433,7 @@ var
    x1, x2, prevy: smallint;
    Index : smallint;
   Begin
+    FillChar(DrawnList,sizeof(DrawnList),0);
     { init prevy }
     prevy := 32767;
     { Save current drawing color }
@@ -425,8 +452,6 @@ var
        (x>ViewWidth) Or (y>ViewHeight) then Exit;
     { Some internal variables }
     Index := 0;
-    { Index of segments to draw }
-    DrawnIndex := 0;
     { Index of points to check  }
     Buffer.WordIndex:=0;
     PushPoint (x,y);
@@ -434,25 +459,35 @@ var
      Begin
        PopPoint (x,y);
        { Get the complete lines for the following }
-       If (prevy - y = 1) then
-         { previous line was one below the new one, so the previous s2 }
-         { = new s1                                                    }
-         Begin
-           stemp := s1;
-           s1 := s2;
-           s2 := stemp;
-         End
-       Else If (y - prevy = 1) then
-         { previous line was one above the new one, so the previous s3 }
-         { = new s1                                                    }
-         Begin
-           stemp := s1;
-           s1 := s3;
-           s3 := stemp;
-         End
-       Else GetScanline(0,ViewWidth,y,s1^);
-       GetScanline(0,ViewWidth,y-1,s2^);
-       GetScanline(0,ViewWidth,y+1,s3^);
+       If y <> prevy then
+         begin
+           If (prevy - y = 1) then
+             { previous line was one below the new one, so the previous s2 }
+             { = new s1                                                    }
+             Begin
+               stemp := s3;
+               s3 := s1;
+               s1 := s2;
+               s2 := stemp;
+               GetScanline(0,ViewWidth,y-1,s2^);
+             End
+           Else If (y - prevy = 1) then
+             { previous line was one above the new one, so the previous s3 }
+             { = new s1                                                    }
+             Begin
+               stemp := s2;
+               s2 := s1;
+               s1 := s3;
+               s3 := stemp;
+               GetScanline(0,ViewWidth,y+1,s3^);
+             End
+           Else
+             begin
+               GetScanline(0,ViewWidth,y-1,s2^);
+               GetScanline(0,ViewWidth,y,s1^);
+               GetScanline(0,ViewWidth,y+1,s3^);
+             end;
+         end;
        prevy := y;
        { check the current scan line }
        While (s1^[x]<>Border) And (x<=ViewWidth) Do Inc (x);
@@ -504,12 +539,16 @@ var
     FreeMem (s1,(ViewWidth+1)*2);
     FreeMem (s2,(ViewWidth+1)*2);
     FreeMem (s3,(ViewWidth+1)*2);
+    CleanUpDrawnList;
     CurrentColor := BackUpColor;
   End;
 
 {
 $Log$
-Revision 1.13  1999-12-20 11:22:36  peter
+Revision 1.14  2000-01-02 19:01:32  jonas
+  * made floodfill a *LOT* faster (better DrawnPoints management)
+
+Revision 1.13  1999/12/20 11:22:36  peter
   * integer -> smallint to overcome -S2 switch needed for ggi version
 
 Revision 1.12  1999/12/11 23:41:38  jonas