A way to switch palette colors using sgdk without asm

SGDK only sub forum

Moderator: Stef

greatkreator
Very interested
Posts: 158
Joined: Sat May 12, 2012 7:37 pm
Location: Ukraine

A way to switch palette colors using sgdk without asm

Post by greatkreator » Thu May 24, 2012 6:50 pm

Do anyone know or maybe already tried:
Is it possible to change palette colors in hblank without asm injection? Just using sgdk.
I would like to implement high color images and don't want to dirty C code with asm injection.

Thanks a lot guys for any help.

P.S. If it is not possible the asm injection code (performing palette dma transfer) would be very appreciated.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Fri May 25, 2012 8:48 am

I forgot to mention the DMA in my PM which is the best solution for what you want to do :p

There is a method in SGDK :

Code: Select all

VDP_doCRamDMA(from, to, len)
but in your case you cannot use it as you require more control and speed.

Also instead of using H Interrupt to update your palette i think you should use the HV counter in your main loop.
What you can do is prepare your DMA then waiting the good moment to start it.

Prepare the DMA :

Code: Select all

    vu16 *pw;
    vu32 *pl;
    u32 vdp_data;
    u16 hv_maxpos;

    VDP_setAutoInc(2);

    pw = (u16 *) GFX_CTRL_PORT;

    // Setup DMA length (in word here)
    len >>= 1;
    *pw = 0x9300 + (len & 0xff);
    newlen >>= 8;
    *pw = 0x9400 + (len & 0xff);

    // Setup DMA address
    from >>= 1;
    *pw = 0x9500 + (from & 0xff);
    from >>= 8;
    *pw = 0x9600 + (from & 0xff);
    from >>= 8;
    *pw = 0x9700 + (from & 0x7f);

    // prepare DMA write
    pl = (u32 *) GFX_CTRL_PORT;
    vdp_data = GFX_DMA_CRAM_ADDR(adr)
Wait end of active period / start of blanking :

Code: Select all

hv_maxpos = ((VLine - 1) << 8) | HEndActivePos);
while (GET_HVCOUNTER  < hv_maxpos);
Here VLine correspond to the scanline where you want to change the palette and HEndActivePos the H position for end of active period (i am not sure about the number to use here and anyway you should tweak it to get best result).

then just trigger DMA in a single instruction :

Code: Select all

*pl = vdp_data;
That should do it...

greatkreator
Very interested
Posts: 158
Joined: Sat May 12, 2012 7:37 pm
Location: Ukraine

Post by greatkreator » Fri May 25, 2012 12:28 pm

Thanks a lot Stef.
It is bad but yet I am not such a cool mega drive coder to assemble it all together to make it work.
I can just stare at it and hope that it works - at least theoretically.

Maybe at some point in the future I will make it work. I hope the near future.
It is hard not to dive in assembly mess deeply and to get something special effects like the high color.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Fri May 25, 2012 12:47 pm

greatkreator wrote:Thanks a lot Stef.
It is bad but yet I am not such a cool mega drive coder to assemble it all together to make it work.
I can just stare at it and hope that it works - at least theoretically.

Maybe at some point in the future I will make it work. I hope the near future.
It is hard not to dive in assembly mess deeply and to get something special effects like the high color.
Maybe there are some mistakes in my code, i didn't tested it because i can't do it right now but at least you have the idea !
Debugging code is not easy on megadrive, you can use GensKMod and use the KDebug features to trace your execution.

greatkreator
Very interested
Posts: 158
Joined: Sat May 12, 2012 7:37 pm
Location: Ukraine

Post by greatkreator » Sat May 26, 2012 3:29 pm

I use vcounter and fill the palette using dma.

Original image:
Image

The image I am able to reproduce so far (total 54 colours, 16 colours each tile line):
Image

Code: Select all

#include <genesis.h>

extern u16 palette_data[];
extern u16 index_data[];

u16 i;

void hinter();

int main() {
	VDP_init();
	VDP_setScreenWidth320();
	VDP_setScreenHeight224();
	VDP_setPlanSize(64, 64);

	VDP_loadTileData(index_data, 1, 1120, 1);

	setHBlankCallback(hinter);
	VDP_setHIntCounter(8);
	VDP_setHInterrupt(1);

	for (;;) {
		VDP_fillTileMapRectInc(APLAN, 1, 0, 0, 40, 28);
		VDP_waitVSync();
	}
	return 0;
}

void hinter() {
	u32 from = palette_data + ((GET_VCOUNTER >> 3) << 4);

	VDP_setAutoInc(2);

	vu16* pw = (u16*) GFX_CTRL_PORT;

	*pw = 0x9300 + 16;
	*pw = 0x9400 + 0;

	*pw = 0x9500 + ((from >> 1) & 0xff);
	*pw = 0x9600 + ((from >> 9) & 0xff);
	*pw = 0x9700 + ((from >> 17) & 0x7f);

	*((u32*)GFX_CTRL_PORT) = GFX_DMA_CRAM_ADDR(PAL0);
}
I couldn't use your help fully Stef. I cannot comprehend it yet.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Sat May 26, 2012 5:04 pm

greatkreator wrote:I use vcounter and fill the palette using dma.

Original image:
Image

The image I am able to reproduce so far (total 54 colours, 16 colours each tile line):
Image

...

I couldn't use your help fully Stef. I cannot comprehend it yet.
The original image looks great :)

Your code is simple and "theoretically" nice but there are some small mistakes :

First you should set HIntCounter to 7 and not 8 if you want H-Int to happen each 8 scanline (they happen each 9 scanlines with your code).
Something sure is that some cpu cycles will be spent before CRAM DMA happen so your DMA won't really start at line 8 (for instance) but at line 10, this is another problem...

Another problem is that you are doing this :

Code: Select all

		VDP_fillTileMapRectInc(APLAN, 1, 0, 0, 40, 28);
indefinitely in your main loop.
That is a big problem as your H-Int code will execute at same time and mess the VDP state so your writes to VDP will become totally out of control and corrupted...
You should never modify VDP data in your main loop if you do it in Interrupt callback and vice versa.
So what you have to do is calling the fillTile method only once at beginning then you only do work on the int handler.

Something similar to that :

Code: Select all

#include <genesis.h>

extern u16 palette_data[];
extern u16 index_data[];

void hinter();

int main() {
	VDP_init();
	VDP_setScreenWidth320();
	VDP_setScreenHeight224();
	VDP_setPlanSize(64, 64);

	VDP_loadTileData(index_data, 1, 1120, 1);
	VDP_fillTileMapRectInc(APLAN, 1, 0, 0, 40, 28);

	setHBlankCallback(hinter);
	VDP_setHIntCounter(8);
	VDP_setHInterrupt(1);

	for (;;) {
		VDP_waitVSync();
	}

	return 0;
}

void hinter() {
        VDP_doCRamDMA(palette_data + ((GET_VCOUNTER >> 3) << 4), 0, 16);
}
But still that won't perfectly as i said earlier the DMA will start too late, you have to move the palette update code in the main loop so you can wait for a specific HVCounter value before doing DMA operation and so you can start it exactly at the desired moment.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Sat May 26, 2012 5:09 pm

By the way, if your original image is only 54 colors then you don't even need the palette change trick. You can simply use a background to display the 16 first colors, the second one for 16 more colors and then sprites for the missing ones... but now i'm telling it, i'm not sure that is easier than refreshing palette during hblank :p

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sat May 26, 2012 5:13 pm

Stef wrote:By the way, if your original image is only 54 colors then you don't even need the palette change trick. You can simply use a background to display the 16 first colors, the second one for 16 more colors and then sprites for the missing ones... but now i'm telling it, i'm not sure that is easier than refreshing palette during hblank :p
Do like I did for my 512 color demo - set the horizontal scroll for each line, then set the entries in the name table so that the scroll makes it select a different palette for each line.

greatkreator
Very interested
Posts: 158
Joined: Sat May 12, 2012 7:37 pm
Location: Ukraine

Post by greatkreator » Sat May 26, 2012 6:29 pm

Stef wrote:By the way, if your original image is only 54 colors then you don't even need the palette change trick. You can simply use a background to display the 16 first colors, the second one for 16 more colors and then sprites for the missing ones... but now i'm telling it, i'm not sure that is easier than refreshing palette during hblank :p
Actually it is not a colorful enough image - theoretically about 400 colors may be used. The method you are talking about has substantial disadvantage: too much tiles are used - thus fullscreen image cannot be used. Of course you can do tricks to re-use tiles but anyway only 45-50 colors can be shown.

By the way my current version works only on a emulator.
The real hardware rejects it. I see few blinking lines only.
I really think about not walking on the edge. I am too afraid that my "masterpiece" can not work on some devices even if I would test it on my very bad Chinese clone well. That is why it is likely i would choose the second stable method you was talking about Stef.

greatkreator
Very interested
Posts: 158
Joined: Sat May 12, 2012 7:37 pm
Location: Ukraine

Post by greatkreator » Sat May 26, 2012 6:37 pm

Chilly Willy wrote:
Stef wrote:By the way, if your original image is only 54 colors then you don't even need the palette change trick. You can simply use a background to display the 16 first colors, the second one for 16 more colors and then sprites for the missing ones... but now i'm telling it, i'm not sure that is easier than refreshing palette during hblank :p
Do like I did for my 512 color demo - set the horizontal scroll for each line, then set the entries in the name table so that the scroll makes it select a different palette for each line.
Am I right you are talking about the images that based on "RGB-like" lines?
If so they look a little "special/strange" to me. Don't they?
I really would like to achieve old-classic-each-pixel-own-color result.

The very fast palette switch walks on the edge. I find it too risky.
I am inclined to use the layered stable way but not in full screen.

However if you Chilly Willy or you Stef have any ideas please tell me.
Thanks guys.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Sat May 26, 2012 9:51 pm

Stef wrote: Actually it is not a colorful enough image - theoretically about 400 colors may be used. The method you are talking about has substantial disadvantage: too much tiles are used - thus fullscreen image cannot be used. Of course you can do tricks to re-use tiles but anyway only 45-50 colors can be shown.
True, that was just for a ~50 colors only image, if you want more, you'll have to use palette update on scanline.
By the way my current version works only on a emulator.
The real hardware rejects it. I see few blinking lines only.
What version are you speaking about ? Did you tried to modify as i told you ? If you speak about your version, it just cannot work on real hardware as VDP writes are messed...
I really think about not walking on the edge. I am too afraid that my "masterpiece" can not work on some devices even if I would test it on my very bad Chinese clone well. That is why it is likely i would choose the second stable method you was talking about Stef.
Having that sort of effect working on real hardware is always more tricky than on emulator, i don't know how your chinese clone is accurate compared to real thing but indeed you may observe differences...
For the second method, i can't really give you more informations that i already did... You have almost all the code. Just need some timing tweaks.

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sat May 26, 2012 10:00 pm

greatkreator wrote:
Chilly Willy wrote:
Stef wrote:By the way, if your original image is only 54 colors then you don't even need the palette change trick. You can simply use a background to display the 16 first colors, the second one for 16 more colors and then sprites for the missing ones... but now i'm telling it, i'm not sure that is easier than refreshing palette during hblank :p
Do like I did for my 512 color demo - set the horizontal scroll for each line, then set the entries in the name table so that the scroll makes it select a different palette for each line.
Am I right you are talking about the images that based on "RGB-like" lines?
If so they look a little "special/strange" to me. Don't they?
I really would like to achieve old-classic-each-pixel-own-color result.
Yes, it uses interleaved R, G, and B only pixels to do a direct color image. It's actually not too bad... better than I thought it would be. However, it is the technique of how to change palettes I thought you would be interested in, not the direct color rendering.

The very fast palette switch walks on the edge. I find it too risky.
I am inclined to use the layered stable way but not in full screen.
It's not a very fast palette switch - the palette entries are all set well ahead of time, and in my case, never change. Look at it this way:

128x32 name table

Code: Select all

 ---------------------------------------------------------------
|                  |                  |                  |      |
|    40x32         |      40x32       |      40x32       |      |
|   palette 0      |    palette 1     |    palette 2     |      |
|                  |                  |                  |      |
 ---------------------------------------------------------------
All three sections of the name table hold the same name patterns, but different palette numbers. The MD allows you to set the horizontal scroll on a line-by-line basis, so merely fill the HSCROLL table with constants that point each line to the palette you wish to use for that line. This gives you three different FIXED palettes for 46 colors you can use (15 + background for each line) with NO TRICKS AT ALL. No DMA, no ints, no changing color entries on the fly.

The extra 8 entries in the table could be put between the three sections to make scrolling possible, but a static display is as easy as you see above.

greatkreator
Very interested
Posts: 158
Joined: Sat May 12, 2012 7:37 pm
Location: Ukraine

Post by greatkreator » Sun May 27, 2012 4:17 pm

Thanks Chilly Willy for the technique.
It is really interesting and elegant.
It has its own shortcomings(i mean less total color number per image than the rapid palette switch) but I will try to employ it in my project.

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sun May 27, 2012 5:35 pm

greatkreator wrote:Thanks Chilly Willy for the technique.
It is really interesting and elegant.
It has its own shortcomings(i mean less total color number per image than the rapid palette switch) but I will try to employ it in my project.
Yeah, the map isn't wide enough to make four screens in 40 cell mode, just three and some change. I only needed two for my direct color mode. If you switched to 32 cell mode, then the map IS wide enough for all four palettes, but then you have to adjust everything for 256 wide instead of 320 wide.

That's the "fun" of old consoles - trying to find the best way around the limits on what you can do.
:D

greatkreator
Very interested
Posts: 158
Joined: Sat May 12, 2012 7:37 pm
Location: Ukraine

Post by greatkreator » Sun May 27, 2012 6:00 pm

The addictive fun.

I wonder have you seen any working demo with the rapid palette switch?
Any demo showing an image with highcolor - not useless sets of colors.
I cannot find any.

Post Reply