Jump to content
IGNORED

hacking on a scanline fill for libti99


tschak909

Recommended Posts

Hey guys,

as part of trying to get some nice to haves in PLATOTERM, I've taken a whack at getting a flood fill implemented for paint functions.

 

I'm using the same scan-line fill algorithm that I've used in other ports, but for some reason, things are going kind of nutty, and I'd like to figure out why..?

#include <conio.h>
#include <vdp.h>

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
#define true 1
#define false 0

unsigned char bm_getpixel(int x, int y)
{
  unsigned int addr = ((x>>3)<<3) + ((y>>3)<< + (y&0x07) + gPattern;
  VDP_SET_ADDRESS(addr);
  return CHECK_BIT(VDPRD,(x%);
}

void paint(int x, int y)
{
  static unsigned short xStack[256];
  static unsigned char yStack[192];
  unsigned char stackentry = 1;
  unsigned char spanAbove, spanBelow;

  unsigned char oldColor = bm_getpixel(x,y);

  if (oldColor == 1)
    return;

  do
    {
      unsigned short startx;
      while (x > 0 && bm_getpixel(x-1,y) == oldColor)
        --x;

      spanAbove = spanBelow = false;
      startx=x;

      while(bm_getpixel(x,y) == oldColor)
        {
          if (y < (191))
            {
              unsigned char belowColor = bm_getpixel(x, y+1);
              if (!spanBelow  && belowColor == oldColor)
                {
                  xStack[stackentry]  = x;
                  yStack[stackentry]  = y+1;
                  ++stackentry;
                  spanBelow = true;
                }
              else if (spanBelow && belowColor != oldColor)
                spanBelow = false;
            }

          if (y > 0)
            {
              unsigned char aboveColor = bm_getpixel(x, y-1);
              if (!spanAbove  && aboveColor == oldColor)
                {
                  xStack[stackentry]  = x;
                  yStack[stackentry]  = y-1;
                  ++stackentry;
                  spanAbove = true;
                }
              else if (spanAbove && aboveColor != oldColor)
                spanAbove = false;
            }

          ++x;
        }
      bm_drawline(startx,y,x-1,y,1);
      --stackentry;
      x = xStack[stackentry];
      y = yStack[stackentry];
    }
  while (stackentry);
}

void main(void)
{
  set_bitmap(0);
  bm_clearscreen();
  bm_setforeground(COLOR_BLACK);

  bm_drawline(100,100,150,100,1);
  bm_drawline(100,100,100,120,1);
  bm_drawline(150,100,150,120,1);
  bm_drawline(100,120,150,120,1);

  paint(149,110);

  for (;
    {
    }
}

post-9462-0-54262500-1550274068.gif

 

-Thom

Link to comment
Share on other sites

There is a slight delay between setting the read address and the VDP actually being ready to be read. Throw an _asm("nop") between setting the vdp read address and the actual read and that might fix it.

 

Sent from my SM-J727V using Tapatalk

Not necessary on the TI - the CPU is too slow for the delay to have meaning except in very tight assembly code.

 

One problem you have is that you expect the return of bm_getpixel() to be 0 or 1. It won't be, it will be 0, 1, 2, 4, 8, 16, 32, 64 or 128 (depending on the bit position of the pixel). If you can, just flip your checks around so that you only test against zero instead (faster). Otherwise I'd just change the return to "return (CHECK_BIT(VDPRD,(x% 8))!=0);"

 

I would also change the return type from char to int. Partially because I still don't 100% trust chars, partially because int is the native word size and your code will be faster for just testing a zero/not zero result against one (no need to mask, shift, pull in additional values, etc). (That would imply making oldcolor an int as well).

 

It's not clear to be why 'xstack' is a short and 'ystack' is a char... the maximum x value is only 255 anyway?

 

I think your shift in "CHECK_BIT" is backwards too. If your x modulo is zero, you want the first pixel, which is the MSb (0x80), not 0x01. Start with 0x80 and shift right instead.

 

I'm not sure that I understand the Y tests inside the while loop in a quick read - but I can tell you that if you pass out-of-range values to bm_getpixel() that you will get random results as you read off screen memory. If it's possible for y to be outside the range 0-191, you want to check that before you call bm_getpixel, else you may get unexpected results. (Like changing register values when you go negative ;) ).

Edited by Tursi
Link to comment
Share on other sites

Reading a little more, I don't know if the y loop is correct, but it looks like you aren't repeating the x-search per scanline, or searching to the right, which means you'd only fill a rectangle bounded to the right by the starting coordinate, and on the left by the first pixel found. All other rows will use those same x values.

 

Still, it's probably worth fixing the low hanging fruit before digging deeper. :)

 

(Removed my floodfill suggestion - there are so many edge cases. There are plenty of solutions already out there.)

Edited by Tursi
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...