Jump to content
Nop90

Experimenting with colors changing every HBL

Recommended Posts

Today wanted to play a little with the HBL interrupt to display images with more than 16 fixed colors, so wrote  a little script (using imagemagick) that from a generic 160x102 png first downscales the colors to 256, than  creates a set of images (one for every line), everyone with only 16 colors. The 102 images are rendered on the screen and the corresponding platettes are changed at every HBL.

 

Nothing new with this way to show more than 16 colors, only I'm not happy if I don't code things by myself.

 

I was especting to have to apply some postprocessing to optimize the palettes, but surprisingly the images are very good only with the authomatic processing.

 

Here are the first three image I converted.

 

Attached there is the source code too. It's only a fast POC so forgive me the bad coding. I know that I don't need to use tgi to draw the image since I have to disable it to change colors and I also know that I don't need to use all that memory to setup data in memory but it's better to create offline two big arrays (one for image daa  and one for the palettes), but I'm lazy 😅

 

What about it? I'm going to optimize this tool and use it to show nice colored splash screens in my next games.

 

bigtree__colorpic.lnx nebula_colorpic.lnx skyline_colorpic.lnx hicol.zip

  • Like 1

Share this post


Link to post
Share on other sites
Posted (edited)

will not work. if you use HBL interrupt you dont have the time to set the full palette.

you either have to poll the register or set up another timer which interrupts before the end of line and then poll the register.

 

Edited by sage

Share this post


Link to post
Share on other sites

I described here how I did it for assembloids:

 

The Bastion demo also features it including a scroller above the image.

Share this post


Link to post
Share on other sites

I see, it only works on emulator, but not on real lynx, anyway it's a starting point for my experimenting.

 

I'll try reducing the colors per line and optimixing the palette leaving some fixed colors.

 

Do you yow how many clocks last the HBL for the 3 refresh rates?

Share this post


Link to post
Share on other sites

At 50hz my lynx 2 seems can do the job (try the attached rom), at 60Hz i can write only 29 bytes of the palette out of 32: at 30 bytes starts the flickering.

 

So seems it's possible. Could soemone try it on a upgraded LCD? I have only unmoded lynx for the moment.

skylyne_50hz.lnx

Share this post


Link to post
Share on other sites

You can do it at 60Hz as well. I think HBL is not best suited since you lose the time you would otherwise have in Vblank. But it should work as well in HBL 🙂

The tree is nice :) In general you'd want motives with vertical gradients to show off the colors.

Share this post


Link to post
Share on other sites
1 hour ago, Nop90 said:

I see, it only works on emulator, but not on real lynx, anyway it's a starting point for my experimenting.

I'll try reducing the colors per line and optimixing the palette leaving some fixed colors.

I think i left some code in the public version here. But I was not satisfied because i left too many relicts in the picture.

 

http://lynxdev.atari.org/BmpConvert.exe

Share this post


Link to post
Share on other sites
17 minutes ago, enthusi said:

You can do it at 60Hz as well. I think HBL is not best suited since you lose the time you would otherwise have in Vblank. But it should work as well in HBL 🙂

The tree is nice :) In general you'd want motives with vertical gradients to show off the colors.

ONe question: how much is the music distorted if you use this?

Share this post


Link to post
Share on other sites

You can check in Bastion 🙂

In fact I didn't use 102 lines when music is running.

Share this post


Link to post
Share on other sites

How many clock cycles is the horizontal blank (if any)?

 

And the is the Vblank only the first 3 horizontal lines not displayed on the LCD?

Edited by Nop90

Share this post


Link to post
Share on other sites

@Nop90

I've tried to actually measure it by placing varying number of NOPs in the HBI routine.

Please correct me if I'm wrong.

First of all CPU clocks are no good unit of measure when dealing with tracing the beam as one clock cycle can take 4 or 5 system clock ticks. The whole line with 60 Hz refresh rate takes 159 μs = 2544 ticks. According to my measurements it seems that the first color change visible on screen is after about 30 μs = 480 ticks. It's slightly more than 100 CPU cycles.

I'm attaching output of my test program. The white pattern is binary encoded VCOUNT_COUNT. Green pattern is a sequence of  sta GREEN0 / stz GREEN0 delayed for about ( 26 + 80 + VCOUNT_COUNT ) * 4 + 11 * 5 system ticks including interrupt (+-4 ticks ).

 

VBlank is for 3 lines, but keep in mind that two first visible lines are for some reason unstable just as if the HBI launched in various "moments" with few pixels of variance.

 

c0000.png

Edited by laoo

Share this post


Link to post
Share on other sites

thank you @laoo you helped me a lot.

 

I was giving up in the project of displaying a general (i.e. not optimized at design time) 256 colors image on the screen of a real lynx. My code was working on the emulator but on real lynx I had problems in the first third of the screen.

 

With your timing as reference I reorganized my code and now it works fine on real lynx.

 

Here is an image (with attached the lnx rom if someone want test himself on a real lynx) of a nice splash screen that @marss made for 4ttude.

 

4ttude.png.dd32e3cda7a1bd02aaa274ca82ca4f7d.png

 

I'm going to update the 4ttude rom with this tonight (I released a new version of 4ttude some hours ago, but without this splash sceen, because I was starting to think it was an impossible task to display it correctly).

image.lnx

  • Like 3

Share this post


Link to post
Share on other sites

Nice. I'm attaching a snapshot from McWill-modded VGA output of real hardware:

 

vlcsnap-2020-02-13-21h01m45s993.thumb.png.9e57d43a30980caf3b22e7aa1a5daa23.png

  • Like 2

Share this post


Link to post
Share on other sites

Nice. This mode has quite some potential in general!

From the gfx used in the Bastion demo:

 

test4_lynx.png

Edited by enthusi
  • Like 1

Share this post


Link to post
Share on other sites

For the moment I want to keep my code private, but if someone wants I can give enough details on how I accomplished this to make it easily replicable.

 

Obviusly the asm part can be decompiled from the rom, but there is a big part of automatic image preprocesssing done with perl scripts and the convert tool from imagemagick.

Share this post


Link to post
Share on other sites
2 hours ago, Cyprian_K said:

@Nop90 any details? change 16 colors every line?

yes, the idea is simple, but timing is critical.

 

I start from a 24 bit image, than at build time i call some perl scripts that uses the Imagemagick Convert tool to:

 - reduce the color to 256

 - create a bmp3 (paletted) image 160x1 px for every line of the image, reducung for each the colors to 16

 - read the data of the files of every single line line so to extract the pixel and palette data; and from this builds two data files, one is a standard unpacked lynx sprite, the other is an array  with the 102 palette datas + 3 dummy palette rows (all zeroes) for the VBLANK (to simplify the HBL handling).

 

Pixel and palettes data are reorganized so that colors are in (reversed ) oder of occurrence so that the first colors to be used are the first to be updated every scanline. The order is reversed because a loop using decrementig X register as a counter saves a CMP instuction every loop respect the case of X incrementing.

 

To update the palette the code:

 - sets X to 16

 - sets the G value of the color at X position in the X position of the G colors array

 - sets the RB value of the color at X position in the X position of the RB colors array

- decrements X

- if X is not 0, branches to the second point

- before exiting the HBL handler updates the addresses to the palette pointers (at points 2 and 3) adding 32 to the LSB ofthe two addresses and if carry is set incrementing the MSB.

 

That's all. After several tries, this code can display an image without flickering without the need to decide color utilization and order at designtime. Obviously such a general code produces some horizontal artifact, but the result isvery good.

 

I tryed usinf 15 or 14 colors instead of 16 with good results. The two unused colors can be used to add other effects (text scrollig) and maybe to same some computational time.

 

This is my next challenge.

  • Like 1

Share this post


Link to post
Share on other sites

The one crucial optimisation you are missing is to set the colors in order of appearance.
Then changing 16 colors is no problem at all.

Share this post


Link to post
Share on other sites
3 hours ago, enthusi said:

The one crucial optimisation you are missing is to set the colors in order of appearance.
Then changing 16 colors is no problem at all.

No, I'm not missing it.

 

4 hours ago, Nop90 said:

Pixel and palettes data are reorganized so that colors are in (reversed ) oder of occurrence so that the first colors to be used are the first to be updated every scanline

I know my English is not very good with complex sentences.  Sorry.

Edited by Nop90
  • Like 1

Share this post


Link to post
Share on other sites

Ah sorry, I misread that then. The Textscroller in Bastion uses 14 free colors and keeps 2 colors global :)

Share this post


Link to post
Share on other sites
1 hour ago, Cyprian_K said:

@Nop90 nice idea.

 

can you estimate how many cycles or % of scanline it takes on real hardware?

I don't know how may cycles last the scanline, but is a simple thing to estimate knowing the screen frequency is set to 50 Hz (the timer 0 frequency is in the Lynx programming manual).

 

The code execution time can be calclated from my code:

 

setpal:
hbl:  
	pha
	phx	
	lda INTSET
	and #TIMER0_INTERRUPT
	beq vbl 
	sta INTRST 
	ldx #15
ADR1:   lda GCOLMAP,x ; dummy address. It's dinamically set in intInit and updated by vbl and hbl
        sta GCOLMAP,x
ADR2:   lda RBCOLMAP,x ; dummy address. It's dinamically set in intInit and updated by vbl and hbl
        sta RBCOLMAP,x
        dex
        bpl ADR1

	clc	
	lda ADR1+1
	adc #32
	sta ADR1+1
	bcc incaddr2
	inc ADR1+2
	bra incaddr2 
incaddr2:
	clc	
	lda ADR2+1
	adc #32
	sta ADR2+1
	bcc done
	inc ADR2+2
	bra done 

Can my code be optimized to be faster? Let me know. 

Edited by Nop90

Share this post


Link to post
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.

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...