adamlwgriffiths / qbasic-fractal

Mandelbrot in QBasic
2 stars 2 forks source link

Create photo of project running on hardware #5

Closed adamlwgriffiths closed 3 years ago

adamlwgriffiths commented 3 years ago

@lilithebowman Would you be able to add a photo of this running on target hardware?

I'm also curious if a CRT will render it better, if you have one lying around. The CGA format was created for CRTs and LCD panels don't render them very well. https://www.youtube.com/watch?v=niKblgZupOc

Although I'm not doing any colour tricks, the colours themselves may look better on CRT anyway.

Falling back to LCD is fine, MVP is just seeing this on actual hardware =)

adamlwgriffiths commented 3 years ago

So I have a feeling, despite selecting from 255 colours, we're only getting 16. It's hard to tell with the https://youtu.be/niKblgZupOc?t=129

image

So the colour selection might need some tweaking to look a bit better.

I also suspect the colours variable on line 9 might need to be 255. But that's not the real solution if we're only geting 16 colours anyway.

Looking at the video, we run this in 320x200, which should mean we get 4 colours (https://youtu.be/niKblgZupOc?t=210) But I'm seeing more than 4. To get all 16 we should be @ 160x100 (https://youtu.be/niKblgZupOc?t=243). Perhaps we're in EGA?

Video also confirms you don't get the composite video interpolation without manually alternating the pixels.

adamlwgriffiths commented 3 years ago

Ok, derp. Answer is in the code

SCREEN 13 has 256 color attributes, black background. 256K possible color hues. Text is 25 by 40. Graphics is 320 by 200.

Still, we're definitely not using the colour space well.

lilithebowman commented 3 years ago

Yeah SCREEN 13 is one of the most popular VGA modes behind 320x240. I don't know if there's a SCREEN command for that one.

lilithebowman commented 3 years ago

Also I only have a single board 8088 (like and XT) computer that I built by hand from the bare parts, and a Packard Smell P166MMX that I found in the trash. I haven't owned a CRT since the 2000s.

lilithebowman commented 3 years ago

The default VGA pallette is a weird organization of colours.

It starts out with the same ones as CGA and EGA in the first 16, and then beyond that it does a bunch of gradients of R/G/B in various mixtures but all cut up in weird ways. So if you do anything like a mandelbrot set it looks like randomness. Almost none of the colours are adjacent.

image

lilithebowman commented 3 years ago

I guess it's not all as weird as I recall but it's still kind-of weird.

adamlwgriffiths commented 3 years ago

Hmm, so if you were to offset the colours by the first 32 (E/CGA + grey scale), then possibly invert it, it might look ok?

lilithebowman commented 3 years ago

Yeah or just set your own pallette with more of a gradient orientation. :D

adamlwgriffiths commented 3 years ago

Hmm good suggestion. What are the palette creation calls?

If I get time later I'll look at getting QBasic on my system again and play around. I don't want to just dump work on you, this is entirely speculative/voluntary =P

lilithebowman commented 3 years ago

PALETTE <int index>, <int colour>

something like that... 1 sec

https://www.qbasic.net/en/reference/qb11/Statement/PALETTE.htm

AHA! It's actually

color = 65536 * BLUE + 256 * GREEN + RED
PALETTE 0, color

That example changes the first colour, I believe. BLUE, GREEN, and RED must be replaced with the individual channel colour. I think there are only 64 so 0-63?

You can also use an array to replace many colours at once, which would be the best method for colour cycling likely.

lilithebowman commented 3 years ago

http://www.petesqbsite.com/phpBB3/viewtopic.php?t=2533

adamlwgriffiths commented 3 years ago

64 should be plenty. I think line 9 is still an off-by-one error, and should be 255. So don't carry that one through with the 64.

I left the render zoomed out as it's a pretty classic view of the set, but it may be better to zoom in on a different area to show off the colours. The problem is you can start increasing the amount of time taken if you view closer to the middle of the set.

lilithebowman commented 3 years ago

There are some hacks you can do apparently to sacrifice accuracy by giving up on the values that go off into infinity sooner. Or doing so in a more clever way.

lilithebowman commented 3 years ago

With only 64 shades of each colour you can probably by mixing them all into gradients use up all 256 colours and make some pretty looking displays.

Best part is, you can do this code in the utility that loads the screenshot after the render too! Just make it another function to cycle the palette.

adamlwgriffiths commented 3 years ago

True, so if the colour values are simply the recursion depth (as they already are), you can then modify the palette however you want and know which values you're replacing. Nice.

lilithebowman commented 3 years ago

Yeah that's how it works.

lilithebowman commented 3 years ago

PXL_20210108_034243411 The micro8088 loading the screenshot (looks the same, so that part works)

lilithebowman commented 3 years ago

image So I was able to modify the PALETTE

lilithebowman commented 3 years ago

image I was trying to use an array to assign them all at once but that wasn't working. I figured an array would be a quick way to animate it. But just setting the values individually seems pretty fast on DOSBOX at max. Probably really slow on the XT.

lilithebowman commented 3 years ago
SUB InitPalette
        DIM blue AS LONG
        DIM green AS LONG
        DIM red AS LONG
        DIM pcolour AS LONG
        FOR i = 0 TO 63
                blue = i
                green = i / 2
                red = i / 3
                pcolour = blue * 65536 + green * 256 + red
                PALETTE i, pcolour
                PALETTE i + 128, pcolour
        NEXT i
        FOR i = 63 TO 0 STEP -1
                blue = i
                green = i / 2
                red = i / 3
                pcolour = blue * 65536 + green * 256 + red
                PALETTE i + 64, pcolour
                PALETTE i + 192, pcolour
        NEXT i

END SUB

This makes a really pretty blueish palette! image

lilithebowman commented 3 years ago

I did it! I was able to use arrays to set palettes and it's VERY fast on this DOSBOX at max speed but the delay might want to be removed on slower computers... OR a time based delay added.

https://user-images.githubusercontent.com/1637212/104113604-5604ee80-52c9-11eb-9336-ca7257b11b6e.mp4

SHOWRAW.BAS - the program which loads the SCREEN.RAW file and cycles 4 palettes

DECLARE SUB LoadRawScreen (filename AS STRING, w AS INTEGER, h AS INTEGER)
DECLARE SUB CyclePalette ()
SCREEN 13
CLS
LINE (0, 0)-(320, 200), 15, BF
CALL LoadRawScreen("C:\SCREEN.RAW", 320, 200)

CALL CyclePalette

SUB CyclePalette
        DIM blue AS LONG
        DIM green AS LONG
        DIM red AS LONG
        DIM pcolour AS LONG
        DIM pvalues1(255) AS LONG
        DIM pvalues2(255) AS LONG
        DIM pvalues3(255) AS LONG
        DIM pvalues4(255) AS LONG
        FOR i = 0 TO 63
                blue = i
                green = i / 2
                red = i / 3
                pcolour = blue * 65536 + green * 256 + red
                pvalues1(i) = pcolour
                pvalues1(i + 128) = pcolour
                blue = i / 2
                green = i / 3
                red = i
                pcolour = blue * 65536 + green * 256 + red
                pvalues2(i) = pcolour
                pvalues2(i + 128) = pcolour
                blue = i / 3
                green = i
                red = i / 2
                pcolour = blue * 65536 + green * 256 + red
                pvalues3(i) = pcolour
                pvalues3(i + 128) = pcolour
                blue = i
                green = i
                red = i
                pcolour = blue * 65536 + green * 256 + red
                pvalues4(i) = pcolour
                pvalues4(i + 128) = pcolour
        NEXT i
        FOR i = 63 TO 0 STEP -1
                blue = i
                green = i / 2
                red = i / 3
                pcolour = blue * 65536 + green * 256 + red
                pvalues1(i + 64) = pcolour
                pvalues1(i + 192) = pcolour
                blue = i / 2
                green = i / 3
                red = i
                pcolour = blue * 65536 + green * 256 + red
                pvalues2(i + 64) = pcolour
                pvalues2(i + 192) = pcolour
                blue = i / 3
                green = i
                red = i / 2
                pcolour = blue * 65536 + green * 256 + red
                pvalues3(i + 64) = pcolour
                pvalues3(i + 192) = pcolour
                blue = i
                green = i
                red = i
                pcolour = blue * 65536 + green * 256 + red
                pvalues4(i + 64) = pcolour
                pvalues4(i + 192) = pcolour

        NEXT i

        index = 0
        DO WHILE INKEY$ = ""
                IF index = 0 THEN
                        PALETTE USING pvalues4
                ELSEIF index = 1 THEN
                        PALETTE USING pvalues3
                ELSEIF index = 2 THEN
                        PALETTE USING pvalues2
                ELSE
                        PALETTE USING pvalues1
                END IF

                index = index + 1
                FOR i = 0 TO 10000
                NEXT i

                IF index > 3 THEN index = 0
        LOOP
END SUB

SUB LoadRawScreen (filename AS STRING, w AS INTEGER, h AS INTEGER)

        OPEN filename FOR BINARY AS #1
        DIM colour AS INTEGER

        FOR y = 0 TO h - 1

                FOR x = 0 TO w - 1

                        position = (x + (y * w))

                        GET #1, position + 1, colour

                        PSET (x, y), colour

                NEXT x

        NEXT y

        CLOSE #1

END SUB
adamlwgriffiths commented 3 years ago

Wow, very nice! It looks like it animates too (haven't gotten around to loading qbasic)

lilithebowman commented 3 years ago

Apparently with the version of QBASIC they packed with DOS 6.22 Supplemental disks, you only get 160kb of RAM to use (and no compilation of executables). I wonder how close to 160k this program gets? It doesn't seem to have any good profiling tools. Just a simple message saying you ran out of space if you make a big enough array. I tried to make the screenshot an array and it takes 64k on disk but somehow is too big.

lilithebowman commented 3 years ago

https://twitter.com/lilithebowman/status/1348477440373501952?s=20

On an XT class hardware it looks even cooler

adamlwgriffiths commented 3 years ago

Ok, I made a new branch and converted some of the video you took into a gif for the README. I was only able to get 30s worth with the online convert I used.

The palette scrolling looks absolutely epic.

I think we should preserve the simplicity of the original version though, and put the palette scrolling version a different file. That way people can just view the algorithm on it's own without having to delve through the other logic. Feel free to commit directly to that PR and we'll merge when you're happy.