English Amiga Board


Go Back   English Amiga Board > Coders > Coders. General

 
 
Thread Tools
Old 16 December 2019, 14:56   #1
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Blitter fill, writing clearing instead of setting?

Is the blitter fill mode limited to setting bits only? I can't find, either by searching or experimentation any way to clear rather than setting, just indications that it's not possible.

I want to fill / clear this (simplified):
00100
00010
00001
00000
00000
to result in:
00111
00011
00001
00000
00000
I can add extra 1s to the source if I have to, but I can't change where the existing 1s are.

This is for clearing / filling the last bitplane in my flight sim thingy to make sure the ground is drawn before I draw things on top of it. I need it to be inclusively filled so it's consistent with how it's drawn in other situations and so it works when I draw the next layer on top by drawing on another bitplane.

Any ideas?

Last edited by deimos; 16 December 2019 at 15:06.
deimos is offline  
Old 16 December 2019, 15:13   #2
roondar
Registered User
 
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,408
I read http://amigadev.elowar.com/read/ADCD.../node0122.html to mean that the fill mode can only 'fill' in various ways, not clear. It's certainly possible I misread it, but AFAIK you're correct in saying that it's not supported.
roondar is offline  
Old 16 December 2019, 15:42   #3
a/b
Registered User
 
Join Date: Jun 2016
Location: europe
Posts: 1,039
You can set the initial state (normally 0, so it skips pixels until it hits a 1) in bltcon1 carry-in bit. If you set it to 1, it will start filling from the start of each line (right border in fill mode, of course), and then switch to skipping when it hits a 1.
a/b is offline  
Old 16 December 2019, 15:57   #4
Samurai_Crow
Total Chaos forever!
 
Samurai_Crow's Avatar
 
Join Date: Aug 2007
Location: Waterville, MN, USA
Age: 49
Posts: 2,186
If you are using a TempRast, you can always invert the minterms of the final blit to apply the mask.
Samurai_Crow is offline  
Old 16 December 2019, 16:04   #5
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Quote:
Originally Posted by Samurai_Crow View Post
If you are using a TempRast, you can always invert the minterms of the final blit to apply the mask.
I'm not. I'm trying to do this in one operation.
deimos is offline  
Old 16 December 2019, 16:06   #6
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Quote:
Originally Posted by a/b View Post
You can set the initial state (normally 0, so it skips pixels until it hits a 1) in bltcon1 carry-in bit. If you set it to 1, it will start filling from the start of each line (right border in fill mode, of course), and then switch to skipping when it hits a 1.
I can't find a way to do that with the FCI bit without ending up with a line down the right hand edge, as I have to draw pixels there to turn off the fill, and I have to use inclusive fill mode, i.e.

I draw this:
00100
00010
00001
00001
00001
and the blitter fills it as:
00111
00011
00001
00001
00001
I could split it into two blits, just clearing the bottom few rows, but there's a point where it's more effort than it's worth - this is case #2 of the 14 cases I have to deal with to draw the sky / ground. I am wondering if there is a better way.

Last edited by deimos; 16 December 2019 at 16:43.
deimos is offline  
Old 16 December 2019, 16:58   #7
chb
Registered User
 
Join Date: Dec 2014
Location: germany
Posts: 439
WARNING, NOT TESTED
Maybe you could left-shift your source by one pixel, then use exclusive fill with FCI set to 1:
Code:
00100
00010
00001
00000
00000

Shift:
01000
00100
00010
00000
00000
(set mask registers accordingly)
Now you need the ones at the beginning of the empty lines, which is a bit tricky, as you have shifted your source. One way to tackle that could be to use a second, non-shifted (empty) source buffer where you put the ones and use an OR-minterm (that gives you unfortunately a slightly slower blitt and needs additional memory):
Code:
Shifted buffer:
01000
00100
00010
00000
00000

non-shifted ones buffer:
00000
00000
00000
00001
00001

ORed together:
01000
00100
00010
00001
00001

Exclusive fill with FCI set:
00111
00011
00001
00000
00000
I think there shouldn't be any problems with pixels on the very left, because they would result in completely filled lines, and that's what is supposed to happen. But as said, nothing tested, I may be completely wrong.
chb is offline  
Old 16 December 2019, 17:15   #8
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Quote:
Originally Posted by chb View Post
Maybe you could left-shift your source by one pixel
Do you mean by using blitter settings or by subtracting 1 from my x coordinates when drawing my line?

Quote:
Originally Posted by chb View Post
a second, non-shifted (empty) source buffer where you put the ones and use an OR-minterm
I can use different minterms with filling? Is there not just an option to invert the minterms and get 0s where I was getting 1s?

Quote:
Originally Posted by chb View Post
(that gives you unfortunately a slightly slower blitt and needs additional memory)
I guess this is the point where I need to weigh up whether it's worth it, compared to splitting the blit into two, or using a scratch buffer and two+ blits.
deimos is offline  
Old 16 December 2019, 17:21   #9
a/b
Registered User
 
Join Date: Jun 2016
Location: europe
Posts: 1,039
Well, that's a different picture than the one in the first post.

In any case, you wouldn't have do draw that line if you were using the FCI bit. When you are doing filled poly clipping, you normally draw a vertical line on the right-hand border when a line-segment is >= width, because blitter works right to left, and skip the left-hand border entirely (don't draw anything when < 0). So you just either change your poly-clipper to optionally skip those lines, or make two routines if performance is an issue.
Or is there another 'hidden' constraint?
a/b is offline  
Old 16 December 2019, 17:33   #10
chb
Registered User
 
Join Date: Dec 2014
Location: germany
Posts: 439
Quote:
Originally Posted by deimos View Post
Do you mean by using blitter settings or by subtracting 1 from my x coordinates when drawing my line?
I thought of blitter shift; AFAIU changing your source was not an option (apart from adding ones. If you can draw it shifted, there's no need to use the second buffer.
Quote:
Originally Posted by deimos View Post
I can use different minterms with filling? Is there not just an option to invert the minterms and get 0s where I was getting 1s?
Filling is just an additional last step working solely on the result of the previous operations. You can use shift, mask, use multiple sources, minterms as usual, but I don't think you can achieve what you want by simply using a NOT minterm.
chb is offline  
Old 16 December 2019, 17:35   #11
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Quote:
Originally Posted by a/b View Post
Well, that's a different picture than the one in the first post.

In any case, you wouldn't have do draw that line if you were using the FCI bit. When you are doing filled poly clipping, you normally draw a vertical line on the right-hand border when a line-segment is >= width, because blitter works right to left, and skip the left-hand border entirely (don't draw anything when < 0). So you just either change your poly-clipper to optionally skip those lines, or make two routines if performance is an issue.
Or is there another 'hidden' constraint?
If we're talking about the same thing, that line is to turn off the fill that's FCI carried in, so it doesn't work in the example I gave.

Changing my poly-clipper to skip those lines sounds essentially the same as splitting the blit into two, one where the diagonal line exists, as a fill, and a second as just a clear, below that.

The 'hidden' constraints are only that I'm trying to make this part of my screen clearing process, so I was aiming for a single blit for the bitplane that is my sky / ground, i.e. all the sky bits are set to 0 and all the ground bits are set to 1. The other 3 bitplanes have all been set to 0 in a previous blit.

The set up I've done to get to this point is to partially clip the screen rectangle against the ground plane - if I see that two adjacent corners are not eith both above or both below the ground then I know there's an intersection to calculate. I don't get a polygon as such, I just know which edges have intersections and that's the horizon line, an I have to fill / clear above / below it. As it's part of my screen clearing I want both filling and clearing to happen.

I can post code if it helps more than it hurts.
deimos is offline  
Old 16 December 2019, 17:38   #12
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Quote:
Originally Posted by chb View Post
I thought of blitter shift; AFAIU changing your source was not an option (apart from adding ones. If you can draw it shifted, there's no need to use the second buffer.

Filling is just an additional last step working solely on the result of the previous operations. You can use shift, mask, use multiple sources, minterms as usual, but I don't think you can achieve what you want by simply using a NOT minterm.
Drawing it shifted introduces complexities, like clipping and corner cases that I really want to avoid.
deimos is offline  
Old 16 December 2019, 19:04   #13
a/b
Registered User
 
Join Date: Jun 2016
Location: europe
Posts: 1,039
OK, i see. Not a typical poly renderer.

Option 1:
Assuming you clear the entire bitplane beforehand, and the horizon is a simple straight line: find min_y and max_y (screen coords) of the plane while drawing sky/plane lines and then only fill between them.

Option 2:
How about a simple post-processing loop to clear bytes that are equal to 1 (only the rightmost pixel is set), something like:
Code:
char  table[256] = { 0, 0, 2, 3, 4, ..., 255 };  // 1 is mapped to 0, the rest is unchanged
char* p_plane = sky_plane_bitplane+width/8-1; // last byte of the first line
for (int h = 0;  h < height;  ++h)
  { *p_plane = table[*p_plane];  p_plane += width/8; }
a/b is offline  
Old 16 December 2019, 19:13   #14
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Quote:
Originally Posted by a/b View Post
OK, i see. Not a typical poly renderer.

Option 1:
Assuming you clear the entire bitplane beforehand, and the horizon is a simple straight line: find min_y and max_y (screen coords) of the plane while drawing sky/plane lines and then only fill between them.

Option 2:
How about a simple post-processing loop to clear bytes that are equal to 1 (only the rightmost pixel is set), something like:
Code:
char  table[256] = { 0, 0, 2, 3, 4, ..., 255 };  // 1 is mapped to 0, the rest is unchanged
char* p_plane = sky_plane_bitplane+width/8-1; // last byte of the first line
for (int h = 0;  h < height;  ++h)
  { *p_plane = table[*p_plane];  p_plane += width/8; }
I think option 1 is conceptually similar to my idea of splitting the blit.

I'm not understanding your option 2 though. Exactly why would we want to do that?

Edit: Oh, post-process the result...

Edit 2: I could just draw the line again to do that, I know where it starts and ends. I'll investigate this further. Adding the line is a kludge, I don't have a problem adding a second kludge to unkludge it.

Last edited by deimos; 16 December 2019 at 19:32.
deimos is offline  
Old 17 December 2019, 16:51   #15
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Quote:
Originally Posted by deimos View Post
Edit: Oh, post-process the result...

Edit 2: I could just draw the line again to do that, I know where it starts and ends. I'll investigate this further. Adding the line is a kludge, I don't have a problem adding a second kludge to unkludge it.
I've now implemented that, and it works sweet, and I think is probably pretty efficient.

But my code is a complexity of nested if statements for all the different cases of how the horizon line might cross each edge of the screen, and I can't see an obvious way of simplifying it. If anyone can point out what I think I must be missing, that would be great:

Code:
void GroundAndSky_Draw(const Camera * camera) {
    WORD displayHeight = display.displayMode == SPLIT_SCREEN_DISPLAY_MODE ? SPLIT_SCREEN_MAIN_DISPLAY_HEIGHT :
                                                                            DISPLAY_HEIGHT;

    LONG a = ((Entity *) camera)->transformation.rotation.value[0][1];
    LONG b = ((Entity *) camera)->transformation.rotation.value[1][1];

    LONG cz = ((Entity *) camera)->transformation.rotation.value[2][1] << 8; // 2^8 = 256 = viewing distance

    LONG topY = displayHeight / 2 - 1;
    LONG rightX = DISPLAY_WIDTH / 2 - 1;
    LONG bottomY = -displayHeight / 2;
    LONG leftX = -DISPLAY_WIDTH / 2;

    BOOL topLeft = a * leftX + b * topY + cz < 0;
    BOOL topRight = a * rightX + b * topY + cz < 0;
    BOOL bottomRight = a * rightX + b * bottomY + cz < 0;
    BOOL bottomLeft = a * leftX + b * bottomY + cz < 0;

    BOOL intersectsTop = topLeft != topRight;
    BOOL intersectsRight = topRight != bottomRight;
    BOOL intersectsBottom = bottomLeft != bottomRight;
    BOOL intersectsLeft = topLeft != bottomLeft;

    if (intersectsTop) {
        Point2D p0 = {{ rightX - (cz + b * topY) / a, 0 }};
        if (intersectsRight) { // top edge to right edge
            WORD y = topY + (cz + a * rightX) / b;
            Point2D p1 = {{ DISPLAY_WIDTH - 1, y }};

            Point2D line [2] = { p0, p1 };
            WORD kludge [2] = { y + 1, displayHeight - 1 };
            BOOL fci = topRight;

            FancyBlitterFillWithKludge(line, kludge, fci);
        } else if (intersectsBottom) { // top edge to bottom edge
            Point2D p1 = {{ rightX - (cz - b * topY) / a, displayHeight - 1 }};

            Point2D line [2] = { p0, p1 };
            BOOL fci = topRight;

            FancyBlitterFill(line, fci);
        } else if (intersectsLeft) { // top edge to left edge
            WORD y = topY + (cz - a * rightX) / b;
            Point2D p1 = {{ 0, y }};

            Point2D line [2] = { p0, p1 };
            BOOL fci = !topLeft;

            FancyBlitterFill(line, fci);
        }
    } else if (intersectsRight) {
        if (intersectsBottom) { // right edge to bottom edge
            WORD y = topY + (cz + a * rightX) / b;
            Point2D p2 = {{ DISPLAY_WIDTH - 1, y }};
            Point2D p3 = {{ rightX - (cz - b * topY) / a, displayHeight - 1 }};

            Point2D line [2] = { p2, p3 };
            WORD kludge [2] = { 0, y - 1 };
            BOOL fci = !topLeft;

            FancyBlitterFillWithKludge(line, kludge, fci);
        } else if (intersectsLeft) { // left edge to right edge
            WORD yLeft = topY + (cz - a * rightX) / b;
            WORD yRight = topY + (cz + a * rightX) / b;
            Point2D p0 = {{ 0, yLeft }};
            Point2D p1 = {{ DISPLAY_WIDTH - 1, yRight }};

            Point2D line [2] = { p0, p1 };

            if (topLeft) {
                if (yRight > yLeft) {
                    WORD kludge [2] = { yRight + 1, displayHeight - 1 };
                    FancyBlitterFillWithKludge(line, kludge, TRUE);
                } else {
                    WORD kludge [2] = { 0, yRight - 1 };
                    FancyBlitterFillWithKludge(line, kludge, FALSE);
                }
            } else {
                if (yRight < yLeft) {
                    WORD kludge [2] = { 0, yRight - 1 };
                    FancyBlitterFillWithKludge(line, kludge, TRUE);
                } else {
                    WORD kludge [2] = { yRight + 1, displayHeight - 1 };
                    FancyBlitterFillWithKludge(line, kludge, FALSE);
                }
            }
        }
    } else if (intersectsBottom) { // bottom edge to left edge
        Point2D p0 = {{ 0, topY + (cz - a * rightX) / b }};
        Point2D p1 = {{ rightX - (cz - b * topY) / a, displayHeight - 1 }};

        Point2D line [2] = { p0, p1 };
        BOOL fci = topRight;

        FancyBlitterFill(line, fci);
    } else { // no intersections
        BlitterFill(topLeft);
    }
}
deimos is offline  
Old 20 December 2019, 14:19   #16
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
I've cleaned up the code the best I can and also used it to make the artificial horizon on the instrument panel work.

Executable attached for anyone interested.

The code now looks like this, it's better than it was, but it still seems overly complicated:

Code:
void GroundAndSky_Draw(const Camera * camera) {
    WORD displayHeight = display.displayMode == SPLIT_SCREEN_DISPLAY_MODE ? SPLIT_SCREEN_MAIN_DISPLAY_HEIGHT :
                                                                            DISPLAY_HEIGHT;

    LONG a = ((Entity *) camera)->transformation.rotation.value[0][1];
    LONG b = ((Entity *) camera)->transformation.rotation.value[1][1];

    LONG cz = ((Entity *) camera)->transformation.rotation.value[2][1] << 8; // 2^8 = 256 = viewing distance

    LONG leftX = -DISPLAY_WIDTH / 2;
    LONG rightX = DISPLAY_WIDTH / 2;
    LONG topY = displayHeight / 2;
    LONG bottomY = -displayHeight / 2;

    BOOL topLeft = a * leftX + b * topY + cz < 0;
    BOOL topRight = a * rightX + b * topY + cz < 0;
    BOOL bottomLeft = a * leftX + b * bottomY + cz < 0;
    BOOL bottomRight = a * rightX + b * bottomY + cz < 0;

    UWORD intersections = 0;

    if (topLeft != bottomLeft)
        intersections |= LEFT;
    if (topRight != bottomRight)
        intersections |= RIGHT;
    if (topLeft != topRight)
        intersections |= TOP;
    if (bottomLeft != bottomRight)
        intersections |= BOTTOM;

    if (!intersections) {
        BlitterFill(topLeft);
        return;
    }

    Point2D upperPoint, lowerPoint;
    BOOL reverse;
    BOOL fci;
    Kludge kludge = { .required = FALSE };

    switch (intersections) {
        WORD x0, x1, y0, y1;

        case LEFT | RIGHT:
            y0 = topY + (cz - a * rightX) / b;
            y1 = topY + (cz + a * rightX) / b;

            if (y0 > y1) {
                upperPoint = (Point2D) {{ DISPLAY_WIDTH - 1, y1 }};
                lowerPoint = (Point2D) {{ 0, y0 }};

                if (topLeft) {
                    reverse = FALSE;
                    fci = FALSE;
                } else {
                    reverse = TRUE;
                    fci = TRUE;
                }

                kludge = (Kludge) { TRUE, 0, y1 - 1 };
            } else {
                upperPoint = (Point2D) {{ 0, y0 }};
                lowerPoint = (Point2D) {{ DISPLAY_WIDTH - 1, y1 }};

                if (topRight) {
                    reverse = FALSE;
                    fci = TRUE;
                } else {
                    reverse = TRUE;
                    fci = FALSE;
                }

                kludge = (Kludge) { TRUE, y1 + 1, DISPLAY_HEIGHT - 1 };
            }
            break;
        case LEFT | TOP:
            upperPoint = (Point2D) {{ rightX - (cz + b * topY) / a, 0 }};
            lowerPoint = (Point2D) {{ 0, topY + (cz - a * rightX) / b }};

            if (bottomRight) {
                reverse = TRUE;
                fci = TRUE;
            } else {
                reverse = FALSE;
                fci = FALSE;
            }
            break;
        case LEFT | BOTTOM:
            upperPoint = (Point2D) {{ 0, topY + (cz - a * rightX) / b }};
            lowerPoint = (Point2D) {{ rightX - (cz - b * topY) / a, displayHeight - 1 }};

            if (topRight) {
                reverse = FALSE;
                fci = TRUE;
            } else {
                reverse = TRUE;
                fci = FALSE;
            }
            break;
        case RIGHT | TOP:
            y1 = topY + (cz + a * rightX) / b;

            upperPoint = (Point2D) {{ rightX - (cz + b * topY) / a, 0 }};
            lowerPoint = (Point2D) {{ DISPLAY_WIDTH - 1, y1 }};

            if (bottomLeft) {
                reverse = TRUE;
                fci = FALSE;
            } else {
                reverse = FALSE;
                fci = TRUE;
            }
            kludge = (Kludge) { TRUE, y1 + 1, displayHeight - 1 };
            break;
        case RIGHT | BOTTOM:
            y1 = topY + (cz + a * rightX) / b;

            upperPoint = (Point2D) {{ DISPLAY_WIDTH - 1, y1 }};
            lowerPoint = (Point2D) {{ rightX - (cz - b * topY) / a, displayHeight - 1 }};

            if (topLeft) {
                reverse = FALSE;
                fci = FALSE;
            } else {
                reverse = TRUE;
                fci = TRUE;
            }
            kludge = (Kludge) { TRUE, 0, y1 - 1 };
            break;
        case TOP | BOTTOM:
            x0 = rightX - (cz + b * topY) / a;
            x1 = rightX - (cz - b * topY) / a;

            upperPoint = (Point2D) {{ x0, 0 }};
            lowerPoint = (Point2D) {{ x1, displayHeight - 1 }};

            if (x0 > x1) {
                if (topLeft) {
                    reverse = FALSE;
                    fci = FALSE;
                } else {
                    reverse = TRUE;
                    fci = TRUE;
                }
            } else {
                if (bottomLeft) {
                    reverse = TRUE;
                    fci = FALSE;
                } else {
                    reverse = FALSE;
                    fci = TRUE;
                }
            }
            break;
        default:
            return; // should never happen
    }

    Line2D line = reverse ? (Line2D) {{ lowerPoint, upperPoint }} : (Line2D) {{ upperPoint, lowerPoint }};

    BlitterLine(line, TRUE);
    if (kludge.required)
        DoKludgeLine(kludge.start, kludge.end, 0x0001);

    BlitterFill(fci);
    
    BlitterLine(line, FALSE);
    if (kludge.required) {
        DoKludgeLine(kludge.start, kludge.end, 0x0000);
        if (fci)
            RemoveKludgeLine(kludge.start, kludge.end);
    }
}

Last edited by deimos; 21 November 2021 at 11:30.
deimos is offline  
Old 20 December 2019, 15:22   #17
a/b
Registered User
 
Join Date: Jun 2016
Location: europe
Posts: 1,039
Code:
/*if (topLeft) {
                    reverse = FALSE;
                    fci = FALSE;
                } else {
                    reverse = TRUE;
                    fci = TRUE;
                }*/
fci = reverse = !topleft;

/*                if (topRight) {
                    reverse = FALSE;
                    fci = TRUE;
                } else {
                    reverse = TRUE;
                    fci = FALSE;
                }*/
reverse = !(fci = topright);

/*            if (bottomRight) {
                reverse = TRUE;
                fci = TRUE;
            } else {
                reverse = FALSE;
                fci = FALSE;
            }*/
fci = reverse = bottomRight;

etc...
Yeah, it's the same code, but 8*6 lines shorter. It's 'easier' to map directly to Scc in asm (I'm sure the produced code is the same, but it's about the idea/hint to give to compiler how to optimize w/o using branches).
And I don't find it any harder to understand, but that's subjective.
a/b is offline  
Old 20 December 2019, 15:38   #18
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Quote:
Originally Posted by a/b View Post
Code:
...
fci = reverse = !topleft;
etc...
Yeah, it's the same code, but 8*6 lines shorter. It's 'easier' to map directly to Scc in asm (I'm sure the produced code is the same, but it's about the idea/hint to give to compiler how to optimize w/o using branches).
And I don't find it any harder to understand, but that's subjective.
Thank you, I've gone and made that change, but I've kept it as two assignment lines for now as I want to keep the order of the two assignments consistent while I'm still testing.

Edit:

I've also changed the switch back to a nested if statement, as I wasn't 100% sure that it was impossible for the horizon to run down an edge, ending up intersecting 3 edges. This way I can check opposing edges first.

Code:
void ArtificialHorizon_Draw(const Camera * camera) {
    BlitterClear();

    LONG a = ((Entity *) camera)->transformation.rotation.value[0][1];
    LONG b = ((Entity *) camera)->transformation.rotation.value[1][1];

    LONG cz = ((Entity *) camera)->transformation.rotation.value[2][1] << 4; // 4, decided experimentally

    LONG leftX = -WIDTH / 2;
    LONG rightX = WIDTH / 2;
    LONG topY = HEIGHT / 2;
    LONG bottomY = -HEIGHT / 2;

    BOOL topLeft = a * leftX + b * topY + cz < 0;
    BOOL topRight = a * rightX + b * topY + cz < 0;
    BOOL bottomLeft = a * leftX + b * bottomY + cz < 0;
    BOOL bottomRight = a * rightX + b * bottomY + cz < 0;

    Point2D upperPoint, lowerPoint;
    BOOL reverse;
    BOOL fci;
    Kludge kludge;

    if (topLeft != bottomLeft && topRight != bottomRight) {
        WORD y0 = topY + (cz - a * rightX) / b;
        WORD y1 = topY + (cz + a * rightX) / b;

        if (y0 > y1) {
            upperPoint = (Point2D) {{ WIDTH - 1, y1 }};
            lowerPoint = (Point2D) {{ 0, y0 }};

            reverse = !topLeft;
            fci = !topLeft;
            kludge = (Kludge) { TRUE, 0, y1 - 1 };
        } else {
            upperPoint = (Point2D) {{ 0, y0 }};
            lowerPoint = (Point2D) {{ WIDTH - 1, y1 }};

            reverse = !topRight;
            fci = topRight;
            kludge = (Kludge) { TRUE, y1 + 1, HEIGHT - 1 };
        }
    } else if (topLeft != topRight && bottomLeft != bottomRight) {
        WORD x0 = rightX - (cz + b * topY) / a;
        WORD x1 = rightX - (cz - b * topY) / a;

        upperPoint = (Point2D) {{ x0, 0 }};
        lowerPoint = (Point2D) {{ x1, HEIGHT - 1 }};

        if (x0 > x1) {
            reverse = !topLeft;
            fci = !topLeft;
            kludge = (Kludge) { FALSE };
        } else {
            reverse = bottomLeft;
            fci = !bottomLeft;
            kludge = (Kludge) { FALSE };
        }
    } else if (topLeft != bottomLeft) {
        if (topLeft != topRight) {
            upperPoint = (Point2D) {{ rightX - (cz + b * topY) / a, 0 }};
            lowerPoint = (Point2D) {{ 0, topY + (cz - a * rightX) / b }};

            reverse = bottomRight;
            fci = bottomRight;
            kludge = (Kludge) { FALSE };
        } else /* bottomLeft != bottomRight */ {
            upperPoint = (Point2D) {{ 0, topY + (cz - a * rightX) / b }};
            lowerPoint = (Point2D) {{ rightX - (cz - b * topY) / a, HEIGHT - 1 }};

            reverse = !topRight;
            fci = topRight;
            kludge = (Kludge) { FALSE };
        }
    } else if (topRight != bottomRight) {
        if (topLeft != topRight) {
            WORD y1 = topY + (cz + a * rightX) / b;

            upperPoint = (Point2D) {{ rightX - (cz + b * topY) / a, 0 }};
            lowerPoint = (Point2D) {{ WIDTH - 1, y1 }};

            reverse = bottomLeft;
            fci = !bottomLeft;
            kludge = (Kludge) { TRUE, y1 + 1, HEIGHT - 1 };
        } else /* bottomLeft != bottomRight */ {
            WORD y1 = topY + (cz + a * rightX) / b;

            upperPoint = (Point2D) {{ WIDTH - 1, y1 }};
            lowerPoint = (Point2D) {{ rightX - (cz - b * topY) / a, HEIGHT - 1 }};

            reverse = !topLeft;
            fci = !topLeft;
            kludge = (Kludge) { TRUE, 0, y1 - 1 };
        }
    } else {
        BlitterFill(topLeft);
        BlitterCopy();
        return;
    }

    Line2D line = reverse ? (Line2D) {{ lowerPoint, upperPoint }} : (Line2D) {{ upperPoint, lowerPoint }};

    KPrintF("Line (%ld, %ld) - (%ld, %ld)\n", line.value[0].value[X], line.value[0].value[Y], line.value[1].value[X], line.value[1].value[Y]);

    BlitterLine(line, TRUE);
    if (kludge.required)
        DoKludgeLine(kludge.start, kludge.end, 0x0001);

    BlitterFill(fci);
    
    BlitterLine(line, FALSE);
    if (kludge.required) {
        DoKludgeLine(kludge.start, kludge.end, 0x0000);
    }

    BlitterWhiteLine(line);

    BlitterCopy();
}

Last edited by deimos; 20 December 2019 at 16:49.
deimos is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Blitter fill, nothing happens? deimos Coders. General 23 15 October 2019 14:41
Blitter Vertical Fill 71M Coders. Asm / Hardware 34 16 November 2017 22:31
Blitter fill problem mekhall Coders. Asm / Hardware 7 20 June 2016 00:04
Blitter fill timing leonard Coders. Asm / Hardware 42 01 September 2014 11:00
Clipping line for blitter fill leonard Coders. Asm / Hardware 12 27 April 2013 12:03

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 23:25.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.10446 seconds with 15 queries