Posté le 24/01/2016 à 14:54 Membre depuis le 21/03/2014, 187 messages
Hi,
I would like to share a C function I have written lately for "fading out" and "fading in" graphics by reducing or increasing the RGB63 values of the respective color palettes step by step.
With the current code you can fade the colors to black but with some adjustments of the "steps" you could also fade them to white or fade them incomplete to have a "dimmed graphic" effect.
Also, you could adjust the fade speed by editing the "steps" value (default is 4). The functions have affect on the first 16 color palettes only (due to RAM limitations) but you could adjust the start
position by editing the "palette_no" variable (for instance a value of 40 would fade all graphics with palette from 40 to 56).

Here is an example how it looks:



And here is the code:

fade_palettes.h

#ifndef __FADE_PALLETES_H__
#define __FADE_PALLETES_H__

struct palette_t
{
	int original_color, new_color;
	int index, red, green, blue, index_temp, red_temp, green_temp, blue_temp;
	int RGB63_red, RGB63_green, RGB63_blue, RGB63_red_index, RGB63_green_index, RGB63_blue_index;
	int RGB63_red_temp, RGB63_green_temp, RGB63_blue_temp, RGB63_red_index_temp, RGB63_green_index_temp, RGB63_blue_index_temp;
};

extern struct palette_t color[256];

void fade_out();
void prepare_fade_in();
void fade_in();

#endif

fade_palettes.c

#include <video.h>
#include <input.h>
#include <DATlib.h>
#include "fade_palettes.h"

struct palette_t color[256];

// FADE OUT //////////////////////////////////////////////////////////////////

void fade_out()
{
	int palette_no = 0; // first palette to start with
	int i;
	int steps=0;

	waitVBlank();

	for(i=0; i<256; i++)
	{
		// save original palettes and calculate hex values for index bits and each color //

		color[i].original_color  = volMEMWORD(4194304+(i*2)+(palette_no*32));  // 4194304 decimal = 0x400000 hex adress of color 0 of palette 0

		color[i].blue=color[i].original_color/16;	// quotient
		color[i].green=color[i].blue/16;		// quotient
		color[i].red=color[i].green/16;			// quotient
		color[i].index=color[i].red/16;			// quotient

		color[i].index=color[i].red%16;			// remainder
		color[i].red=color[i].green%16;			// remainder
		color[i].green=color[i].blue%16;		// remainder
		color[i].blue=color[i].original_color%16;	// remainder

		// convert to RGB63 ///////////////////////////////////////////////

		if(color[i].index==0) {color[i].RGB63_red_index=1; color[i].RGB63_green_index=1; color[i].RGB63_blue_index=1;}
		if(color[i].index==1) {color[i].RGB63_red_index=1; color[i].RGB63_green_index=1; color[i].RGB63_blue_index=3;}
		if(color[i].index==2) {color[i].RGB63_red_index=1; color[i].RGB63_green_index=3; color[i].RGB63_blue_index=1;}
		if(color[i].index==3) {color[i].RGB63_red_index=1; color[i].RGB63_green_index=3; color[i].RGB63_blue_index=3;}
		if(color[i].index==4) {color[i].RGB63_red_index=3; color[i].RGB63_green_index=1; color[i].RGB63_blue_index=1;}
		if(color[i].index==5) {color[i].RGB63_red_index=3; color[i].RGB63_green_index=1; color[i].RGB63_blue_index=3;}
		if(color[i].index==6) {color[i].RGB63_red_index=3; color[i].RGB63_green_index=3; color[i].RGB63_blue_index=1;}
		if(color[i].index==7) {color[i].RGB63_red_index=3; color[i].RGB63_green_index=3; color[i].RGB63_blue_index=3;}
		if(color[i].index==8) {color[i].RGB63_red_index=0; color[i].RGB63_green_index=0; color[i].RGB63_blue_index=0;}
		if(color[i].index==9) {color[i].RGB63_red_index=0; color[i].RGB63_green_index=0; color[i].RGB63_blue_index=2;}
		if(color[i].index==10){color[i].RGB63_red_index=0; color[i].RGB63_green_index=2; color[i].RGB63_blue_index=0;}
		if(color[i].index==11){color[i].RGB63_red_index=0; color[i].RGB63_green_index=2; color[i].RGB63_blue_index=2;}
		if(color[i].index==12){color[i].RGB63_red_index=2; color[i].RGB63_green_index=0; color[i].RGB63_blue_index=0;}
		if(color[i].index==13){color[i].RGB63_red_index=2; color[i].RGB63_green_index=0; color[i].RGB63_blue_index=2;}
		if(color[i].index==14){color[i].RGB63_red_index=2; color[i].RGB63_green_index=2; color[i].RGB63_blue_index=0;}
		if(color[i].index==15){color[i].RGB63_red_index=2; color[i].RGB63_green_index=2; color[i].RGB63_blue_index=2;}

		color[i].RGB63_red   = color[i].red   * 4 + color[i].RGB63_red_index;
		color[i].RGB63_green = color[i].green * 4 + color[i].RGB63_green_index;
		color[i].RGB63_blue  = color[i].blue  * 4 + color[i].RGB63_blue_index;

		// copy ASM Hex Color Code values to temporary variables ///////////

		color[i].index_temp = color[i].index;
		color[i].red_temp   = color[i].red;
		color[i].green_temp = color[i].green;
		color[i].blue_temp  = color[i].blue;
	}

	while(1)
	{
		waitVBlank();

		steps-=4;

		for(i=0; i<256; i++)
		{
			// add steps to RGB63 temporary values /////////////////////////

			color[i].RGB63_red_temp   = color[i].RGB63_red + steps;
			color[i].RGB63_green_temp = color[i].RGB63_green + steps;
			color[i].RGB63_blue_temp  = color[i].RGB63_blue + steps;

			// keep values inside the range of 0 to 63 /////////////////////

			if(color[i].RGB63_red_temp>63) color[i].RGB63_red_temp=63;
			if(color[i].RGB63_red_temp<0) color[i].RGB63_red_temp=0;
			if(color[i].RGB63_green_temp>63) color[i].RGB63_green_temp=63;
			if(color[i].RGB63_green_temp<0) color[i].RGB63_green_temp=0;
			if(color[i].RGB63_blue_temp>63) color[i].RGB63_blue_temp=63;
			if(color[i].RGB63_blue_temp<0) color[i].RGB63_blue_temp=0;

			// convert RGB63 back to ASM Hex Color Code ////////////////////

			color[i].RGB63_red_index_temp = color[i].RGB63_red_temp%4;
			color[i].red_temp = color[i].RGB63_red_temp/4;

			color[i].RGB63_green_index_temp = color[i].RGB63_green_temp%4;
			color[i].green_temp = color[i].RGB63_green_temp/4;

			color[i].RGB63_blue_index_temp = color[i].RGB63_blue_temp%4;
			color[i].blue_temp = color[i].RGB63_blue_temp/4;

			if(color[i].RGB63_red_index_temp==1 && color[i].RGB63_green_index_temp==1 && color[i].RGB63_blue_index_temp==1) color[i].index_temp=0;
			if(color[i].RGB63_red_index_temp==1 && color[i].RGB63_green_index_temp==1 && color[i].RGB63_blue_index_temp==3) color[i].index_temp=1;
			if(color[i].RGB63_red_index_temp==1 && color[i].RGB63_green_index_temp==3 && color[i].RGB63_blue_index_temp==1) color[i].index_temp=2;
			if(color[i].RGB63_red_index_temp==1 && color[i].RGB63_green_index_temp==3 && color[i].RGB63_blue_index_temp==3) color[i].index_temp=3;
			if(color[i].RGB63_red_index_temp==3 && color[i].RGB63_green_index_temp==1 && color[i].RGB63_blue_index_temp==1) color[i].index_temp=4;
			if(color[i].RGB63_red_index_temp==3 && color[i].RGB63_green_index_temp==1 && color[i].RGB63_blue_index_temp==3) color[i].index_temp=5;
			if(color[i].RGB63_red_index_temp==3 && color[i].RGB63_green_index_temp==3 && color[i].RGB63_blue_index_temp==1) color[i].index_temp=6;
			if(color[i].RGB63_red_index_temp==3 && color[i].RGB63_green_index_temp==3 && color[i].RGB63_blue_index_temp==3) color[i].index_temp=7;
			if(color[i].RGB63_red_index_temp==0 && color[i].RGB63_green_index_temp==0 && color[i].RGB63_blue_index_temp==0) color[i].index_temp=8;
			if(color[i].RGB63_red_index_temp==0 && color[i].RGB63_green_index_temp==0 && color[i].RGB63_blue_index_temp==2) color[i].index_temp=9;
			if(color[i].RGB63_red_index_temp==0 && color[i].RGB63_green_index_temp==2 && color[i].RGB63_blue_index_temp==0) color[i].index_temp=10;
			if(color[i].RGB63_red_index_temp==0 && color[i].RGB63_green_index_temp==2 && color[i].RGB63_blue_index_temp==2) color[i].index_temp=11;
			if(color[i].RGB63_red_index_temp==2 && color[i].RGB63_green_index_temp==0 && color[i].RGB63_blue_index_temp==0) color[i].index_temp=12;
			if(color[i].RGB63_red_index_temp==2 && color[i].RGB63_green_index_temp==0 && color[i].RGB63_blue_index_temp==2) color[i].index_temp=13;
			if(color[i].RGB63_red_index_temp==2 && color[i].RGB63_green_index_temp==2 && color[i].RGB63_blue_index_temp==0) color[i].index_temp=14;
			if(color[i].RGB63_red_index_temp==2 && color[i].RGB63_green_index_temp==2 && color[i].RGB63_blue_index_temp==2) color[i].index_temp=15;

			// write new ASM Hex Color Code to color adress ////////////////

			color[i].new_color=(color[i].index_temp)*4096+(color[i].red_temp)*256+(color[i].green_temp)*16+(color[i].blue_temp);
			volMEMWORD(4194304+(i*2)+(palette_no*32)) = color[i].new_color;
		}

		if(steps<=-64) break; // exit loop when done
	}


}

// FADE IN //////////////////////////////////////////////////////////////////

void prepare_fade_in()
{
	int palette_no = 0; // first palette to start with
	int i;
	int steps=-64;

	waitVBlank();

	for(i=0; i<256; i++)
	{
		// save original palettes and calculate hex values for index bits and each color //

		color[i].original_color  = volMEMWORD(4194304+(i*2)+(palette_no*32));  // 4194304 decimal = 0x400000 hex adress of color 0 of palette 0

		color[i].blue=color[i].original_color/16;	// quotient
		color[i].green=color[i].blue/16;		// quotient
		color[i].red=color[i].green/16;			// quotient
		color[i].index=color[i].red/16;			// quotient

		color[i].index=color[i].red%16;			// remainder
		color[i].red=color[i].green%16;			// remainder
		color[i].green=color[i].blue%16;		// remainder
		color[i].blue=color[i].original_color%16;	// remainder

		// convert to RGB 63 ////////////////////////////////////////////////////

		if(color[i].index==0) {color[i].RGB63_red_index=1; color[i].RGB63_green_index=1; color[i].RGB63_blue_index=1;}
		if(color[i].index==1) {color[i].RGB63_red_index=1; color[i].RGB63_green_index=1; color[i].RGB63_blue_index=3;}
		if(color[i].index==2) {color[i].RGB63_red_index=1; color[i].RGB63_green_index=3; color[i].RGB63_blue_index=1;}
		if(color[i].index==3) {color[i].RGB63_red_index=1; color[i].RGB63_green_index=3; color[i].RGB63_blue_index=3;}
		if(color[i].index==4) {color[i].RGB63_red_index=3; color[i].RGB63_green_index=1; color[i].RGB63_blue_index=1;}
		if(color[i].index==5) {color[i].RGB63_red_index=3; color[i].RGB63_green_index=1; color[i].RGB63_blue_index=3;}
		if(color[i].index==6) {color[i].RGB63_red_index=3; color[i].RGB63_green_index=3; color[i].RGB63_blue_index=1;}
		if(color[i].index==7) {color[i].RGB63_red_index=3; color[i].RGB63_green_index=3; color[i].RGB63_blue_index=3;}
		if(color[i].index==8) {color[i].RGB63_red_index=0; color[i].RGB63_green_index=0; color[i].RGB63_blue_index=0;}
		if(color[i].index==9) {color[i].RGB63_red_index=0; color[i].RGB63_green_index=0; color[i].RGB63_blue_index=2;}
		if(color[i].index==10){color[i].RGB63_red_index=0; color[i].RGB63_green_index=2; color[i].RGB63_blue_index=0;}
		if(color[i].index==11){color[i].RGB63_red_index=0; color[i].RGB63_green_index=2; color[i].RGB63_blue_index=2;}
		if(color[i].index==12){color[i].RGB63_red_index=2; color[i].RGB63_green_index=0; color[i].RGB63_blue_index=0;}
		if(color[i].index==13){color[i].RGB63_red_index=2; color[i].RGB63_green_index=0; color[i].RGB63_blue_index=2;}
		if(color[i].index==14){color[i].RGB63_red_index=2; color[i].RGB63_green_index=2; color[i].RGB63_blue_index=0;}
		if(color[i].index==15){color[i].RGB63_red_index=2; color[i].RGB63_green_index=2; color[i].RGB63_blue_index=2;}

		color[i].RGB63_red   = color[i].red   * 4 + color[i].RGB63_red_index;
		color[i].RGB63_green = color[i].green * 4 + color[i].RGB63_green_index;
		color[i].RGB63_blue  = color[i].blue  * 4 + color[i].RGB63_blue_index;

		// copy hex values to temporary variables ///////////////////////////////

		color[i].index_temp = color[i].index;
		color[i].red_temp   = color[i].red;
		color[i].green_temp = color[i].green;
		color[i].blue_temp  = color[i].blue;

		// set all color palettes to black //////////////////////////////////////

		volMEMWORD(4194304+(i*2)+(palette_no*32)) = 0x0000;
	}
}

void fade_in()
{
	int palette_no;
	int i=0;
	int steps=-64;

	waitVBlank();

	palette_no = 0; // first palette to start with

	while(1)
	{
		waitVBlank();

		steps+=4;

		for(i=0; i<256; i++)
		{
			// add steps to RGB63 temporary values ////////////////////

			color[i].RGB63_red_temp   = color[i].RGB63_red + steps;
			color[i].RGB63_green_temp = color[i].RGB63_green + steps;
			color[i].RGB63_blue_temp  = color[i].RGB63_blue + steps;

			// keep values inside the range of 0 to 63 ////////////////

			if(color[i].RGB63_red_temp>63) color[i].RGB63_red_temp=63;
			if(color[i].RGB63_red_temp<0) color[i].RGB63_red_temp=0;
			if(color[i].RGB63_green_temp>63) color[i].RGB63_green_temp=63;
			if(color[i].RGB63_green_temp<0) color[i].RGB63_green_temp=0;
			if(color[i].RGB63_blue_temp>63) color[i].RGB63_blue_temp=63;
			if(color[i].RGB63_blue_temp<0) color[i].RGB63_blue_temp=0;

			// convert RGB63 back to ASM Hex Color Code ////////////////

			color[i].RGB63_red_index_temp = color[i].RGB63_red_temp%4;
			color[i].red_temp = color[i].RGB63_red_temp/4;

			color[i].RGB63_green_index_temp = color[i].RGB63_green_temp%4;
			color[i].green_temp = color[i].RGB63_green_temp/4;

			color[i].RGB63_blue_index_temp = color[i].RGB63_blue_temp%4;
			color[i].blue_temp = color[i].RGB63_blue_temp/4;

			if(color[i].RGB63_red_index_temp==1 && color[i].RGB63_green_index_temp==1 && color[i].RGB63_blue_index_temp==1) color[i].index_temp=0;
			if(color[i].RGB63_red_index_temp==1 && color[i].RGB63_green_index_temp==1 && color[i].RGB63_blue_index_temp==3) color[i].index_temp=1;
			if(color[i].RGB63_red_index_temp==1 && color[i].RGB63_green_index_temp==3 && color[i].RGB63_blue_index_temp==1) color[i].index_temp=2;
			if(color[i].RGB63_red_index_temp==1 && color[i].RGB63_green_index_temp==3 && color[i].RGB63_blue_index_temp==3) color[i].index_temp=3;
			if(color[i].RGB63_red_index_temp==3 && color[i].RGB63_green_index_temp==1 && color[i].RGB63_blue_index_temp==1) color[i].index_temp=4;
			if(color[i].RGB63_red_index_temp==3 && color[i].RGB63_green_index_temp==1 && color[i].RGB63_blue_index_temp==3) color[i].index_temp=5;
			if(color[i].RGB63_red_index_temp==3 && color[i].RGB63_green_index_temp==3 && color[i].RGB63_blue_index_temp==1) color[i].index_temp=6;
			if(color[i].RGB63_red_index_temp==3 && color[i].RGB63_green_index_temp==3 && color[i].RGB63_blue_index_temp==3) color[i].index_temp=7;
			if(color[i].RGB63_red_index_temp==0 && color[i].RGB63_green_index_temp==0 && color[i].RGB63_blue_index_temp==0) color[i].index_temp=8;
			if(color[i].RGB63_red_index_temp==0 && color[i].RGB63_green_index_temp==0 && color[i].RGB63_blue_index_temp==2) color[i].index_temp=9;
			if(color[i].RGB63_red_index_temp==0 && color[i].RGB63_green_index_temp==2 && color[i].RGB63_blue_index_temp==0) color[i].index_temp=10;
			if(color[i].RGB63_red_index_temp==0 && color[i].RGB63_green_index_temp==2 && color[i].RGB63_blue_index_temp==2) color[i].index_temp=11;
			if(color[i].RGB63_red_index_temp==2 && color[i].RGB63_green_index_temp==0 && color[i].RGB63_blue_index_temp==0) color[i].index_temp=12;
			if(color[i].RGB63_red_index_temp==2 && color[i].RGB63_green_index_temp==0 && color[i].RGB63_blue_index_temp==2) color[i].index_temp=13;
			if(color[i].RGB63_red_index_temp==2 && color[i].RGB63_green_index_temp==2 && color[i].RGB63_blue_index_temp==0) color[i].index_temp=14;
			if(color[i].RGB63_red_index_temp==2 && color[i].RGB63_green_index_temp==2 && color[i].RGB63_blue_index_temp==2) color[i].index_temp=15;

			// write new ASM Hex Color Code to color adress //////////////

			color[i].new_color=(color[i].index_temp)*4096+(color[i].red_temp)*256+(color[i].green_temp)*16+(color[i].blue_temp);
			volMEMWORD(4194304+(i*2)+(palette_no*32)) = color[i].new_color;
		}

		if(steps>=0) break;
	}
}

main.c

int main(void)
{
	picture demo_pic_1;
	aSprite demo_spr_1;
	int end_loop_timer=0;

	volMEMWORD(0x401ffe)=0x0000; // set BG color to black
	LSPCmode=0x900;

	initGfx();
	clearFixLayer();
	clearSprites(1, 381);

	palJobPut(2, demo_pic_Palettes.palCount, demo_pic_Palettes.data);
	palJobPut(4, demo_spr_Palettes.palCount, demo_spr_Palettes.data); 
	SCClose();

	prepare_fade_in();

	pictureInit(&demo_pic_1, &demo_pic,  1, 1, 50, 50, FLIP_NONE);
	aSpriteInit(&demo_spr_1, &demo_spr,  2, 2, 50, 50, 0, FLIP_NONE);
	SCClose();

	fade_in();

	do
	{
		waitVBlank();
		end_loop_timer+=1;		

		aSpriteAnimate(&demo_spr);
		SCClose();

		if(end_loop_timer==420)
		{
			fade_out();
			clearFixLayer();
			clearSprites(1, 381);
		}

	}while(!(end_loop_timer==420));
}
Posté le 24/01/2016 à 18:28 Membre depuis le 28/01/2003, 160 messages
Looks pretty convoluted, how fast does this run ?

Why not just pre cook the palettes if you are going to be limited to 16 anyway ?
Posté le 24/01/2016 à 19:24 Membre depuis le 21/03/2014, 187 messages
With 16 palettes (256 colors) it runs pretty fast, it became slow with more than 40 palettes. But you are right, using a pre-calculated color table for each palette would be the faster way.
I am sure a fade-in / fade-out function could also be done a lot faster in ASM - but that is still beyond my capabilities ...
Posté le 25/01/2016 à 15:08Edité par HPMAN le 26/01/2016 à 17:37 Membre depuis le 28/01/2003, 160 messages
This should provide the same results with less ressources?

Quick write up, might be errors in there, but you get the idea anyway...
typedef struct palette_t
{
	short RGB63_red, RGB63_green, RGB63_blue;
} palette_t;



#include <video.h>
#include <input.h>
#include <DATlib.h>
#include "fade_palettes.h"

struct palette_t color[256];

// FADE OUT //////////////////////////////////////////////////////////////////

void fade_out()
{
	int palette_no = 0; // first palette to start with
	int i;
	int steps=0;
	palette_t *c;
	short original_color, index, stepping;
	
	palette_no<<=5;
	stepping=-4;

	waitVBlank();

	for(i=0; i<256; i++)
	{
		if(!(i&0xf)) continue;	//meh, worth?
		c=&color[i];
		
		// save original palettes and calculate hex values for index bits and each color //

		original_color  = volMEMWORD(0x400000+i+i+palette_no);  // 4194304 decimal = 0x400000 hex adress of color 0 of palette 0

		// convert to RGB63 ///////////////////////////////////////////////

		c->RGB63_blue	= ((original_color&0x000f)<<2) + ((original_color&0x1000)?2:0);
		c->RGB63_green	= ((original_color&0x00f0)>>2) + ((original_color&0x2000)?2:0);
		c->RGB63_red	= ((original_color&0x0f00)>>6) + ((original_color&0x4000)?2:0);
		if(!(original_color&0x8000)) {c->RGB63_blue++;c->RGB63_green++;c->RGB63_red++;}

		// copy ASM Hex Color Code values to temporary variables ///////////
	}

	while(1)
	{
		waitVBlank();

		steps+=stepping;

		for(i=0; i<256; i++)
		{
			if(!(i&0xf)) continue;	//meh, worth?
			c=&color[i];

			// add steps to RGB63 temporary values /////////////////////////

			c->RGB63_blue += stepping;
			c->RGB63_green += stepping;
			c->RGB63_red += stepping;

			// keep values inside the range of 0 to 63 /////////////////////

			if(c->RGB63_blue>63) c->RGB63_blue=63;
			else if(c->RGB63_blue<0) c->RGB63_blue=0;
			if(c->RGB63_green>63) c->RGB63_green=63;
			else if(c->RGB63_green<0) c->RGB63_green=0;
			if(c->RGB63_red>63) c->RGB63_red=63;
			else if(c->RGB63_red<0) c->RGB63_red=0;

			// convert RGB63 back to ASM Hex Color Code ////////////////////

			index=((c->RGB63_blue&0x2)>>1) + (c->RGB63_green&0x02) + ((c->RGB63_red&0x02)<<1) + (c->RGB63_blue&0x1?0:1);

			// write new ASM Hex Color Code to color adress ////////////////

			volMEMWORD(0x400000+i+i+palette_no) = (index<<12)+((c->RGB63_red&0xfc)<<6)+((c->RGB63_green&0xfc)<<2)+(c->RGB63_blue>>2);
		}

		if(steps<=-64) break; // exit loop when done
	}
}
Posté le 26/01/2016 à 13:56 Membre depuis le 21/03/2014, 187 messages
Hi HPMAN,
thank you for your fade-out code, yours is much more efficient.
Because the code won't compile at first I have changed the following:

palette_t *c;
to
struct palette_t *c;

index=((c->RGB63_blue&0x2)>>1) + (RGB63_green&0x02) + ((RGB63_red&0x02)<<1) + (RGB63_blue&0x1?0:1);
to
index=((c->RGB63_blue&0x2)>>1) + (c->RGB63_green&0x02) + ((c->RGB63_red&0x02)<<1) + (c->RGB63_blue&0x1?0:1);

After that I was able to run it and the fade effect was ultra fast, that's why I have added 4 x waitVBlank(); into the second "for" loop to be able to see what happens.
It seems that the colors are directly set to black without steps in between - maybe that is caused by my changes? Could please have a second look on the code?

Here is a video of it:
Posté le 26/01/2016 à 16:44 Membre depuis le 28/01/2003, 160 messages
Slight syntax issue, edited code

c->RGB63_blue = ((original_color&0x000f)<<2) + (index&0x1000)?2:0;
to
c->RGB63_blue = ((original_color&0x000f)<<2) + ((index&0x1000)?2:0);

Should work fine now.


Watch job timing, updating colors during active display will issue rogue pixels on screen.
Posté le 27/01/2016 à 16:07 Membre depuis le 21/03/2014, 187 messages
Hi HPMAN,

thanks again for your byte shifting and pointer magic - the "fade-out" function works now perfectly magic

I have edited your code for a "fade-in" function which is also working but after "fading-out" at first and then "fading-in", the palette colors are changed slightly.
I have tried my best to find out the reason for that but I am stucked and can't find the error - do you please may have a suggestion for me?

before fading vs. after fading
palette-difference.png

Here is the latest code:

struct palette_t
{
	short RGB63_red, RGB63_green, RGB63_blue;
	short RGB63_red_temp, RGB63_green_temp, RGB63_blue_temp;
};

#include <video.h>
#include <input.h>
#include <DATlib.h>
#include "fade_palettes.h"
#include "fixlayer/fixData.h"
#include "externs.h"

struct palette_t color[256];


void fade_in()
{
	int palette_no = 0; // first palette to start with
	int i;
	int steps=0;
	struct palette_t *c;
	short original_color, index, stepping;

	palette_no<<=5;
	stepping=-1;

	waitVBlank();

	for(i=0; i<256; i++)
		{
			if(!(i&0xf)) continue;	//meh, worth?
			c=&color[i];

			// calculate original index for each color //

			original_color  = volMEMWORD(0x400000+i+i+palette_no);
			index = original_color&0xf000;

			// convert to RGB63 ///////////////////////////////////////////////

			c->RGB63_blue   = ((original_color&0x000f)<<2) + ((index&0x1000)?2:0);
			c->RGB63_green	= ((original_color&0x00f0)>>2) + ((index&0x2000)?2:0);
			c->RGB63_red	= ((original_color&0x0f00)>>6) + ((index&0x4000)?2:0);
			if(!(index&0x8000)) {c->RGB63_blue++;c->RGB63_green++;c->RGB63_red++;}

			// copy RGB63 values to temporary variables ///////////

			c->RGB63_blue_temp   = c->RGB63_blue;
			c->RGB63_green_temp  = c->RGB63_green;
			c->RGB63_red_temp    = c->RGB63_red;
		}

		// fade-out //////////////////////////////////////////////////////////////////////
		
		while(1)
		{
			waitVBlank();
			steps+=stepping;

			for(i=0; i<256; i++)
			{
				if(!(i&0xf)) continue;	//meh, worth?
				c=&color[i];

				// add steps to RGB63 values /////////////////////////

				c->RGB63_blue += stepping;
				c->RGB63_green += stepping;
				c->RGB63_red += stepping;

				c->RGB63_blue_temp += stepping;
				c->RGB63_green_temp += stepping;
				c->RGB63_red_temp += stepping;

				// keep values inside the range of 0 to 63 /////////////////////

				if(c->RGB63_blue>63) c->RGB63_blue=63;
				else if(c->RGB63_blue<0) c->RGB63_blue=0;
				if(c->RGB63_green>63) c->RGB63_green=63;
				else if(c->RGB63_green<0) c->RGB63_green=0;
				if(c->RGB63_red>63) c->RGB63_red=63;
				else if(c->RGB63_red<0) c->RGB63_red=0;

				// convert RGB63 back to ASM Hex Color Code ////////////////////

				index=((c->RGB63_blue&0x2)>>1) + (c->RGB63_green&0x02) + ((c->RGB63_red&0x02)<<1) + (c->RGB63_blue&0x1?0:1);

				// write new ASM Hex Color Code to color adress ////////////////

				volMEMWORD(0x400000+i+i+palette_no) = (index<<12)+((c->RGB63_red&0xfc)<<6)+((c->RGB63_green&0xfc)<<2)+(c->RGB63_blue>>2);
			}

			// fixPrintf(2,27,1,3,"steps %04d", steps);
			if(steps==-64) break; // exit loop when done

		}

		// fade-in ////////////////////////////////////////////////////////////////////////////
		
		while(1)
		{
			waitVBlank();
			steps-=stepping;

			for(i=0; i<256; i++)
			{
				if(!(i&0xf)) continue;	//meh, worth?
				c=&color[i];

				// add steps to RGB63 temporary values /////////////////////////

				c->RGB63_blue_temp -= stepping;
				c->RGB63_green_temp -= stepping;
				c->RGB63_red_temp -= stepping;

				c->RGB63_blue   = c->RGB63_blue_temp;
				c->RGB63_green  = c->RGB63_green_temp;
				c->RGB63_red    = c->RGB63_red_temp;

				// keep values inside the range of 0 to 63 /////////////////////

				if(c->RGB63_blue>63) c->RGB63_blue=63;
				else if(c->RGB63_blue<0) c->RGB63_blue=0;
				if(c->RGB63_green>63) c->RGB63_green=63;
				else if(c->RGB63_green<0) c->RGB63_green=0;
				if(c->RGB63_red>63) c->RGB63_red=63;
				else if(c->RGB63_red<0) c->RGB63_red=0;

				// convert RGB63 back to ASM Hex Color Code ////////////////////

				index=((c->RGB63_blue&0x2)>>1) + (c->RGB63_green&0x02) + ((c->RGB63_red&0x02)<<1) + (c->RGB63_blue&0x1?0:1);

				// write new ASM Hex Color Code to color adress ////////////////

				volMEMWORD(0x400000+i+i+palette_no) = (index<<12)+((c->RGB63_red&0xfc)<<6)+((c->RGB63_green&0xfc)<<2)+(c->RGB63_blue>>2);
			}

			// fixPrintf(2,27,1,3,"steps %04d", steps);
			if(steps==0) break; // exit loop when done
		}
}
Posté le 02/02/2016 à 01:21 Membre depuis le 28/01/2003, 160 messages
That's an issue with dark bit being approximated, with blue value only.

Can fix it by restoring exact values in last step:
typedef struct palette_t
{
	short RGB63_red, RGB63_green, RGB63_blue;
	short RGB63_original_red, RGB63_original_green, RGB63_original_blue;
	short original_color;
} palette_t;

// FADE OUT //////////////////////////////////////////////////////////////////

void fade_out()
{
	int palette_no = 16; // first palette to start with
	int i;
	int steps=0;
	palette_t *c;
	palette_t color[256];
	short hexColor, index, stepping;
	short *palRAMptr;
	
	palette_no<<=5;
	stepping=-4;

	waitVBlank();

	palRAMptr=(short*)(0x400000+palette_no);
	for(i=0; i<256; i++)
	{
		if(!(i&0xf)) {palRAMptr++;continue;}
		c=&color[i];
		
		// save original palettes and calculate hex values for index bits and each color //

		hexColor  = *palRAMptr++;

		// convert to RGB63 ///////////////////////////////////////////////

		c->RGB63_blue	= ((hexColor&0x000f)<<2) + ((hexColor&0x1000)?2:0);
		c->RGB63_green	= ((hexColor&0x00f0)>>2) + ((hexColor&0x2000)?2:0);
		c->RGB63_red	= ((hexColor&0x0f00)>>6) + ((hexColor&0x4000)?2:0);
		if(!(hexColor&0x8000)) {c->RGB63_blue++;c->RGB63_green++;c->RGB63_red++;}

		c->RGB63_original_blue	= c->RGB63_blue;
		c->RGB63_original_green	= c->RGB63_green;
		c->RGB63_original_red	= c->RGB63_red;
		c->original_color = hexColor;
	}

	while(1)
	{
		waitVBlank();

		steps+=stepping;
		palRAMptr=(short*)(0x400000+palette_no);

		for(i=0; i<256; i++)
		{
			if(!(i&0xf)) {palRAMptr++;continue;}
			c=&color[i];

			// add steps to RGB63 temporary values /////////////////////////

			c->RGB63_blue += stepping;
			c->RGB63_green += stepping;
			c->RGB63_red += stepping;

			// keep values inside the range of 0 to 63 /////////////////////

			if(c->RGB63_blue>63) c->RGB63_blue=63;
			else if(c->RGB63_blue<0) c->RGB63_blue=0;
			if(c->RGB63_green>63) c->RGB63_green=63;
			else if(c->RGB63_green<0) c->RGB63_green=0;
			if(c->RGB63_red>63) c->RGB63_red=63;
			else if(c->RGB63_red<0) c->RGB63_red=0;

			// convert RGB63 back to ASM Hex Color Code ////////////////////

			index=((c->RGB63_blue&0x2)>>1) + (c->RGB63_green&0x02) + ((c->RGB63_red&0x02)<<1) + (c->RGB63_blue&0x1?0:1);

			// write new ASM Hex Color Code to color adress ////////////////

			*palRAMptr++ = (index<<12)+((c->RGB63_red&0xfc)<<6)+((c->RGB63_green&0xfc)<<2)+(c->RGB63_blue>>2);
		}

		if(steps<=-64) break; // exit loop when done
	}
	
	//fade in
	steps=64;
	while(1) {
		waitVBlank();

		steps+=stepping;
		
		palRAMptr=(short*)(0x400000+palette_no);
		for(i=0; i<256; i++)
		{
			if(!(i&0xf)) {palRAMptr++;continue;}
			c=&color[i];
			
			c->RGB63_blue	= c->RGB63_original_blue - steps;
			c->RGB63_green	= c->RGB63_original_green - steps;
			c->RGB63_red	= c->RGB63_original_red - steps;

			if(c->RGB63_blue>63) c->RGB63_blue=63;
			else if(c->RGB63_blue<0) c->RGB63_blue=0;
			if(c->RGB63_green>63) c->RGB63_green=63;
			else if(c->RGB63_green<0) c->RGB63_green=0;
			if(c->RGB63_red>63) c->RGB63_red=63;
			else if(c->RGB63_red<0) c->RGB63_red=0;

			index=((c->RGB63_blue&0x2)>>1) + (c->RGB63_green&0x02) + ((c->RGB63_red&0x02)<<1) + (c->RGB63_blue&0x1?0:1);

			*palRAMptr++ = (index<<12)+((c->RGB63_red&0xfc)<<6)+((c->RGB63_green&0xfc)<<2)+(c->RGB63_blue>>2);
		}
		if(steps<=0-stepping) break; // exit loop before last step
	}

	//restore exact values as last step
	palRAMptr=(short*)(0x400000+palette_no);
	for(i=0; i<256; i++)
	{
		if(!(i&0xf)) {palRAMptr++;continue;}
		*palRAMptr++ = color[i].original_color;
	}

}

That's still terrible tho, updating 16 palettes takes about 65% of a frame CPU time, meaning pixels will be all around the screen when running this on real hardware, plus you are locked out to do anything else meaningful.
Posté le 02/02/2016 à 11:57 Membre depuis le 07/07/2015, 117 messages
never ever write to palette-ram during display is activ or you will get some glitches (random white pixels) on real hardware... this is not vissible in MAME.
calculate palette fadings in realtime is possible but costs a lot of cpu-time (especially using all 15bit). I'm using precalculated tables to fade to black or white or crossfading between two palettes or greyscale a palette (for gameover!?). it's easier and faster, use more entries to fade slower or less entries to speed up... and rom-space is no problem.

=> 16 palettes using 32 steps = 16kbyte (16384byte)

but it's possible to update 2 or 3 colors during HSYNC (using Timer interrupt ) to create and rainbow-effect or fadein/out-effect for a vertical scoller.
Posté le 02/02/2016 à 16:10 Membre depuis le 21/03/2014, 187 messages
I have made a real hardware test today (which was long overdue) and was sad because both of you are right - my original code doesn't work, only randomly spreaded pixels everywhere and no fading was visible.
Your code HPMAN (thank you for your time to develop it), is fading in & out the palettes perfectly but as you wrote already, there are also randomly spreaded pixels visible. I have reduced the amount of colors to fade down to 48 (only 3 palettes)
to save calculation time, as a result, the spreading pixels problem was also reduced but still visible on the top of the screen. It seems that there is no "lazy" method for fading colors without pre-calculation due to hardware limitations.

Blastar, your color pre-calculed fades are very nice, do you use some kind for a tool for it or did you have made them manually with your NGFX palette tool?
Posté le 02/02/2016 à 20:20 Membre depuis le 07/07/2015, 117 messages
NeoHomeBrew, this is a small additional tool. just load (or drop) two palettes in binary-format (ngpal) and choose how many steps you want. output is asm-include (dc.w $0000...). what output format do you prefer?
Posté le 03/02/2016 à 00:01 Membre depuis le 21/03/2014, 187 messages
Wow, that sounds like a very useful and time-saving tool, I would be happy if you would release it (if there is something I could do for you in exchange please let me know).
Because I am working with the C dev kit, an output like the following would be fantastic:
const int fade_colors[] =
{
	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // step 1 
	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // step 2 
};
Posté le 03/02/2016 à 02:16 Membre depuis le 07/07/2015, 117 messages
NeoHomeBrew, please check if this output is correct because i never used anything other than ASM with neogeo.
what is the correct file-extension and -discription?

test_2_o.png
const int fade_colors[] =
{
	0x0000, 0x40AF, 0x22BF, 0x54EF, 0x3400, 0x5510, 0x7910, 0x5C20, 0x5F30, 0x4F51, 0x4F62, 0x6F84, 0x7FA4, 0x4FD6, 0x4FF7, 0x7FFF,  // step 1
	0x0000, 0x709E, 0x12BE, 0x64DF, 0x3400, 0x5510, 0x3910, 0x1C20, 0x1F30, 0x0F51, 0x0F62, 0x0F84, 0x1FA4, 0x2FC6, 0x2FE7, 0x0FFF,  // step 2
	0x0000, 0x609E, 0x02BE, 0x14DE, 0x7300, 0x1510, 0x3910, 0x5B20, 0x5E30, 0x6E41, 0x6E52, 0x5E83, 0x4EA4, 0x5EC5, 0x5EE6, 0x7EEE,  // step 3
	0x0000, 0x509D, 0x32AD, 0x24CE, 0x7300, 0x1510, 0x7810, 0x5B20, 0x3E20, 0x2E41, 0x2E52, 0x3E73, 0x2E94, 0x3EB5, 0x3ED6, 0x0EEE,  // step 4
	0x0000, 0x608D, 0x41AD, 0x14CD, 0x7300, 0x1510, 0x7810, 0x3B10, 0x7D20, 0x6D41, 0x5D51, 0x7D73, 0x4D94, 0x6DB5, 0x4DD6, 0x7DDD,  // step 5
	0x0000, 0x708C, 0x719C, 0x24BD, 0x7300, 0x5410, 0x3810, 0x7A10, 0x3D20, 0x0D41, 0x1D51, 0x1D73, 0x0D94, 0x0DB5, 0x2DC6, 0x0DDD,  // step 6
	0x0000, 0x408C, 0x619C, 0x73BC, 0x3300, 0x5410, 0x5710, 0x3A10, 0x7C20, 0x4C41, 0x5C51, 0x4C73, 0x7C83, 0x6CA5, 0x5CC5, 0x7CCC,  // step 7
	0x0000, 0x707B, 0x519B, 0x43BC, 0x3300, 0x5410, 0x5710, 0x7910, 0x3C20, 0x0C41, 0x3C41, 0x2C63, 0x1C83, 0x1CA4, 0x3CB5, 0x0CCC,  // step 8
	0x0000, 0x607B, 0x618B, 0x73AB, 0x3300, 0x3400, 0x1710, 0x7910, 0x5B20, 0x7B30, 0x7B41, 0x6B63, 0x5B83, 0x7B94, 0x4BB5, 0x7BBB,  // step 9
	0x0000, 0x507A, 0x518A, 0x03AB, 0x3300, 0x3400, 0x5610, 0x3910, 0x1B20, 0x3B30, 0x3B41, 0x0B63, 0x2B73, 0x1B94, 0x2BA5, 0x0BBB,  // step 10
	0x0000, 0x407A, 0x418A, 0x339A, 0x7200, 0x7300, 0x5610, 0x7810, 0x5A20, 0x7A30, 0x5A41, 0x5A62, 0x4A73, 0x4A94, 0x5AA4, 0x7AAA,  // step 11
	0x0000, 0x7069, 0x7179, 0x039A, 0x7200, 0x7300, 0x1610, 0x3810, 0x1A20, 0x1A30, 0x1A41, 0x3A52, 0x0A73, 0x2A84, 0x3A94, 0x0AAA,  // step 12
	0x0000, 0x4069, 0x0179, 0x3389, 0x7200, 0x7300, 0x1610, 0x5710, 0x5920, 0x5930, 0x6931, 0x5952, 0x6963, 0x5983, 0x5994, 0x7999,  // step 13
	0x0000, 0x5068, 0x3168, 0x4289, 0x7200, 0x3300, 0x5510, 0x5710, 0x3910, 0x1930, 0x2931, 0x1952, 0x1962, 0x3973, 0x2984, 0x0999,  // step 14
	0x0000, 0x6058, 0x2168, 0x7278, 0x3200, 0x3300, 0x1510, 0x1710, 0x7810, 0x7820, 0x6831, 0x6842, 0x5862, 0x5873, 0x4884, 0x7888,  // step 15
	0x0000, 0x5057, 0x1167, 0x4278, 0x3200, 0x3300, 0x1510, 0x5610, 0x3810, 0x3820, 0x0831, 0x2842, 0x3852, 0x2863, 0x3873, 0x0888,  // step 16
	0x0000, 0x1057, 0x3157, 0x1277, 0x0200, 0x6200, 0x6400, 0x0610, 0x6710, 0x7720, 0x4731, 0x4742, 0x4752, 0x6763, 0x7773, 0x7777,  // step 17
	0x0000, 0x2047, 0x0157, 0x2267, 0x0200, 0x6200, 0x6400, 0x4510, 0x2710, 0x3720, 0x2721, 0x0742, 0x2742, 0x1762, 0x0773, 0x0777,  // step 18
	0x0000, 0x1046, 0x1156, 0x1266, 0x4100, 0x6200, 0x2400, 0x0510, 0x6610, 0x5620, 0x6621, 0x7631, 0x6642, 0x7652, 0x6663, 0x7666,  // step 19
	0x0000, 0x0046, 0x2146, 0x6156, 0x4100, 0x2200, 0x6300, 0x0510, 0x0610, 0x1620, 0x2621, 0x3631, 0x1641, 0x1652, 0x1662, 0x0666,  // step 20
	0x0000, 0x3035, 0x5045, 0x5155, 0x4100, 0x2200, 0x6300, 0x6400, 0x4510, 0x5520, 0x5520, 0x5531, 0x7531, 0x6542, 0x7552, 0x7555,  // step 21
	0x0000, 0x0035, 0x6035, 0x6145, 0x4100, 0x2200, 0x2300, 0x2400, 0x0510, 0x3510, 0x1520, 0x3521, 0x3531, 0x0542, 0x1552, 0x0555,  // step 22
	0x0000, 0x1034, 0x7034, 0x5144, 0x0100, 0x6100, 0x2300, 0x6300, 0x4410, 0x7410, 0x7410, 0x6421, 0x5431, 0x5441, 0x6442, 0x7444,  // step 23
	0x0000, 0x2024, 0x4034, 0x2134, 0x0100, 0x6100, 0x6200, 0x2300, 0x0410, 0x3410, 0x3410, 0x0421, 0x2421, 0x3431, 0x0442, 0x0444,  // step 24
	0x0000, 0x3023, 0x7023, 0x1133, 0x0100, 0x0100, 0x2200, 0x2300, 0x6300, 0x4310, 0x7310, 0x4321, 0x6321, 0x5331, 0x7331, 0x7333,  // step 25
	0x0000, 0x0023, 0x4023, 0x2123, 0x0100, 0x0100, 0x2200, 0x6200, 0x2300, 0x0310, 0x1310, 0x2311, 0x0321, 0x2321, 0x1331, 0x0333,  // step 26
	0x0000, 0x3012, 0x5022, 0x7022, 0x4000, 0x0100, 0x4100, 0x2200, 0x6200, 0x4210, 0x5210, 0x7210, 0x7210, 0x4221, 0x6221, 0x7222,  // step 27
	0x0000, 0x2012, 0x6012, 0x4022, 0x4000, 0x4000, 0x0100, 0x6100, 0x2200, 0x2200, 0x1210, 0x1210, 0x3210, 0x2211, 0x0221, 0x0222,  // step 28
	0x0000, 0x1011, 0x1011, 0x7011, 0x4000, 0x4000, 0x0100, 0x0100, 0x6100, 0x6100, 0x6100, 0x5110, 0x5110, 0x7110, 0x7110, 0x7111,  // step 29
	0x0000, 0x2001, 0x2001, 0x4011, 0x4000, 0x4000, 0x4000, 0x0100, 0x0100, 0x2100, 0x2100, 0x3100, 0x3100, 0x1110, 0x1110, 0x0111,  // step 30
	0x0000, 0x3000, 0x3000, 0x3000, 0x0000, 0x0000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x6000, 0x6000, 0x6000, 0x6000, 0x7000,  // step 31
	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,  // step 32
};
Posté le 03/02/2016 à 18:02 Membre depuis le 21/03/2014, 187 messages
Hi Blastar,

thank you - your color codes array works perfectly! It has been verfied to work on the real system without any graphical errors (with 16 palettes/256 colors) cool
I would suggest to output the array into a "output.c" file or just a simple "output.txt" file. The array has to be copied into the source code anyway (which is not a big deal in my opinion).
Except HPMAN has maybe a better idea for a global include with external access?



Here is the C code of the fading demo in the video:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <task.h>
#include <input.h>
#include <DATlib.h>
#include <math.h>
#include "externs.h"
#include "fixData.h"

typedef struct bkp_ram_info {WORD debug_dips; BYTE stuff[254];}	// 256 bytes backup block
bkp_ram_info;
bkp_ram_info bkp_data;

BYTE p1,p2,ps,p1e,p2e;

// pre-calculated palettes ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

const int fade_colors[] =
{
	0x0000, 0x40AF, 0x22BF, 0x54EF, 0x3400, 0x5510, 0x7910, 0x5C20, 0x5F30, 0x4F51, 0x4F62, 0x6F84, 0x7FA4, 0x4FD6, 0x4FF7, 0x7FFF,  // step 1
	0x0000, 0x709E, 0x12BE, 0x64DF, 0x3400, 0x5510, 0x3910, 0x1C20, 0x1F30, 0x0F51, 0x0F62, 0x0F84, 0x1FA4, 0x2FC6, 0x2FE7, 0x0FFF,  // step 2
	0x0000, 0x609E, 0x02BE, 0x14DE, 0x7300, 0x1510, 0x3910, 0x5B20, 0x5E30, 0x6E41, 0x6E52, 0x5E83, 0x4EA4, 0x5EC5, 0x5EE6, 0x7EEE,  // step 3
	0x0000, 0x509D, 0x32AD, 0x24CE, 0x7300, 0x1510, 0x7810, 0x5B20, 0x3E20, 0x2E41, 0x2E52, 0x3E73, 0x2E94, 0x3EB5, 0x3ED6, 0x0EEE,  // step 4
	0x0000, 0x608D, 0x41AD, 0x14CD, 0x7300, 0x1510, 0x7810, 0x3B10, 0x7D20, 0x6D41, 0x5D51, 0x7D73, 0x4D94, 0x6DB5, 0x4DD6, 0x7DDD,  // step 5
	0x0000, 0x708C, 0x719C, 0x24BD, 0x7300, 0x5410, 0x3810, 0x7A10, 0x3D20, 0x0D41, 0x1D51, 0x1D73, 0x0D94, 0x0DB5, 0x2DC6, 0x0DDD,  // step 6
	0x0000, 0x408C, 0x619C, 0x73BC, 0x3300, 0x5410, 0x5710, 0x3A10, 0x7C20, 0x4C41, 0x5C51, 0x4C73, 0x7C83, 0x6CA5, 0x5CC5, 0x7CCC,  // step 7
	0x0000, 0x707B, 0x519B, 0x43BC, 0x3300, 0x5410, 0x5710, 0x7910, 0x3C20, 0x0C41, 0x3C41, 0x2C63, 0x1C83, 0x1CA4, 0x3CB5, 0x0CCC,  // step 8
	0x0000, 0x607B, 0x618B, 0x73AB, 0x3300, 0x3400, 0x1710, 0x7910, 0x5B20, 0x7B30, 0x7B41, 0x6B63, 0x5B83, 0x7B94, 0x4BB5, 0x7BBB,  // step 9
	0x0000, 0x507A, 0x518A, 0x03AB, 0x3300, 0x3400, 0x5610, 0x3910, 0x1B20, 0x3B30, 0x3B41, 0x0B63, 0x2B73, 0x1B94, 0x2BA5, 0x0BBB,  // step 10
	0x0000, 0x407A, 0x418A, 0x339A, 0x7200, 0x7300, 0x5610, 0x7810, 0x5A20, 0x7A30, 0x5A41, 0x5A62, 0x4A73, 0x4A94, 0x5AA4, 0x7AAA,  // step 11
	0x0000, 0x7069, 0x7179, 0x039A, 0x7200, 0x7300, 0x1610, 0x3810, 0x1A20, 0x1A30, 0x1A41, 0x3A52, 0x0A73, 0x2A84, 0x3A94, 0x0AAA,  // step 12
	0x0000, 0x4069, 0x0179, 0x3389, 0x7200, 0x7300, 0x1610, 0x5710, 0x5920, 0x5930, 0x6931, 0x5952, 0x6963, 0x5983, 0x5994, 0x7999,  // step 13
	0x0000, 0x5068, 0x3168, 0x4289, 0x7200, 0x3300, 0x5510, 0x5710, 0x3910, 0x1930, 0x2931, 0x1952, 0x1962, 0x3973, 0x2984, 0x0999,  // step 14
	0x0000, 0x6058, 0x2168, 0x7278, 0x3200, 0x3300, 0x1510, 0x1710, 0x7810, 0x7820, 0x6831, 0x6842, 0x5862, 0x5873, 0x4884, 0x7888,  // step 15
	0x0000, 0x5057, 0x1167, 0x4278, 0x3200, 0x3300, 0x1510, 0x5610, 0x3810, 0x3820, 0x0831, 0x2842, 0x3852, 0x2863, 0x3873, 0x0888,  // step 16
	0x0000, 0x1057, 0x3157, 0x1277, 0x0200, 0x6200, 0x6400, 0x0610, 0x6710, 0x7720, 0x4731, 0x4742, 0x4752, 0x6763, 0x7773, 0x7777,  // step 17
	0x0000, 0x2047, 0x0157, 0x2267, 0x0200, 0x6200, 0x6400, 0x4510, 0x2710, 0x3720, 0x2721, 0x0742, 0x2742, 0x1762, 0x0773, 0x0777,  // step 18
	0x0000, 0x1046, 0x1156, 0x1266, 0x4100, 0x6200, 0x2400, 0x0510, 0x6610, 0x5620, 0x6621, 0x7631, 0x6642, 0x7652, 0x6663, 0x7666,  // step 19
	0x0000, 0x0046, 0x2146, 0x6156, 0x4100, 0x2200, 0x6300, 0x0510, 0x0610, 0x1620, 0x2621, 0x3631, 0x1641, 0x1652, 0x1662, 0x0666,  // step 20
	0x0000, 0x3035, 0x5045, 0x5155, 0x4100, 0x2200, 0x6300, 0x6400, 0x4510, 0x5520, 0x5520, 0x5531, 0x7531, 0x6542, 0x7552, 0x7555,  // step 21
	0x0000, 0x0035, 0x6035, 0x6145, 0x4100, 0x2200, 0x2300, 0x2400, 0x0510, 0x3510, 0x1520, 0x3521, 0x3531, 0x0542, 0x1552, 0x0555,  // step 22
	0x0000, 0x1034, 0x7034, 0x5144, 0x0100, 0x6100, 0x2300, 0x6300, 0x4410, 0x7410, 0x7410, 0x6421, 0x5431, 0x5441, 0x6442, 0x7444,  // step 23
	0x0000, 0x2024, 0x4034, 0x2134, 0x0100, 0x6100, 0x6200, 0x2300, 0x0410, 0x3410, 0x3410, 0x0421, 0x2421, 0x3431, 0x0442, 0x0444,  // step 24
	0x0000, 0x3023, 0x7023, 0x1133, 0x0100, 0x0100, 0x2200, 0x2300, 0x6300, 0x4310, 0x7310, 0x4321, 0x6321, 0x5331, 0x7331, 0x7333,  // step 25
	0x0000, 0x0023, 0x4023, 0x2123, 0x0100, 0x0100, 0x2200, 0x6200, 0x2300, 0x0310, 0x1310, 0x2311, 0x0321, 0x2321, 0x1331, 0x0333,  // step 26
	0x0000, 0x3012, 0x5022, 0x7022, 0x4000, 0x0100, 0x4100, 0x2200, 0x6200, 0x4210, 0x5210, 0x7210, 0x7210, 0x4221, 0x6221, 0x7222,  // step 27
	0x0000, 0x2012, 0x6012, 0x4022, 0x4000, 0x4000, 0x0100, 0x6100, 0x2200, 0x2200, 0x1210, 0x1210, 0x3210, 0x2211, 0x0221, 0x0222,  // step 28
	0x0000, 0x1011, 0x1011, 0x7011, 0x4000, 0x4000, 0x0100, 0x0100, 0x6100, 0x6100, 0x6100, 0x5110, 0x5110, 0x7110, 0x7110, 0x7111,  // step 29
	0x0000, 0x2001, 0x2001, 0x4011, 0x4000, 0x4000, 0x4000, 0x0100, 0x0100, 0x2100, 0x2100, 0x3100, 0x3100, 0x1110, 0x1110, 0x0111,  // step 30
	0x0000, 0x3000, 0x3000, 0x3000, 0x0000, 0x0000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x6000, 0x6000, 0x6000, 0x6000, 0x7000,  // step 31
	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,  // step 32
};

// main loop ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int main()
{
	int i=0, j=0;
	int palette_no=16, steps=0, fade_in=0, fade_out=0;

	picture test_palette_1, test_palette_2, test_palette_3, test_palette_4, test_palette_5, test_palette_6, test_palette_7, test_palette_8,
		test_palette_9, test_palette_10, test_palette_11, test_palette_12, test_palette_13, test_palette_14, test_palette_15, test_palette_16;

	volMEMWORD(0x401ffe)=0x3456; // BG color
	LSPCmode=0x900;

	initGfx();
	clearFixLayer();
	clearSprites(1, 381);

	palJobPut( 1, hypernoid_font_Palettes.palCount, hypernoid_font_Palettes.data); // fix layer palette

	pictureInit(&test_palette_1, &test_palette,    0, 16, 32, 20, FLIP_NONE);
	palJobPut(16, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_2, &test_palette,   16, 17, 32, 30, FLIP_NONE);
	palJobPut(17, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_3, &test_palette,   32, 18, 32, 40, FLIP_NONE);
	palJobPut(18, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_4, &test_palette,   48, 19, 32, 50, FLIP_NONE);
	palJobPut(19, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_5, &test_palette,   64, 20, 32, 60, FLIP_NONE);
	palJobPut(20, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_6, &test_palette,   80, 21, 32, 70, FLIP_NONE);
	palJobPut(21, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_7, &test_palette,   96, 22, 32, 80, FLIP_NONE);
	palJobPut(22, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_8, &test_palette,  112, 23, 32, 90, FLIP_NONE);
	palJobPut(23, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_9, &test_palette,  128, 24, 32, 100, FLIP_NONE);
	palJobPut(24, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_10, &test_palette, 144, 25, 32, 110, FLIP_NONE);
	palJobPut(25, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_11, &test_palette, 160, 26, 32, 120, FLIP_NONE);
	palJobPut(26, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_12, &test_palette, 176, 27, 32, 130, FLIP_NONE);
	palJobPut(27, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_13, &test_palette, 192, 28, 32, 140, FLIP_NONE);
	palJobPut(28, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_14, &test_palette, 208, 29, 32, 150, FLIP_NONE);
	palJobPut(29, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_15, &test_palette, 224, 30, 32, 160, FLIP_NONE);
	palJobPut(30, test_palette_Palettes.palCount, test_palette_Palettes.data);

	pictureInit(&test_palette_16, &test_palette, 240, 31, 32, 170, FLIP_NONE);
	palJobPut(31, test_palette_Palettes.palCount, test_palette_Palettes.data);

	SCClose();

	while(1)
	{
		waitVBlank();

		p1=volMEMBYTE(P1_CURRENT);
		ps=volMEMBYTE(PS_CURRENT);

		// manual steps ////////////////////////////////////

		if(p1&JOY_UP) if(steps<32) steps+=1;
		if(p1&JOY_DOWN) if(steps>0) steps-=1;

		// auto steps //////////////////////////////////////

		if(p1&JOY_A) fade_out=1;
		if(p1&JOY_B) fade_in=1;

		if(fade_out==1)
		{
			if(steps<32) steps+=1;
			if(steps==32) fade_out=0;
		}

		if(fade_in==1)
		{
			if(steps>0) steps-=1;
			if(steps==0) fade_in=0;
		}

		// change palette colors ////////////////////////////

		if(steps>0 && steps<32)
		{
			for (j=0; j<16; j++) // j = how many palettes to fade
    		        {
				for(i=0; i<16; i++) // i = how many colors of each palette
				{
					volMEMWORD(0x400000+i+i+(palette_no*32)) = fade_colors[i+(steps*16)];
				}

				palette_no+=1;  // move to next palette
			}

			palette_no=16; // reset to first palette when done
		}

		fixPrintf(13, 3,1,3,"FADE STEPS: %03d", steps);

	        if(p1&JOY_D) break; // restart while loop

	} // end of while loop
} // end of main loop

Posté le 03/02/2016 à 18:52 Membre depuis le 28/01/2003, 160 messages
use an external asm file to hold data, then import it
extern short fade_data[0];

Then use palette macros in code to ensure it's vsynced
if(steps>0 && steps<32)
{
	for (j=0; j<16; j++) // j = how many palettes to fade
	{
		palJobPut(palette_no++,1,&fade_data[steps<<4]);
	}
	palette_no=16; // reset to first palette when done
}
Posté le 03/02/2016 à 23:16 Membre depuis le 07/07/2015, 117 messages
ok, I will integrate 3 options for saving: asm (dc.w $0000,..), c (0x000,...) & byteswapped binary (like ngpal).
Posté le 04/02/2016 à 10:26 Membre depuis le 21/03/2014, 187 messages
THX @ HPMAN - will try to implement this code
THX @ BLASTAR - having all this three options woud be great
Posté le 05/02/2016 à 18:11 Membre depuis le 07/07/2015, 117 messages
NeoHomeBrew, check my Blog.
I also added an option to switch graphical output to 'real NeoGeo colors' so you are able create (and export) some nice (DATlib compatible) gradients for use with the GFX-programm of your choice...
Posté le 06/02/2016 à 00:03 Membre depuis le 21/03/2014, 187 messages
Great, thank you a lot for your work Blastar smile I have played around with the ColorFade tool already and it looks very promising.
Will use it in the next days to generate fade tables for my intro screen and highscore list and will tell you how it works out for me.

There are three things which came to my mind while checking out your tool:
1.) What do you think about adding the "Palette Editor" from NGFX also to the ColorFade tool? It would be nice to have the option
to change/edit the source colors (Palette 1 TOP) and target colors (Palette 2 BOTTOM) manually.
2.) Could you may show the ASM color codes which are used for Palette 1 and Palette 2 inside of the program (maybe in a box at the bottom? )
3.) Would it be possible to import a palette by "scanning" the colors out of a .png image file (which is already reduced to 16 colors)?
Posté le 06/02/2016 à 15:43 Membre depuis le 07/07/2015, 117 messages
the palette editor is far more complex than the fading tool but it's no big deal to integrate this.
in the palette editor you can see the asm-values, no need for other boxes.
I also added an 'import colors from image ' option but the sorting could be different... you can swap colors in the palette editor with drag and drop. if you exported an image in NGFX with 'real colors' enabled you have to enable this also in the fading-tool (its disabled by default) before you import your image or you will get wrong color-values...
Posté le 08/02/2016 à 14:56 Membre depuis le 21/03/2014, 187 messages
Hi Blastar,
thank you for the latest additions to your ColorFade-Calculator. I have spent the last weekend to test your tool.
Importing the palette colors via png images hasn't worked that well for me because DATlib uses its very own algorithm to generate the palettes
out of the images and I got divergent results regarding to the color codes and the position of these codes inside of the palette.
That's why I end up to use your format and to set up a .ngpal manually inside NGFX at first. DATlib saves the palettes in 0x0000 format
in a palettes.s file and I have copied the values one by one into the palette editor and then I have saved the palette.
After that, I opened the .ngpal inside the ColorFade-Calculator and was able to setup and to export fade tables with ease king.
The results looks excellent, I have added a short video below.

I have three more suggestions:
1.) Would it be possible to bulk-import 16 color codes at the same time (maybe divided by commas inside a .txt file)?
2.) Could you please add a "save .ngpal" option also to the ColorFade-Calculator?
3.) Are you maybe in the mood to add the option to have a "clean fade" (maybe only when fading to black or to white), that means
that there are all three RGB63 values increased / reduced by 1 each step? I know this would cause colors which are nearer to
the target (0000 or FFFF) to diappear earlier and you wouldn't be that free in selecting the amount of steps but it would fade the
colors much "cleaner" without jumping around slightly from green to blue or to red.

Posté le 13/02/2016 à 17:10 Membre depuis le 07/07/2015, 117 messages
it's done.
- save palettes (ngpal, asm, c)
- import palettes from text files ($0000, 0x0000..)
- full dark bit support (disabled by default)
- added simple fading (disabled by default)
please remember, neogeo is 15bit + dark bit ... it's NOT RGB63!!! the darkbit is now optional(!) supported but will sometimes look strange! use it with care...
Posté le 14/02/2016 à 19:17 Membre depuis le 21/03/2014, 187 messages
Hi Blastar,

whoa - what a great update, thanks a lot for your work! The "Simple Fade Mode" with activated Dark Bit generates outstanding results!
The color steps in between are nice & clean and the effect looks much more 'dramatic' in my eyes than before thanks to the earlier
disappearing of the darker colors (when fading to black). Importing colors via .txt file and saving the imported palette is working
perfectly and saves a lot of time. It is a great tool now, nothing more to improve from my side sun

Here is the fade demo again, this time with the new Simple Fade Mode + activated Dark Bit:

Posté le 12/04/2017 à 12:21 Membre depuis le 13/08/2014, 17 messages
Guys can u provide a little tutorial for Datlib user on how to make a fade palette effect with pre-calculated support of NGFX-Calculator?

thx
Posté le 19/04/2017 à 03:06 Membre depuis le 21/03/2014, 187 messages
Hi Black_Jack,

1.) Copy the palette of your graphic from the palettes.s file (should be 16 words in hexdecimal, separated with comma) and save it in a blank .txt file
For example: 0x8000, 0x4311, 0xaca7, 0x2973, 0xceec, 0xffff, 0x2742, 0x7531, 0x8443, 0x7776, 0xe888, 0x8aa9, 0xc454, 0x7bba, 0xf665, 0xf554
2.) Open this .txt file with NGFX ColorFade-Calculator by selecting Palette 1 (Top) > Import from file...
3.) Adjust amount of fading steps by changing the Count: 3-256 value (I have used 62 steps)
4.) Optional: Change the fade style to "simple fade" by selecting Settings > Simple fade
5.) Save it as .c file by selecting File>Save as.. and file type "C-Output (*.c)"
6.) This file should contain an array with the values of the fading steps: const int fade_colors[] ={your palette values};
7.) Add this array to your code and build a function to change the color values in a while loop.

I have made it like in the following code for 4 palettes (of 4 different graphics) in the same array named "ranking_colors" (palette numbers 4, 5, 6,7) with 62 steps for each palette:

void fade_palettes(short style)
{
	short i=0, j=0;
	short palette_no=4, steps=0, array_step=0;

	if(style==FADE_IN) steps=63;

	while(1)
	{
		waitVBlank();

		if(style==FADE_OUT)
		{
			steps+=1;
		}

		if(style==FADE_IN)
		{
			steps-=1;
		}

		// change palette colors

		if(steps>0 && steps<62)
		{
			for (j=4; j<8; j++) // j = how many palettes to fade
    		        {
				for(i=0; i<16; i++) // i = how many colors of each palette
				{
					volMEMWORD(0x400000+i+i+(palette_no*32)) = ranking_colors[(i+((steps-1)*16))+array_step];
				}

				palette_no+=1; // move to next palette
				array_step+=992; // 62 steps x 16 colors - move to next array color position
			}

			palette_no=4; // reset to first palette when done
			array_step=0; // reset to first array step when done
		}

		// fixPrintf(13, 3,1,3,"FADE STEPS: %03d", steps);

		// exit loop when done
		if(style==FADE_OUT && steps>=63) break;
		if(style==FADE_IN && steps<=0) break;
	}
}

This is how the array looks like in this example (showing only the first 3 steps to keep this post short):

const short ranking_colors[] =
{
	// FixFont
	0x8000, 0x0222, 0x0333, 0xC911, 0x20F0, 0x6FF0, 0x4F00, 0x100F, 0x30FF, 0x8000, 0x0C81, 0x0D91, 0xAE91, 0x2FA1, 0x9FC1, 0x4FD1,  // step 1
	0x8000, 0x8222, 0x8333, 0x3900, 0xA0F0, 0xEFF0, 0xCF00, 0x900F, 0xB0FF, 0x8000, 0x8C81, 0x8D91, 0x5D90, 0xAFA1, 0x6EB1, 0xCFD1,  // step 2
	0x8000, 0x7111, 0x7222, 0xB900, 0x00F0, 0x0FF0, 0x0F00, 0x000F, 0x00FF, 0x8000, 0x7B70, 0x7C80, 0xDD90, 0x5EA0, 0xEEB1, 0x3FC0,  // step 3
	... up to step 62

	// ranking_bg (inside box)
	0x8000, 0x6111, 0x0221, 0xE111, 0x3321, 0xD221, 0xC332, 0xA432, 0x2432, 0x5442, 0xA543, 0x4553, 0x9653, 0xF653, 0x7653, 0x9763,  // step 1
	0x8000, 0xE111, 0x8221, 0x1110, 0xB321, 0x2211, 0x3321, 0x5331, 0xA432, 0xD442, 0x5442, 0xC553, 0x6543, 0x0653, 0xF653, 0x6653,  // step 2
	0x8000, 0x1110, 0x7110, 0x9110, 0x4221, 0xA211, 0xB321, 0xD331, 0x5331, 0x2432, 0xD442, 0x3542, 0xE543, 0x8653, 0x0653, 0xE653,  // step 3
	... up to step 62

	// ranking_frame
	0x8000, 0x4311, 0xACA7, 0x2973, 0xCEEC, 0xFFFF, 0x2742, 0x7531, 0x8443, 0x7776, 0xE888, 0x8AA9, 0xC454, 0x7BBA, 0xF665, 0xF554,  // step 1
	0x8000, 0xC311, 0x5BA6, 0xA973, 0x3EDB, 0x0FFF, 0xA742, 0xF531, 0x7332, 0xF776, 0x1887, 0x7998, 0x3443, 0xFBBA, 0x0665, 0x0554,  // step 2
	0x8000, 0x3300, 0xDBA6, 0x5872, 0xBEDB, 0x8FFF, 0x5641, 0x0531, 0xF332, 0x0776, 0x9887, 0xF998, 0xB443, 0x0BBA, 0x8665, 0x8554,  // step 3
	... up to step 62

	// ranking screen background (behind box)
	0x8000, 0xF000, 0x5010, 0x2111, 0x8111, 0xD121, 0xF343, 0x0232, 0xA222, 0x5121, 0x8343, 0x7232, 0x0343, 0x7343, 0x8000, 0x8000,  // step 1
	0x8000, 0x8000, 0xD010, 0xA111, 0x7000, 0x2111, 0x0343, 0x8232, 0x5121, 0xD121, 0x7232, 0xF232, 0x8343, 0xF343, 0x8000, 0x8000,  // step 2
	0x8000, 0x8000, 0x2000, 0x5010, 0xF000, 0xA111, 0x8343, 0x7121, 0xD121, 0x2111, 0xF232, 0x0232, 0x7232, 0x0343, 0x8000, 0x8000,  // step 3
	... up to step 62
};

For a fade-in you need to ensure that all palette entries (palette 4, 5,6,7 in this example) are set to black 0x8000 before starting the fade-in:

void prepare_fade_in()
{
	short i=0, j=0;
	short palette_no=4; // start palette
	waitVBlank();

	// set all colors to black
	for (j=4; j<8; j++) // j = how many palettes to fade
	{
		for(i=0; i<16; i++) // i = how many colors of each palette
		{
			volMEMWORD(0x400000+i+i+(palette_no*32)) = 0x8000;
		}

		palette_no+=1; // move to next palette
	}
}
Posté le 24/04/2017 à 10:24 Membre depuis le 13/08/2014, 17 messages
Thanks!!! smile