Page 4 of 5

Re: Magnetic Scrolls Interpreter - Christmas Edition

Posted: Tue May 10, 2022 11:54 am
by pjw
mk79 wrote:
pjw wrote:Spectacular! Any chance of you sharing your "proper on-the-fly Floyd-Steinberg dithering for MODE 8 graphics"?
You mean, like in source code shared on GitHub or something like that? :-P It's in ql_c function RGB8ToQLiFS ;-)
Yeah, I mean something like that :? The binary might be more intelligible to the like of me, so we still have to see.

Re: Magnetic Scrolls Interpreter - Christmas Edition

Posted: Tue May 10, 2022 12:26 pm
by tofro
Floyd-Steinberg is actually easy to understand - It will be useful if you try to display a higher-quality picture on a lower-quality (in terms of colour depth) display.

It starts by comparing what it wants to display with what it's capable to display. In the code, it scales down R3G3B3 Amiga (00000RRR0GGG0BBB) pictures to R1G1B1 (number == bit depth/colour) QL pictures - The original has 7 shades of each base colour, the QL only one (on or off). Let's assume the original pixel has "not quite full" red (0000010000000000 == 100R). The QL can only display "full red" - So, when we display a "full red" (111b) pixel for this one on the QL, we have accumulated 011b "too much red". This is compensated by deducting this "too much red" from neighboring pixels. (That also works the other way round, when we display "not enough" of a colour because of rounding down at 011b). The "too much" or "not enough" of a base colour is distributed in 1/16 of the difference to neighbours: 7/16 of the difference goes to the pixel to the right, 1/16 to the pixel one down and one right, 5/16 goes to the pixel below us, and 3/16to the one diagonally left and down (in the code, the division by 16 is delayed to long after the final sum of the applied differences is calculated to keep rounding errors small - we're doing integer arithmetic only). This is done for all 3 base colour components (red, green, blue) separately - Basically a "wave of colour differences" runs from the top left to bottom right and evens out the picture.

The following code converts one Amiga pixel into one QL pixel and sets the correction arrays (oldErrors and newErrors). Note these arrays (even if they "look" local) are static and survive until the next (and all following) function call. So, while we run horizontally through the line, we collect an array of colour correction values for the next line in the nextLinCorr array - which will be applied when we run through the next line.

Code: Select all

unsigned short RGB8ToQLiFS(unsigned int RGB8, int x, int y) {
    char r, b, g, newR, newG, newB;
    short rCorr, bCorr, gCorr;
    int newCol;

    static colourCorr nextLinCorr [259], thisLinCorr [259];
    //static colourCorr nextPixCorr;
    static colourCorr *oldErrors;
    static colourCorr *newErrors;

    if ((x > 250) || (x < 0)) return 0;
    if ((y > 250) || (y < 0)) return 0;

    // Initialize if we start a new picture
    if ((x == 0) && (y == 0)) {
        memset (nextLinCorr, 0, sizeof (nextLinCorr));
        memset (thisLinCorr, 0, sizeof (thisLinCorr));
        oldErrors = &(nextLinCorr [1]); // Catches out of bounds at start and end of a line
        newErrors = &(thisLinCorr [1]);
    } else if (x == 0) // Initialize if we start a new line (alternate the two arrays)
    {
        colourCorr *tmp = oldErrors;
        oldErrors = newErrors;
        newErrors = tmp;
        memset(newErrors - sizeof (colourCorr), 0, sizeof(nextLinCorr)); // clear new
        //memset(&nextPixCorr, 0, sizeof (colourCorr));
    }

    // Convert color parts to 0-7
    r = (((RGB8 & red_mask)) >> red_shift);
    g = (((RGB8 & green_mask)) >> green_shift);
    b = (RGB8 & blue_mask);

    // Add the correction values
    r += (oldErrors [x + 1].RCorr / 16);
    g += (oldErrors [x + 1].GCorr / 16);
    b += (oldErrors [x + 1].BCorr / 16);

    // Now find the colour errors (in original colour space) that occur when we map the colour values
    newR = (r > 3) ? 7 : 0; 
    newG = (g > 3) ? 7 : 0; 
    newB = (b > 3) ? 7 : 0; 

    rCorr = r - newR; 
    gCorr = g - newG;
    bCorr = b - newB;

    //printf ()

    // And apply the correction Values to the correction array
    // (note correction array is shifted one to the right!)
    oldErrors [x + 2].RCorr += 7 * rCorr;
    newErrors [x + 2].RCorr += 1 * rCorr;
    newErrors [x + 1].RCorr += 5 * rCorr;
    newErrors [x + 0].RCorr += 3 * rCorr;
    oldErrors [x + 2].GCorr += 7 * gCorr;
    newErrors [x + 2].GCorr += 1 * gCorr;
    newErrors [x + 1].GCorr += 5 * gCorr;
    newErrors [x + 0].GCorr += 3 * gCorr;
    oldErrors [x + 2].BCorr += 7 * bCorr;
    newErrors [x + 2].BCorr += 1 * bCorr;
    newErrors [x + 1].BCorr += 5 * bCorr;
    newErrors [x + 0].BCorr += 3 * bCorr;

    // simply fumble the three bits into one number 0-7
    return (((newB != 0)) | ((newR != 0) << 1) | ((newG != 0) << 2));
}
Normally, you would simply apply the correction values for the "next right" and "next row down" pixels back to the original picture - The code above uses a two separate arrays that are alternated between rows for the correction values, because the original picture is read-only, which makes the code a bit harder to understand.

Re: Magnetic Scrolls Interpreter - Christmas Edition

Posted: Tue May 10, 2022 1:47 pm
by Silvester
pjw wrote: :? The binary might be more intelligible to the like of me
Photon also used Floyd Steinberg 7/3/5/1 distribution : http://www.dilwyn.me.uk/graphics/photonsource.zip see process_asm (line 112 onwards).

BTW tofro, are the original raw images available? I had a quick search but never found them.

Re: Magnetic Scrolls Interpreter - Christmas Edition

Posted: Tue May 10, 2022 2:04 pm
by tofro
Silvester wrote: BTW tofro, are the original raw images available? I had a quick search but never found them.
Well, they're packed (rather: concatenated with a small header) in the .gfx files. The format of those is (somewhat loosely) described in the "tech_txt" file on GitHub. The truth is (as always) in the code.

Re: Magnetic Scrolls Interpreter - Christmas Edition

Posted: Tue May 10, 2022 2:09 pm
by Silvester
tofro wrote:Well, they're packed (rather: concatenated with a small header) in the .gfx files. The format of those is (somewhat loosely) described in the "tech_txt" file on GitHub. The truth is (as always) in the code.
Ah, I'd hoped that wasn't the case, thought the original images may have also been available somewhere as PNG/JPG :)

Re: Magnetic Scrolls Interpreter - Christmas Edition

Posted: Tue May 10, 2022 2:13 pm
by XorA
tofro wrote:I finally came around to
  1. Publish the source code on Github
  2. Fix some nasty bugs
  3. Implement proper on-the-fly Floyd-Steinberg dithering for MODE 8 graphics - looks much nicer now on a real QL. (activate with "-f")
PawnGuru.pngPawnBridge.png

(I'm pretty sure I meant "mid January 2022" in my previous post. Thus, I'm only 4 months late...)
That looks amazing! Almost like the QL was designed for games :-D

Re: Magnetic Scrolls Interpreter - Christmas Edition

Posted: Tue May 10, 2022 2:31 pm
by tofro
Silvester wrote:
tofro wrote:Well, they're packed (rather: concatenated with a small header) in the .gfx files. The format of those is (somewhat loosely) described in the "tech_txt" file on GitHub. The truth is (as always) in the code.
Ah, I'd hoped that wasn't the case, thought the original images may have also been available somewhere as PNG/JPG :)
That gives you a very good reason to completely play through all the games (in high-colour, on QPC) and make some screenshots ;)

Re: Magnetic Scrolls Interpreter - Christmas Edition

Posted: Tue May 10, 2022 3:18 pm
by pjw
tofro wrote:Floyd-Steinberg is actually easy to understand - It will be useful if you try to display a higher-quality picture on a lower-quality (in terms of colour depth) display.
<>
Thanks for that excellent exposé, tofro. I think I got the gist of it.

I'll put it by for later. I may make use of it some day.

Re: Magnetic Scrolls Interpreter - Christmas Edition

Posted: Tue May 10, 2022 3:19 pm
by pjw
Silvester wrote:
pjw wrote: :? The binary might be more intelligible to the like of me
Photon also used Floyd Steinberg 7/3/5/1 distribution : http://www.dilwyn.me.uk/graphics/photonsource.zip see process_asm (line 112 onwards).<>
Got it. Thanks for the tip!

Re: Magnetic Scrolls Interpreter - Christmas Edition

Posted: Tue May 10, 2022 4:05 pm
by Sparrowhawk
Any chance you could add the release zips to the github Releases section of the repo's pages? Saves lazy people like me having to trawl through forum posts to find the latest ;)

And... fabulous work. Thank you.