home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-386-Vol-2of3.iso / b / bgi256-3.zip / FLOOD.DOC < prev    next >
Text File  |  1992-12-27  |  19KB  |  409 lines

  1.                   BGI256 FloodFill Description
  2.                             12/26/92
  3.  
  4.  
  5. I won't be getting into the details of the floodfill algorithms 
  6. here. I will presume that if you wish to explore the inner depths 
  7. of floodfills that you already have the basic understanding. If 
  8. not, you can obtain it from any number of books and articles on 
  9. the subject. The intent of this document is to explain the 
  10. approach I took to floodfill in the BGI256 driver, the reasoning 
  11. behind it, and how to use it.
  12.  
  13.  
  14. Overview:
  15.  
  16. There are two basic types of floodfills. A border bound 
  17. floodfill, and a seed bound floodfill. In the border bound 
  18. floodfill, all areas within a defined border are filled with a 
  19. prescribed color. In a seed bound floodfill only the area 
  20. bound within by the seed color is filled. To put it a bit more 
  21. simply, a border fill will overwrite all other colors inside the 
  22. border color. A seed fill defines as its border any color other 
  23. than the starting seed color.
  24.  
  25. Floodfills always start from a predefined point referred to as 
  26. the "seed" point. The seed defines the area that will be filled 
  27. by declaring where it is to begin. The seed location is always 
  28. passed as the X/Y parameter in the FloodFill command. The color 
  29. value that is passed is the border color to which the fill will 
  30. be confined in a border fill. For seed fill operations, the color 
  31. information passed is ignored. 
  32.  
  33.  
  34. Types of Floodfills:
  35.  
  36. If you look in the graphics books, you will usually see the 
  37. simple floodfill algorithm. It consists of a recursive routine 
  38. that looks at each of the pixel locations surrounding the filled 
  39. location. This is a very slow method and eats lots of stack space 
  40. because of the recursion. Because of the limitations, nobody 
  41. actually uses the basic flood fill algorithm. Other more advanced 
  42. methods are used. 
  43.  
  44. There are a number of methods by which a floodfill can be 
  45. performed. Each has its own set of tradeoffs. They boil down to 
  46. two distinct classes of algorithms. Those that read the display 
  47. to determine if it was already filled (simplex fills), and those 
  48. that track the information separately (complex fills). 
  49.  
  50. The complex floodfills are the most reliable and must be used 
  51. when doing a read/modify/write or a pattern type of fill. The 
  52. disadvantage is that they are slow and use lots of memory 
  53. resources. Complex fills are slow and hog memory because they 
  54. must track every place on the screen that was filled so that it 
  55. won't be filled again. This means that for each fill location on 
  56. the display it must check the location stack to see if it has 
  57. been there before. For large convoluted fills the stack can grow 
  58. to be quite large which can slow things down a lot and use lots 
  59. of memory.
  60.  
  61. A simplex fill is a special case floodfill. It relies on a few 
  62. limitations to be able to perform quickly. The simplex fill 
  63. allows for much faster fills to happen by not bothering to track 
  64. if it has been someplace before. Instead it looks at the display 
  65. to see if it was there before. Since we have to look at the 
  66. display to decide whether to fill it or not, the information is 
  67. already there. 
  68.  
  69. This eliminates the slow down of checking the stack, but requires 
  70. the limitation that the current floodfill drawing color not be 
  71. the seed color. This is because the fast floodfill uses the 
  72. drawing color as the indicator that it has been to the location 
  73. previously. If you think about it, you can see that this creates 
  74. a problem for floodfills which do a read/modify/write type of 
  75. fill such as XOR. What is written to the display is based on what 
  76. was there which means that it changes. A pattern fill has a 
  77. similar problem in that both the background and the foreground 
  78. colors are being filled so a simple single color test won't work, 
  79. and since most pattern fills use the background color, there is 
  80. the problem of dealing with attempting to draw the background 
  81. color on the background. Leading to the problem of once again not 
  82. knowing if you've been there before.
  83.  
  84. To prevent these problems, a complex floodfill must use the 
  85. slower method that tracks the locations of the fill rather than 
  86. reading the screen at the time of the fill. 
  87.  
  88.  
  89. Complex Fill:
  90.  
  91. There are two basic types of location storage. The pixel per bit 
  92. method, and the XY location storage method. The pixel per bit 
  93. method has the advantage of speed because it is a fixed array of 
  94. bits identifying each pixel on the screen. That means that it can 
  95. be directly accessed, making the method very quick. The downside 
  96. is that the entire storage area must be allocated in memory. This 
  97. is ok for small screen areas, but for large screens we run into a 
  98. memory problem. As an example, lets say we are filling a 1024x768 
  99. screen; That means that we would require 98304 bytes of storage 
  100. for the pixel information. That is over the 64K segment 
  101. limitation, which makes things rather difficult. 
  102.  
  103. The other problem is that the BGI driver does not have direct 
  104. access to the system memory. It is provided memory only via the 
  105. stack, and the amount of stack it is given is predefined. The 
  106. default is 4000 bytes. Since the stack also must be used for 
  107. normal stack operations, including interrupts, you have to 
  108. subtract about 2000 bytes from the allocation to determine how 
  109. much stack is actually available for use inside the BGI. This 
  110. means that we only have about 2000 bytes of default stack to work 
  111. with. that comes out to about 24000 pixels. That seems like a lot 
  112. until you realize that it only covers an area of 240x100 pixels. 
  113. Even low-res CGA is larger than that. 
  114.  
  115. The pixel per bit location identification is actually the 
  116. preferred method when the memory is available since it is fast 
  117. efficient and accurate. Unfortunately, in the PC environment it 
  118. runs into hardware limitations. 
  119.  
  120. Given the limitations of the hardware and the driver, it is more 
  121. desirable to use a sparse array method. That is, storing the 
  122. locations of the fills rather than identifying the pixels. 
  123. Luckily, we don't have to store the location of each pixel 
  124. changed, we only need to store the scan line (Y), and the start 
  125. and stop location of the fill on the scan line (X1 and X2). 
  126. That is a big increase in memory usage, from 1/8th byte per pixel 
  127. to 6 bytes, but it makes use of the fact that fills seldom 
  128. consist of individual pixel fills. Most fills involve large areas 
  129. which means that actual memory usage is typically reduced. For a 
  130. fill line of 128 pixels we would use 16 bytes of memory for the 
  131. bit per pixel method, but only 6 bytes for the sparse array 
  132. method. In addition, typically the whole screen is not filled, so 
  133. we only use memory for those scan lines that are actually filled.  
  134. The down side is that we have to search the storage area on each 
  135. fill because it is no longer possible to code a fixed access 
  136. method. That means the search time is significantly slowed down, 
  137. especially when the filled area is convoluted requiring the 
  138. location stack to grow to a large size.
  139.  
  140.  
  141. Simplex fill -- It's the Speed Stupid!
  142.  
  143. While accuracy is important of course, it doesn't do much good if 
  144. it takes over a minute to fill the screen. Users are simply not 
  145. going to accept that kind of performance. So what to do? 
  146.  
  147. A simplex fill can often get the job done much faster and with 
  148. minimal memory usage. The simplex fill does apply some 
  149. restrictions. If you are going to do a read/modify/write type 
  150. fill such as XOR or a patterned fill, you cannot use the simplex 
  151. fill. In a normal fill, the fill mechanism determines if a fill 
  152. is to be done based on whether the pixel is the border color or 
  153. the seed color (depending on the type of fill being done). For 
  154. the simplex fill we add one more test which looks to see if the 
  155. pixel is the fill color. If it is the fill color, then we know 
  156. that we have been there before and it gets treated as if it were 
  157. the border or seed. That way we don't have to track the location 
  158. since we can tell that we have been there by looking at the pixel 
  159. color. 
  160.  
  161. The limitation here is that we can't fill an area with the same 
  162. color. Since normally you would not do that, it is usually an 
  163. acceptable limitation. Most simplex fills concentrate on reducing 
  164. the number of repeat visits to a location to see if it needs to 
  165. be filled. Since each visit slows down the fill operation that 
  166. much longer, it is important to limit the repeats. This is 
  167. normally done by an ordered list pushed on a location stack. 
  168.  
  169. The search method normally involves tracking the direction of the 
  170. search for areas to fill. There is no need to go back to an area 
  171. that was already filled, so by indicating the direction of the 
  172. search, that aspect can be eliminated. A popular method of 
  173. reducing the repeat visits is to break a fillable scan line into 
  174. three sections. Left, middle, and right. The left and right 
  175. sections are explored in both directions if they exceed the 
  176. length of the master scan line we came from. The middle section 
  177. is only explored in the direction we are moving since we know 
  178. where we've been. This reduces the re-visitation time by not 
  179. looking at the scan line we came from. Unfortunately, there is a 
  180. tremendous memory hit to do that. Instead of storing the 
  181. information for one scan line, we have to store it for three 
  182. sections. We've just eaten up three times the memory for a slight 
  183. increase in speed. In most cases it simply isn't worth it. Memory 
  184. is too precious. 
  185.  
  186. In my simplex floodfill I store the entire scan line segment 
  187. instead of breaking it up. This means a slight decrease in speed, 
  188. but empirical experience has shown that in real life there is no 
  189. noticeable difference in speed but a significant difference in 
  190. memory savings. 
  191.  
  192. An advantage of the simplex fill is that it uses an adjustable 
  193. stack. That is it only keeps the minimum information needed on 
  194. the stack for areas that it has yet to explore. A complex fill 
  195. must save everything it has done so that it can know where its 
  196. been. By discarding completed locations off the stack, the 
  197. simplex fill can reduce memory usage. 
  198.  
  199. The simplex fill also has an advantage for situations where we 
  200. run out of memory. In a complex fill, when we run out of memory, 
  201. the fill must terminate at that point since it has no more memory 
  202. to be able to track locations. That usually leaves an incomplete 
  203. floodfill with ragged holes everyplace. With a simplex fill, 
  204. because of the ordered list, and because we can discard old 
  205. information from the stack, we can just stop exploring in the 
  206. direction we were moving, back up and try again in another 
  207. direction. This usually results in a cleaner fill failure. 
  208. Ragged holes are seldom left behind. Usually it is just one or 
  209. two large areas that are left unfilled. 
  210.  
  211.  
  212. Patterned Fills:
  213.  
  214. Another problem with simplex fills is dealing with pattern fills 
  215. (fills with a foreground and background color mix). Since the 
  216. simplex fill looks only for the foreground color, a pattern fill 
  217. can drive it crazy since it will keep trying to fill in the 
  218. background that it put on the display. Because of this, patterned 
  219. fills are not allowed with a simplex floodfill. 
  220.  
  221.  
  222. Auto Flood Fill Detection:
  223.  
  224. Because the simplex floodfill mechanism can't deal with anything 
  225. beyond the simple fill method of a solid unpatterned write only 
  226. foreground color, an auto-detection function exists which looks 
  227. at the floodfill configuration and determines if the floodfill 
  228. can occur as a simplex fill or requires a complex fill. If a 
  229. read/modify/write fill method is selected, or a patterned fill is 
  230. used, it will automatically select the complex fill operation. If 
  231. a single foreground color with solid write only fill is selected, 
  232. and the seed color is not equal to the fill color, the simplex 
  233. method will be used. You can force the complex fill method to be 
  234. used with the ComplexFill option using the SetWriteMode command 
  235. if you wish, but this will slow down the operation and reduce the 
  236. amount of usable stack. It is normally better to let the system 
  237. determine the best method.
  238.  
  239.  
  240. Delayed Filling:
  241.  
  242. Because of the out-of-memory failure problem with complex fills, 
  243. I added a control flag which allows the filling to be delayed 
  244. until all information has been collected. If we run out of 
  245. memory, the flood fill does not happen. This allows an alternate 
  246. action to be taken before damaging the image with a partial fill. 
  247. The delayed fill is only available in the complex fill mode 
  248. because it requires the complex fill location stack to work. If 
  249. the simplex method is selected, the delayed fill flag will be 
  250. ignored. If the simplex fill is automatically selected, and you 
  251. wish to have a delayed fill, you must select the forced complex 
  252. fill method. 
  253.  
  254.  
  255. Flood Tracer:
  256.  
  257. A problem with the delayed fill is that it can take time to 
  258. perform the initial search of the flood area. With nothing 
  259. happening on the screen it can look like the program locked up 
  260. and stopped working. To deal with this, I added a tracer function 
  261. which shows the location of the floodfill search as it traces the 
  262. floodfill area. The tracer works in simplex or complex mode, but 
  263. since the fill is directly noticeable in simplex mode, there is 
  264. no real need to have it on except when in complex fill mode and 
  265. the delayed fill function is turned on.
  266.  
  267.  
  268. Compressed stack:
  269.  
  270. Even with the sparse array method used, the stack can still 
  271. easily run out of space in a convoluted fill pattern. If you run 
  272. out of stack space, you might want to turn on the stack 
  273. compression flag. This reduces stack usage by 33%, giving you 
  274. that much more stack memory. The trade off is that the fill speed 
  275. will be slowed down by about 50%. The reason for this is because 
  276. the stack compression discards the X2 location of the scan line 
  277. (doesn't save it). This provides the 33% reduction of the stack, 
  278. but it means that we must recreate the X2 location when we read 
  279. the location off the stack. To recreate it, we must read the 
  280. screen again to find the end of the scan line segment. That is 
  281. where the 50% slow down comes from. 
  282.  
  283. The following floodfill options are available in the BGI256 
  284. driver. The options are selected via the SetWriteMode function.
  285.  
  286.      BorderFill      (default)
  287.      SeedFill   
  288.      SimplexFill     (default)
  289.      ComplexFIll
  290.      FillCompressOff (default)
  291.      FillCompressOn
  292.      FillDelayOff    (default)
  293.      FillDelayOn
  294.      FillTraceOff    (default)
  295.      FillTraceOn
  296.  
  297.  
  298. You can select the desired option using the SetWriteMode command. 
  299. As an example, to select the Seed method, you would use the 
  300. following statement.
  301.  
  302.  SetWriteMode(FloodFillType+SeedFill);
  303.  
  304.  
  305. Note: Do not mix commands in the same SetWriteMode function. Only 
  306. one command per function call is valid. As an example, the 
  307. following statement is _NOT_ valid.
  308.  
  309.  SetWriteMode(FloodFillType+SeedFill+FillCompressOn+FillDelayOn);
  310.  
  311. Instead, you must write it in three separate statements like the 
  312. following.
  313.  
  314.  SetWriteMode(FloodFillType+SeedFill);
  315.  SetWriteMode(FloodFillType+FillCompressOn);
  316.  SetWriteMode(FloodFillType+FillDelayOn);
  317.  
  318.  
  319. You can read the current option settings by using the 
  320. GetFloodFillOpt command. When you select the command, the current 
  321. floodfill option flags will be returned in the next GetMaxMode 
  322. call. 
  323.  
  324.  SetWriteMode(FloodFillType+GetFloodFillOpt); 
  325.  FFOptFlags := GetMaxMode;"
  326.  
  327.  
  328. The format of the option flag byte is as follows:
  329.  
  330.  bit        description
  331.   0: 0=borderfill    1=seedfill
  332.   1: <reserved>
  333.   2: 0=auto fill     1=force complex fill
  334.   3: 0=compress off  1=compress on
  335.   4: 0=delay off     1=delay on
  336.   5: 0=tracer off    1=tracer on
  337.   6: <reserved>
  338.   7: 0=simplex fill  1=complex fill
  339.  
  340.  
  341.  
  342. Other Misc Functions:
  343.  
  344. When working on your own floodfills, you may find it desirable to 
  345. know just how much stack space is used up. Several functions have 
  346. been provided to obtain that information. Using the SetWriteMode 
  347. Misc Function command, you can ask for the peak stack usage and 
  348. the stack free space left from the previously run fill command. 
  349.  
  350.  
  351. The following code will tell you how much free space was 
  352. available on the fill stack at the end of the last fill command, 
  353. and how much was used. The total space available is the two 
  354. values added together. To determine the number of scan segments 
  355. that were used, dive the Stack Peak value by four if stack 
  356. compression was used, or by six if stack compression was not 
  357. used. 
  358.  
  359.   SetWriteMode(MiscCommand+ReturnXYStackPeak);
  360.   XYStackPeak := GetMaxMode;
  361.   SetWriteMode(MiscCommand+ReturnXYStackFree);
  362.   XYStackFree := GetMaxMode;
  363.  
  364.  
  365. Reminders:
  366.  
  367. One thing to watch out for is to remember that the flood fill is 
  368. based on the color information (border or seed). What may seem to 
  369. be two equal colors on the display may in fact be two different 
  370. colors. As an example, the default startup white color (255) 
  371. looks the same as the graph unit white color (15). In fact, they 
  372. are the same color, but the color _number_ is different. Thus if 
  373. you draw a picture using a border color of 255 then tell the 
  374. floodfill to fill it using the white 15 color, you will not get 
  375. the results you expected. You must remember to use the proper 
  376. border or seed color for the action you want.
  377.  
  378. Also keep in mind that the floodfill is a memory hog. It needs 
  379. lots of memory. Even a simple large circle or square on the 
  380. screen will require more stack space than provided by the default 
  381. memory allocation given to the BGI if the complex fill method is 
  382. used. If you expect to be filling large and/or complex areas, you 
  383. should allocate more memory with the SetGraphBufSize function. 
  384. Note that you must allocate the buffer size before calling 
  385. InitGraph. Once InitGraph has been called, calls to 
  386. SetGraphBufSize will be ignored. 
  387.  
  388. If you expect to be filling user created images, you should set 
  389. the buffer size as large as possible since it is not possible to 
  390. know ahead of time how much memory will be required for the fill. 
  391. You may also want to turn on the stack compression. There will be 
  392. some slow down of the fill, but not by an overly noticeable 
  393. amount, especially when a slow complex fill is being done. The 
  394. 33% improvement in memory usage can make it worthwhile. 
  395.  
  396. In most cases, it is recommended to let the floodfill function 
  397. select the most optimum fill method (simplex or complex) by using 
  398. the AutoFill command (default). 
  399.  
  400. The only error returned by the floodfill command is running out 
  401. of stack memory. Attempting to fill a border or filling a simplex 
  402. seed color is not considered an error condition. If you need to 
  403. detect this situation, look at the stack free space. If the value 
  404. returned is zero, then the flood fill was terminated because an 
  405. attempt was made to fill a border color or the seed color matched 
  406. the fill color for a simplex fill. 
  407.  
  408. <eof>
  409.