Forums

Sega Master System / Mark III / Game Gear
SG-1000 / SC-3000 / SF-7000 / OMV
Home - Forums - Games - Scans - Maps - Cheats - Credits
Music - Videos - Development - Hacks - Translations - Homebrew

View topic - When Changing Palette Colors Goes Wrong

Reply to topic
Author Message
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
When Changing Palette Colors Goes Wrong
Post Posted: Mon Sep 25, 2023 12:54 am
Hello again, folks!
I'm really getting back into stride with my project but I've come across a bizarre issue after assembling my latest code.

On paper, I should have the same blue background I've always had and only my text should be flickering between a main color and a secondary color, doing this for 16 frames before shifting up another shade of gray until the text is eventually white.
What actually happened when I loaded the ROM was a black background and my text going nuts with random colors, all while the game seems to be running at half speed. Below is a link to the code on github for those who wish to review all of the changes, but the main culprits I have my eye on for this are
-IntroStory_AnimateRow
-IntroStory_Frame
and
-DrawPalette

IntroStory_AnimateRow:
   ld a,$15 ;load dark gray as first intro color
   ld (intro_color),a ;store in RAM
   ld c,$00 ;C register acts as a frame counter
--:   ld (cur_pal+$04),a ;A register still has main color, so store it at text color index
-:   call IntroStory_Frame ;do a frame
   inc c ;and count another frame
   ld a,$0F ;check to see if we're on the 16th frame
   cp c
   jr nz,+ ;if not, alternate between main and sub color
   ld a,(intro_color) ;if we are on even 16th frame, brighten the main color
   ccf
   adc $15 ;by adding $15
   ld (intro_color),a ;and storing this new color
   cp $54 ;then check to see if we're done.
   jr nc,-- ;If we aren't done, then continue the loop, otherwise
   ret ;exit
+:   ld a,c
   rra ;move the low bit of the frame counter into carry to check if even or odd
   jr nc,- ;if even frame, use main color next frame
   ld a,(cur_pal+$04)
   scf
   sbc $15
   jr nz,++
   ld a,$20
++:   ld (cur_pal+$04),a
   jr -


IntroStory_Frame:
   call WaitForVBlank
   call DrawPalette
   call PSGFrame
   ret

and
DrawPalette:
   call PrepareBKGLoadPalette
   ld b,$0F
   jp DrawPalette_Norm

DrawPalette_Norm:
   ld hl,cur_pal
   ld c,VDPData
   otir


Hopefully someone with a keener eye than myself can spot what might be the cause of the slowdown and random colors flashing.

github link: https://github.com/Cereza64/Final-Fantasy-SMS

Brief note: While I was in the middle of typing this out, I realized that DrawPalette was actually overwriting my palette load from before, so for now I have a band-aid on the problem by just setting the first 4 cur_pal RAM addresses with blue...and come to think of it reloading the whole background palette every frame might be what's causing the slowdown too...I'll have to tweak that and see.
flashy colors.mp4 (4.4 MB)
Video I took of the problem. Beware flashing colors

  View user's profile Send private message
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
Quick Follow-Up
Post Posted: Mon Sep 25, 2023 1:04 am
DrawPalette WAS in fact causing the slowdown. It may be a routine from the original game that I might have to cut out due to system differences.

I have since edited my code to only change the text color index instead of rewriting all of the color indexes every frame (what a stupid thing to do lol)
  View user's profile Send private message
  • Joined: 06 Mar 2022
  • Posts: 533
  • Location: London, UK
Reply with quote
Post Posted: Mon Sep 25, 2023 2:02 am
Are you maybe missing some rets in your subroutines?
In particular in either DrawPalette or DrawPalette_Norm, but maybe in numerous other places?

Without a ret more code than you anticipated will execute, which might be why you are apparently running into timing issues with functions that should run very quickly.
  View user's profile Send private message Visit poster's website
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
Post Posted: Mon Sep 25, 2023 2:18 am
willbritton wrote
Are you maybe missing some rets in your subroutines?
In particular in either DrawPalette or DrawPalette_Norm, but maybe in numerous other places?

Without a ret more code than you anticipated will execute, which might be why you are apparently running into timing issues with functions that should run very quickly.


I'm not missing any rets in the code which would do this. The slow runtime was an issue with writing 16 palette indexes over and over again each frame, an issue I've since fixed.

However, I'm still trying to figure out why my colors seem to be random instead of

dark gray & blue -> light gray & dark gray -> light gray & white
Emulicious_2023-09-24_21-43-26.mp4 (9.23 MB)
Fixed the colors and run time speed, but still flashing random colors

  View user's profile Send private message
  • Joined: 06 Mar 2022
  • Posts: 533
  • Location: London, UK
Reply with quote
Post Posted: Mon Sep 25, 2023 2:43 am
CerezaSaturn64 wrote
I'm not missing any rets in the code which would do this.

So with the code that you have in github right now, how does execution proceed once the otir in DrawPalette_Norm has finished? It looks to me that it would just drop right through to whatever is next in memory, which may or may not be SetVDPAddress, depending on what the linker did.

CerezaSaturn64 wrote

The slow runtime was an issue with writing 16 palette indexes over and over again each frame, an issue I've since fixed.

You ought to be able to easily write 16 palette entries in vblank. If you really can't you must be super tight on timing anyway.

CerezaSaturn64 wrote

However, I'm still trying to figure out why my colors seem to be random instead of

dark gray & blue -> light gray & dark gray -> light gray & white

If there really is a problem with calling an unintended SetVDPAddress that could conceivably cause something like this. Sorry for the speculation, but
I'm traveling atm so can't try running myself for a few days at least. I'd step through with a debugger though to see what's causing the problem.
  View user's profile Send private message Visit poster's website
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
Post Posted: Mon Sep 25, 2023 2:53 am
willbritton wrote
So with the code that you have in github right now, how does execution proceed once the otir in DrawPalette_Norm has finished? It looks to me that it would just drop right through to whatever is next in memory, which may or may not be SetVDPAddress, depending on what the linker did.

You ought to be able to easily write 16 palette entries in vblank. If you really can't you must be super tight on timing anyway.

If there really is a problem with calling an unintended SetVDPAddress that could conceivably cause something like this. Sorry for the speculation, but
I'm traveling atm so can't try running myself for a few days at least. I'd step through with a debugger though to see what's causing the problem.


Good point.
I'll take a look tomorrow and see if a ret would fix DrawPalette_Norm, but right now my code is not using it. I'll definitely take a look under the hood while the code is running to see why im getting random colors. Thanks for the suggestions and safe travels!
  View user's profile Send private message
  • Joined: 04 Jul 2010
  • Posts: 532
  • Location: Angers, France
Reply with quote
Post Posted: Mon Sep 25, 2023 5:46 am
Few mistakes (only check few lines)

No ret in drawpalette (which is called)
= fall into setvdpaddress

Remove JP (no utility)

Push/pop af utility in vdp writing?

Before any optimisation/factorisation, better to duplicate the code, test it step by step with a debbuger then optimise and retest. even more if you're not sure of how things works.

  View user's profile Send private message
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
Post Posted: Mon Sep 25, 2023 10:13 pm
Good News!
You guys were absolutely right with missing a ret at the end of DrawPalette_Norm. I put that in and it worked perfectly (as far as that subroutine goes).

As for everything else, I've been going through my code with a fine-tooth comb and managed to get everything nearly perfect. The code starts, flickers through the colors in order and gets right to the last frame aaaaaaand...ends on gray instead of white. Running through the debugger, I've isolated the issue to it being my frame counter off by 1. The original game will show dark gray text on frame 1 while my current code shows dark gray text at frame 2. I'm not exactly sure what is causing this delay and I'm hoping someone with better eyes than me can see what might be causing this problem, as the frame counter being off by 1 is why the text stops animating at the wrong point.

I also updated my github with the latest version and I also update the changelog with each upload too so you can see what my current issues are.

Thank you guys for the helpful tips!
  View user's profile Send private message
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
Changing just one row of text?
Post Posted: Thu Sep 28, 2023 3:15 am
I'm curious if anyone knows how to make only one row of text fade into view instead of all rows of text at once.
The original NES version uses the 3 different palettes available to swap between an "invisible" palette, a "fading in" palette, and a "full white" palette. I remember Phantasy Star's intro also has text that fades in row by row instead of all at once, so I at least know that what I'm hoping for is possible. Any help with this is greatly appreciated
  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3590
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Thu Sep 28, 2023 10:11 am
you might use the sprites palette for the BG to have a 'fade-in' transition using the same charset

so basically you draw the text twice, using the two palettes

anything more than this would likely require two charsets - or to draw directly to tiles to create the transition on the fly
  View user's profile Send private message Visit poster's website
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 14564
  • Location: London
Reply with quote
Post Posted: Thu Sep 28, 2023 6:06 pm
You could use line interrupts with a single palette change to fade text in line by line. It’s tricky though. For a pure text intro, using two font sets is easier.
  View user's profile Send private message Visit poster's website
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
Post Posted: Thu Sep 28, 2023 6:25 pm
Maxim wrote
You could use line interrupts with a single palette change to fade text in line by line. It’s tricky though. For a pure text intro, using two font sets is easier.


Would it be possible to perhaps have every line start at a particular palette index and then have each row change into the next index over on the palette for it to start animating? Is that what you mean by line interrupts with single palette change?

I'm just not super sure multiple font sets is feasible with my current set up as id need 3 sets, two that wont be affected by the animating row (invisible and set at white) and then one more set for the animating row.
  View user's profile Send private message
  • Joined: 06 Mar 2022
  • Posts: 533
  • Location: London, UK
Reply with quote
Post Posted: Thu Sep 28, 2023 7:11 pm
CerezaSaturn64 wrote
I'm just not super sure multiple font sets is feasible with my current set up as id need 3 sets, two that wont be affected by the animating row (invisible and set at white) and then one more set for the animating row.

You wouldn't need "invisible" if you wrote to the tile map one row of text at a time. You need the timing to fade and hold rows of text in any case so might as well couple that to the writing each line of text to display.

sverx's suggestion of using the upper palette to quickly switch between fadable and fixed colours is how I'd approach it too, simple enough solution I reckon.
  View user's profile Send private message Visit poster's website
  • Joined: 06 Mar 2022
  • Posts: 533
  • Location: London, UK
Reply with quote
Post Posted: Fri Sep 29, 2023 3:44 pm
CerezaSaturn64 wrote
As for everything else, I've been going through my code with a fine-tooth comb and managed to get everything nearly perfect. The code starts, flickers through the colors in order and gets right to the last frame aaaaaaand...ends on gray instead of white. Running through the debugger, I've isolated the issue to it being my frame counter off by 1. The original game will show dark gray text on frame 1 while my current code shows dark gray text at frame 2. I'm not exactly sure what is causing this delay and I'm hoping someone with better eyes than me can see what might be causing this problem, as the frame counter being off by 1 is why the text stops animating at the wrong point.

P.S. did you ever figure out this out-by-one issue?

I'm jetlagged to s**t right now and looking for some non safety-critical tasks to keep my mind from imploding in on itself so if you hadn't figured it out yet I will take a look. I tried doing it by eyeball on my phone a few days ago but couldn't quite manage it, but now I'm back I have the tools to help properly.
  View user's profile Send private message Visit poster's website
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
Post Posted: Fri Sep 29, 2023 5:09 pm
willbritton wrote
CerezaSaturn64 wrote
As for everything else, I've been going through my code with a fine-tooth comb and managed to get everything nearly perfect. The code starts, flickers through the colors in order and gets right to the last frame aaaaaaand...ends on gray instead of white. Running through the debugger, I've isolated the issue to it being my frame counter off by 1. The original game will show dark gray text on frame 1 while my current code shows dark gray text at frame 2. I'm not exactly sure what is causing this delay and I'm hoping someone with better eyes than me can see what might be causing this problem, as the frame counter being off by 1 is why the text stops animating at the wrong point.

P.S. did you ever figure out this out-by-one issue?

I'm jetlagged to s**t right now and looking for some non safety-critical tasks to keep my mind from imploding in on itself so if you hadn't figured it out yet I will take a look. I tried doing it by eyeball on my phone a few days ago but couldn't quite manage it, but now I'm back I have the tools to help properly.


I did, and in fact I misidentified the issue. Turns out the only thing wrong was the fact that I did a jr on no carry set when i needed to jr on carry set. It just made it branch to the second color first instead of what I wanted.

I'm trying to figure out the other stuff now. I made a second font set but I'm having trouble loading it in after the first set for some reason. Should just be as simple as calling a similar routine again starting at where the last one left off copying to VRAM, right?
  View user's profile Send private message
  • Joined: 06 Mar 2022
  • Posts: 533
  • Location: London, UK
Reply with quote
Post Posted: Fri Sep 29, 2023 5:46 pm
CerezaSaturn64 wrote
I did, and in fact I misidentified the issue. Turns out the only thing wrong was the fact that I did a jr on no carry set when i needed to jr on carry set. It just made it branch to the second color first instead of what I wanted.

Nice one! And fwiw I constantly get turned around by checking the carry flag, it's one of those things I've still not managed to cement properly in my muscle memory so have to think very hard about it still!

CerezaSaturn64 wrote
Should just be as simple as calling a similar routine again starting at where the last one left off copying to VRAM, right?

Yes should be. At the moment you have a routine called `LoadFont` that once completed should leave the VDP pointer after the last tile copied, so doing another VDP copy operation should append more data after that point – assuming that's actually where you want the next tileset to go. If not, you need to call `SetVDPAddress` with a new starting location of course. You should be able to see the result in the tile viewer in Emulicious.

I was building up a few notes when I was trying to step through your routine before, but here I think I'd drip feed two things in particular:

1. I think you might be over-extracting routines in places. For instance you have a `PrepareLoadFont` which is actually just a set VDP address with the address hardcoded to $0000 and a `LoadFont` which is actually just a VDP copy with the source data hardcoded. You might be just as well to stick with using the already parameterised `SetVDPAddress` and `CopyToVDP` directly in your calling code. I think it would make it easier to read and also it would save some cycles.

2. Not super important, but while we're talking about your `SetVDPAddress` you might find that in many examples of others' code, setting the VDP address (or writing to the VDP control port) in particular is implemented as a fast reset vector, e.g. `rst $08`, etc. This is because it's used so frequently and often in moderately time critical situations and the `rst p` instructions are slightly quicker to execute than regular calls. I'd say it's also quite common to see set VDP address implemented as a macro alternatively. Take a look at SMSLib's CRT0 and you'll see that sverx has two reset vectors: one at $08 which copies HL to the VDP control port (just like your SetVDPAddress) and another at $18 which does the same for the data port. In his `rst $08` vector he clobbers the C register rather than pushing to the stack (for speed over safety) although if you didn't want to clobber A you could alternatively use ex af, af' which takes 4 t-states to execute as opposed to push af's 11 and pop af's 10.
  View user's profile Send private message Visit poster's website
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
Post Posted: Fri Sep 29, 2023 6:06 pm
willbritton wrote
CerezaSaturn64 wrote
I did, and in fact I misidentified the issue. Turns out the only thing wrong was the fact that I did a jr on no carry set when i needed to jr on carry set. It just made it branch to the second color first instead of what I wanted.

Nice one! And fwiw I constantly get turned around by checking the carry flag, it's one of those things I've still not managed to cement properly in my muscle memory so have to think very hard about it still!

CerezaSaturn64 wrote
Should just be as simple as calling a similar routine again starting at where the last one left off copying to VRAM, right?

Yes should be. At the moment you have a routine called `LoadFont` that once completed should leave the VDP pointer after the last tile copied, so doing another VDP copy operation should append more data after that point – assuming that's actually where you want the next tileset to go. If not, you need to call `SetVDPAddress` with a new starting location of course. You should be able to see the result in the tile viewer in Emulicious.

I was building up a few notes when I was trying to step through your routine before, but here I think I'd drip feed two things in particular:

1. I think you might be over-extracting routines in places. For instance you have a `PrepareLoadFont` which is actually just a set VDP address with the address hardcoded to $0000 and a `LoadFont` which is actually just a VDP copy with the source data hardcoded. You might be just as well to stick with using the already parameterised `SetVDPAddress` and `CopyToVDP` directly in your calling code. I think it would make it easier to read and also it would save some cycles.

2. Not super important, but while we're talking about your `SetVDPAddress` you might find that in many examples of others' code, setting the VDP address (or writing to the VDP control port) in particular is implemented as a fast reset vector, e.g. `rst $08`, etc. This is because it's used so frequently and often in moderately time critical situations and the `rst p` instructions are slightly quicker to execute than regular calls. I'd say it's also quite common to see set VDP address implemented as a macro alternatively. Take a look at SMSLib's CRT0 and you'll see that sverx has two reset vectors: one at $08 which copies HL to the VDP control port (just like your SetVDPAddress) and another at $18 which does the same for the data port. In his `rst $08` vector he clobbers the C register rather than pushing to the stack (for speed over safety) although if you didn't want to clobber A you could alternatively use ex af, af' which takes 4 t-states to execute as opposed to push af's 11 and pop af's 10.


This is definitely a good list of things to keep in mind. I'll have to take some time and optimize now since almost everything in my current code is serviceable.

Assuming I can get the tiles to load, how about the stringmap? Should I make a new table that starts with 00 or do I continue where the first one left off? Just append more onto the old stringmap file?
  View user's profile Send private message
  • Joined: 06 Mar 2022
  • Posts: 533
  • Location: London, UK
Reply with quote
Post Posted: Fri Sep 29, 2023 7:01 pm
CerezaSaturn64 wrote
Assuming I can get the tiles to load, how about the stringmap? Should I make a new table that starts with 00 or do I continue where the first one left off? Just append more onto the old stringmap file?

Depends how you're implementing your second tileset really. I think you ought to be able to re-use the same stringmaptable if you are clever about the offsets you use for your second tileset. For example, it looks like you have somewhat less than 128 text tiles defined at the moment, so maybe you could load the second tileset in from 128 ($80) onwards and have your text display routine set bit 7 for each character. Alternatively setting bit 8 (bit 0 of the second byte of each tile reference) will give you tilesets which are 256 tiles big, but you might run into conflict with your sprite tiles that way. Or, as sverx suggested, setting bit 11 (bit 3 of the second byte) will reuse the existing tiles but with the upper palette so in that case no need even for a duplicate tilset.

Alternatively you could of course duplicate the stringmaptable, but start it from a different offset. In that case you'd need to also duplicate the string definitions, referencing your new stringmaptable too, which will use up approximately twice as much ROM space for your string data, and feels to me like the wrong approach vs. either a mathematical relationships between your two tilesets or using the upper palette.
  View user's profile Send private message Visit poster's website
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
Post Posted: Fri Sep 29, 2023 7:07 pm
willbritton wrote
CerezaSaturn64 wrote
Assuming I can get the tiles to load, how about the stringmap? Should I make a new table that starts with 00 or do I continue where the first one left off? Just append more onto the old stringmap file?

Depends how you're implementing your second tileset really. I think you ought to be able to re-use the same stringmaptable if you are clever about the offsets you use for your second tileset. For example, it looks like you have somewhat less than 128 text tiles defined at the moment, so maybe you could load the second tileset in from 128 ($80) onwards and have your text display routine set bit 7 for each character. Alternatively setting bit 8 (bit 0 of the second byte of each tile reference) will give you tilesets which are 256 tiles big, but you might run into conflict with your sprite tiles that way. Or, as sverx suggested, setting bit 11 (bit 3 of the second byte) will reuse the existing tiles but with the upper palette so in that case no need even for a duplicate tilset.

Alternatively you could of course duplicate the stringmaptable, but start it from a different offset. In that case you'd need to also duplicate the string definitions, referencing your new stringmaptable too, which will use up approximately twice as much ROM space for your string data, and feels to me like the wrong approach vs. either a mathematical relationships between your two tilesets or using the upper palette.


I completely forgot I could even set the tiles to use the upper palette just by setting the right bit lol. That sounds like a much better plan. Let's hope I can make that work.
  View user's profile Send private message
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
The Plan...
Post Posted: Mon Oct 02, 2023 8:19 pm
So I'm mildly stumped on how to properly accomplish the task I've set out to do, and I'd like to make sure that what I'm going to attempt will actually work before I try to no avail.

Right now I have the game drawing all of the text to the screen, which then cycles through colors to fade in all at once. In order to isolate the effect to one line at a time, I'd need to draw each line individually, then run the color cycling code, then put another layer of the same text over top that uses the sprite palette which does not get altered.

The questions I have regarding execution are

1. What is the most efficient way to break down each line? Is it simply doing
strings.intro1:
    .stringmap FontIconsStringmap, "<5>The world is veiled in<br><br>"
strings.intro2:
    .stringmap FontIconsStringmap, "<4>darkness. The wind stops,<br><br>"

etc., or is there a better way of breaking the lines down so that they can be more efficiently drawn by the code (since drawing would need to happen in between vblank now)

2. If I can use the same font tileset and just set the sprite palette bit, how do I make sure that it sits on top of the animating text? Also, how would I go about setting this bit when I'm using a stringmap?

I did move SetVDPAddress to $10 and change all "call Set VDPAddress" code to "rst $10" so at least that will be more efficient.
  View user's profile Send private message
  • Site Admin
  • Joined: 19 Oct 1999
  • Posts: 14564
  • Location: London
Reply with quote
Post Posted: Mon Oct 02, 2023 9:15 pm
I’d make a label for each line of text, and then put all the labels in a table. That way the code has to work through the table to work through all the lines. I’d have a few RAM variables for the current table address and a counter, and maybe also put the VRAM write address before each text string.

If your font mapping is to bytes or words, either way you need to set the sprite palette bit at bit 11 of the word in VRAM. Just reuse the write address when you draw a second time.

Top tip: if you moved SetVDPAddress to $10 then WLA DX will let you write “rst SetVDPAddress“ as well as “rst $10”.
  View user's profile Send private message Visit poster's website
  • Joined: 06 Mar 2022
  • Posts: 533
  • Location: London, UK
Reply with quote
Post Posted: Tue Oct 03, 2023 5:52 am
I guess an alternative way could be to use the delimiters within the text to control when the palette fade happens, either using the existing <br> delimiter in conjunction with a special routine, like "DrawTextWithPaletteFades", or with a new delimiter that triggers the palette fade for the line being drawn perhaps?

In either approach (this one or Maxim's) I think having a single routine which draws a line of text, then fades the palette, then redraws the same line but with the fixed palette would be a good building block.

So in pseudocode in my approach, I'd maybe look to have something along the lines of:


function DrawLineWithPaletteFades(ptr_line_of_text, starting_line):
    // draw the line with the fadeable palette
    WaitForVBlank();
    SetVDPAddress($3800 + 64 * starting_line);
    var p = ptr_line_of_text;
    while (*p != END_OF_LINE_CHARACTER):
        WriteByteToVdp(*p);
        WriteByteToVdp(fadeable_palette_attribute); // e.g. bit 11 set
        p++;

    // delay if necessary

    DoPaletteFadingOnEntireScreen();

    // delay if necessary

    // redraw the line with the fixed palette so that it doesn't fade next time
    WaitForVBlank();
    SetVDPAddress($3800 + 64 * starting_line);
    var p = ptr_line_of_text;
    while (*p != END_OF_LINE_CHARACTER):
        WriteByteToVdp(*p);
        WriteByteToVdp(non_fadeable_palette_attribute); // e.g. bit 11 reset
        p++;

    // return the current text pointer so we could use it to draw more text
    return p;
   
function DrawTextWithPaletteFades(ptr_text, len_text):
    var p = ptr_text;
    var line = 0;
    while (p < ptr_text + len_text):
        p = DrawLineWithPaletteFades(p, line);
        line += 2; // double spacing


So the function DrawLineWithPaletteFades above is the main thing, and I would suggest is the approach needed either with the explicit way of drawing the lines one by one that Maxim suggests or with my second function which attempts to do it automatically based on a chunk of text to write to the screen.

The second function DrawTextWithPaletteFades here just runs through a contiguous sequence of lines and draws them one at a time. I've handled the double line spacing by incrementing a line counter by 2, instead of with a <br><br> sequence, I had imagined replacing that with a single <br> instead (in retrospect, this separates content from layout somewhat so might be a good idea generally).
  View user's profile Send private message Visit poster's website
  • Joined: 26 Aug 2022
  • Posts: 20
Reply with quote
Post Posted: Wed Oct 11, 2023 11:52 pm
Last edited by badnest on Thu Oct 12, 2023 1:45 am; edited 1 time in total
I'm gonna go for a different take on this -- I think the whole thing could be accomplished much easier with line interrupts, with the whole text always on the tilemap with the same color. Here's how I would do it:

In vblank, the text color is set to white and the line counter is setup to interrupt in the line just before the first line of text to receive the palette effect.

In this first hblank interrupt, the text color is changed to one of the flashing colors, and the line counter is setup for another interrupt to occur after the line of text (~+16 raster lines).

In this second hblank interrupt the text color is set to blue and the line counter is turned off.

This repeats until the effect is done for the line of text, then a RAM variable gets changed so the vblank now sets up the first interrupt 16 raster lines further down.
  View user's profile Send private message
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
Post Posted: Thu Oct 12, 2023 12:03 am
badnest wrote
I'm gonna go for a different take on this -- I think the whole thing could be accomplished much easier with line interrupts, with the whole text always on the tilemap with the same color. Here's how I would do it:

In vblank, the text color is set to white and the line counter is setup to interrupt in the line just before the first line of text to receive the palette effect.

In this first hblank interrupt, the text color is changed to one of the flashing colors, and the line counter is setup for another interrupt to occur after the line of text (+16 raster lines).

In this second hblank interrupt the text color is set to blue and the line counter is turned off.

This repeats until the effect is done for the line of text, then a RAM variable gets changed so the vblank now sets up the first interrupt 16 raster lines further down.


Sounds complicated but well worth trying out. I haven't worked with line interrupts at all though so I'm not sure how well I could implement them. I will try my best though! Thank you for the tip
  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3590
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Thu Oct 12, 2023 6:35 am
badnest wrote
In vblank, the text color is set to white and the line counter is setup to interrupt in the line just before the first line of text to receive the palette effect.

In this first hblank interrupt, the text color is changed to one of the flashing colors, and the line counter is setup for another interrupt to occur after the line of text (~+16 raster lines).

In this second hblank interrupt the text color is set to blue and the line counter is turned off.


The idea isn't bad, but there's an issue: when the hblank interrupt gets fired, it's too late to set for the next interrupt to occur after a different amount of lines.

So you would probably use it this way instead: set the interrupt counter to fire every 16 lines and in your handler check if it's time to switch to some color - or alternatively have an array of colors to apply (in RAM so that you can manipulate that when needed) and have the hblank interrupt handler apply a palette change using the next value in the array.
  View user's profile Send private message Visit poster's website
  • Joined: 26 Aug 2022
  • Posts: 20
Reply with quote
Post Posted: Mon Oct 16, 2023 5:35 am
sverx wrote
The idea isn't bad, but there's an issue: when the hblank interrupt gets fired, it's too late to set for the next interrupt to occur after a different amount of lines.


You're right, my mistake. Though I've been experimenting with tricking the VDP by setting up the line counter one interrupt in advance. I've got it down to this:

Vblank: Line counter is setup to interrupt every line. This will trigger line interrupts 1 and 2.

1st Hblank int (line 0): Text color is set to white, line counter is setup to trigger on the row before the effect, this will trigger interrupt 3.

2nd Hblank int (line 1): Text color is reduntantly set to white, line counter is setup to trigger the row after the effect, this will trigger interrupt 4.

3rd Hblank int: Text color is set to flashing effect color, line counter is disabled.

4th Hblank int: Text color is set to background color, line counter is redundantly disabled.


I've attached a quick and dirty POC. The hblank routine is at $01C1.
raster_txtpal.zip (5.04 KB)

  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3590
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Mon Oct 16, 2023 7:40 am
Yes, that's how you do it. Great work! :)
  View user's profile Send private message Visit poster's website
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
Post Posted: Thu Oct 19, 2023 11:06 pm
badnest wrote
sverx wrote
The idea isn't bad, but there's an issue: when the hblank interrupt gets fired, it's too late to set for the next interrupt to occur after a different amount of lines.


You're right, my mistake. Though I've been experimenting with tricking the VDP by setting up the line counter one interrupt in advance. I've got it down to this:

Vblank: Line counter is setup to interrupt every line. This will trigger line interrupts 1 and 2.

1st Hblank int (line 0): Text color is set to white, line counter is setup to trigger on the row before the effect, this will trigger interrupt 3.

2nd Hblank int (line 1): Text color is reduntantly set to white, line counter is setup to trigger the row after the effect, this will trigger interrupt 4.

3rd Hblank int: Text color is set to flashing effect color, line counter is disabled.

4th Hblank int: Text color is set to background color, line counter is redundantly disabled.


I've attached a quick and dirty POC. The hblank routine is at $01C1.


any possibility you could include the source file as well? I'm still pretty new at coding in assembly here and the comments and breakdown of the code would help me tremendously in learning what all the moving parts are doing as well as what I need beyond the line interrupt handler to accomplish this for my own project.
  View user's profile Send private message
  • Joined: 26 Aug 2022
  • Posts: 20
Reply with quote
Post Posted: Fri Oct 20, 2023 1:50 am
Like I said it's a quick and dirty POC. There's a small timing issue so noise appears at the top of the screen, and the source is not commented. But since you're interested I'll comment the relevant parts and upload a zip file when I get some time, probably within a couple days or so.
  View user's profile Send private message
  • Joined: 25 Feb 2023
  • Posts: 99
Reply with quote
Post Posted: Fri Oct 20, 2023 2:52 am
badnest wrote
Like I said it's a quick and dirty POC. There's a small timing issue so noise appears at the top of the screen, and the source is not commented. But since you're interested I'll comment the relevant parts and upload a zip file when I get some time, probably within a couple days or so.


Thank you!
Yeah, I've been flying by the seat of my pants with assembly coding a game. I've worked in C before but never to make games (at least none with graphics) so I'm also learning how to code for an entire system and play with the graphics.

The will to succeed and put out a game is far stronger than the little voice who has doubts though.
  View user's profile Send private message
  • Joined: 26 Aug 2022
  • Posts: 20
Reply with quote
Post Posted: Sat Oct 21, 2023 5:51 pm
There's nothing very relevant to the subject in main.asm, besides copying d_raster to ram so it can be altered. d_raster is the data that the hblank routine takes in, it's explained in data.asm. The real action is in blanking.asm.
raster_pal_srcs.zip (17.49 KB)

  View user's profile Send private message
Reply to topic



Back to the top of this page

Back to SMS Power!