shithub: ft²

Download patch

ref: 2dc801a4650666d198feb5970d63b20955fa19c4
parent: 21bf3f4f5c1efed4024872ba6c59e606125733ed
author: Olav Sørensen <olav.sorensen@live.no>
date: Tue Apr 25 12:56:39 EDT 2023

Alpha-based fade in for the about screen

--- a/src/ft2_about.c
+++ b/src/ft2_about.c
@@ -8,6 +8,7 @@
 #include "ft2_structs.h"
 
 #define NUM_STARS 2048
+#define ALPHA_FADE_MILLISECS 2100 /* amount of milliseconds until content is fully faded in */
 #define ABOUT_SCREEN_W 626
 #define ABOUT_SCREEN_H 167
 #define ABOUT_LOGO_W 449
@@ -27,13 +28,9 @@
 
 static char *customText1 = "Clone by Olav \"8bitbubsy\" S\025rensen";
 static char *customText2 = "https://16-bits.org";
-static char customText3[64];
-
-static int16_t customText1Y, customText2Y, customText3Y;
-static int16_t customText1X, customText2X, customText3X;
-static int32_t lastStarScreenPos[NUM_STARS], fadeValue;
-static uint32_t randSeed, frameCounter;
-static float f2pi;
+static char customText3[256];
+static int16_t customText1Y, customText2Y, customText3Y, customText1X, customText2X, customText3X;
+static uint32_t alphaValue, randSeed, frameCounter;
 static vector_t starPoints[NUM_STARS], rotation;
 static matrix_t matrix;
 
@@ -51,15 +48,17 @@
 
 static void rotateMatrix(void)
 {
-	const float xx = rotation.x * f2pi;
+#define MY_PI_FLOAT 3.141592653589793f
+
+	const float xx = rotation.x * MY_PI_FLOAT;
 	const float sa = sinf(xx);
 	const float ca = cosf(xx);
 
-	const float yy = rotation.y * f2pi;
+	const float yy = rotation.y * MY_PI_FLOAT;
 	const float sb = sinf(yy);
 	const float cb = cosf(yy);
 
-	const float zz = rotation.z * f2pi;
+	const float zz = rotation.z * MY_PI_FLOAT;
 	const float sc = sinf(zz);
 	const float cc = cosf(zz);
 
@@ -75,14 +74,12 @@
 
 	// z
 	matrix.x.z = cb * sc;
-	matrix.y.z = 0.0f - sb;
+	matrix.y.z = -sb;
 	matrix.z.z = cb * cc;
 }
 
 static void aboutInit(void)
 {
-	f2pi = (float)(2.0 * 4.0 * atan(1.0)); // M_PI can not be trusted
-	
 	vector_t *s = starPoints;
 	for (int32_t i = 0; i < NUM_STARS; i++, s++)
 	{
@@ -92,8 +89,8 @@
 	}
 
 	rotation.x = rotation.y = rotation.z = 0.0f;
-	for (int32_t i = 0; i < NUM_STARS; i++)
-		lastStarScreenPos[i] = -1;
+	alphaValue = 0;
+	frameCounter = 0;
 }
 
 static void starfield(void)
@@ -101,88 +98,73 @@
 	vector_t *star = starPoints;
 	for (int16_t i = 0; i < NUM_STARS; i++, star++)
 	{
-		// erase last star pixel
-		int32_t screenBufferPos = lastStarScreenPos[i];
-		if (screenBufferPos >= 0)
-		{
-			if (!(video.frameBuffer[screenBufferPos] & 0xFF000000))
-				video.frameBuffer[screenBufferPos] = video.palette[PAL_BCKGRND];
-
-			lastStarScreenPos[i] = -1;
-		}
-
 		star->z += 0.00015f;
-		if (star->z >= 0.5f) star->z -= 1.0f;
+		if (star->z >= 0.5f)
+			star->z -= 1.0f;
 
 		const float z = (matrix.x.z * star->x) + (matrix.y.z * star->y) + (matrix.z.z * star->z) + 0.5f;
 		if (z <= 0.0f)
 			continue;
 
-		float y = (((matrix.x.y * star->x) + (matrix.y.y * star->y) + (matrix.z.y * star->z)) / z) * 400.0f;
-		y += 2.0f + (ABOUT_SCREEN_H/2.0f);
-
-		const int32_t outY = (int32_t)(y + 0.5f); // rounded
-		if ((uint32_t)outY > 2+ABOUT_SCREEN_H)
+		float y = (ABOUT_SCREEN_H/2.0f) + ((((matrix.x.y * star->x) + (matrix.y.y * star->y) + (matrix.z.y * star->z)) / z) * 400.0f);
+		const int32_t outY = (int32_t)y;
+		if (outY < 3 || outY >= 3+ABOUT_SCREEN_H)
 			continue;
 
-		float x = (((matrix.x.x * star->x) + (matrix.y.x * star->y) + (matrix.z.x * star->z)) / z) * 400.0f;
-		x += 2.0f + (ABOUT_SCREEN_W/2.0f);
+		float x = (ABOUT_SCREEN_W/2.0f) + ((((matrix.x.x * star->x) + (matrix.y.x * star->y) + (matrix.z.x * star->z)) / z) * 400.0f);
 
-		const int32_t outX = (int32_t)(x + 0.5f); // rounded
-		if ((uint32_t)outX > 2+ABOUT_SCREEN_W)
+		const int32_t outX = (int32_t)x;
+		if (outX < 3 || outX >= 3+ABOUT_SCREEN_W)
 			continue;
 
-		// render star pixel if the pixel under it is the background key
-		screenBufferPos = ((uint32_t)outY * SCREEN_W) + (uint32_t)outX;
-		if ((video.frameBuffer[screenBufferPos] >> 24) == PAL_BCKGRND)
-		{
-			int32_t d = (int32_t)(z * 255.0f);
-			if (d > 255)
-				d = 255;
+		int32_t d = (int32_t)(z * 255.0f);
+		if (d > 255)
+			d = 255;
+		d ^= 255;
 
-			d ^= 255;
+		// add a tint of blue to the star pixel
 
-			int32_t r = d - 75;
-			if (r < 0)
-				r = 0;
+		int32_t r = d - 79;
+		if (r < 0)
+			r = 0;
 
-			int32_t g = d - 38;
-			if (g < 0)
-				g = 0;
+		int32_t g = d - 38;
+		if (g < 0)
+			g = 0;
 
-			int32_t b = d + 64;
-			if (b > 255)
-				b = 255;
+		int32_t b = d + 64;
+		if (b > 255)
+			b = 255;
 
-			video.frameBuffer[screenBufferPos] = RGB32(r, g, b);
-			lastStarScreenPos[i] = screenBufferPos;
-		}
+		video.frameBuffer[(outY * SCREEN_W) + outX] = RGB32(r, g, b);
 	}
 }
 
-void aboutFrame(void)
+void aboutFrame(void) // called every frame when the about screen is shown
 {
+	clearRect(3, 3, ABOUT_SCREEN_W, ABOUT_SCREEN_H);
+
+	// 3D starfield
 	rotateMatrix();
 	starfield();
-
 	rotation.x -= 0.00011f;
 	rotation.z += 0.00006f;
 
-	// fade in stuff after 1/3th of a second
-	if (fadeValue < 256 && ++frameCounter >= (int32_t)((VBLANK_HZ/3.0)+0.5))
-	{
-		blit32Fade(91, 31, bmp.ft2AboutLogo, ABOUT_LOGO_W, ABOUT_LOGO_H, fadeValue);
-		textOutFade(customText1X, customText1Y, PAL_FORGRND, customText1, fadeValue);
-		textOutFade(customText2X, customText2Y, PAL_FORGRND, customText2, fadeValue);
-		textOutFade(customText3X, customText3Y, PAL_FORGRND, customText3, fadeValue);
+	// logo + text
+	blit32Alpha(91, 31, bmp.ft2AboutLogo, ABOUT_LOGO_W, ABOUT_LOGO_H, alphaValue);
+	textOutAlpha(customText1X, customText1Y, PAL_FORGRND, customText1, alphaValue);
+	textOutAlpha(customText2X, customText2Y, PAL_FORGRND, customText2, alphaValue);
+	textOutAlpha(customText3X, customText3Y, PAL_FORGRND, customText3, alphaValue);
 
-		fadeValue += 3;
-		if (fadeValue > 256)
-			fadeValue = 256;
-	}
+	alphaValue += (uint32_t)((65536.0 / (ALPHA_FADE_MILLISECS / (1000.0 / VBLANK_HZ))) + 0.5);
+	if (alphaValue > 65536)
+		alphaValue = 65536;
+
+	// the exit button has to be redrawn since it gets overwritten :)
+	showPushButton(PB_EXIT_ABOUT);
 }
 
-void showAboutScreen(void) // called once when About screen is opened
+void showAboutScreen(void) // called once when about screen is opened
 {
 	if (ui.extended)
 		exitPatternEditorExtended();
@@ -195,7 +177,7 @@
 	showPushButton(PB_EXIT_ABOUT);
 
 	sprintf(customText3, "v%s (%s)", PROG_VER_STR, __DATE__);
-	customText1X = (SCREEN_W - textWidth(customText1)) >> 1;
+	customText1X = (SCREEN_W - textWidth(customText1)) / 2;
 	customText2X = (SCREEN_W-8) - textWidth(customText2);
 	customText3X = (SCREEN_W-8) - textWidth(customText3);
 	customText1Y = 157;
@@ -203,8 +185,6 @@
 	customText3Y = 157;
 
 	aboutInit();
-	frameCounter = 0;
-	fadeValue = 0;
 	ui.aboutScreenShown = true;
 }
 
--- a/src/ft2_gui.c
+++ b/src/ft2_gui.c
@@ -385,7 +385,7 @@
 	}
 }
 
-static void charOutFade(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, char chr, int32_t fade) // for about screen
+void charOutAlpha(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, char chr, uint32_t alpha)
 {
 	assert(xPos < SCREEN_W && yPos < SCREEN_H);
 
@@ -393,7 +393,11 @@
 	if (chr == ' ')
 		return;
 
+	if (alpha > 65536)
+		alpha = 65536;
+
 	const uint32_t pixVal = video.palette[paletteIndex];
+	const uint32_t palNum = paletteIndex << 24;
 	const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W];
 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
 
@@ -401,14 +405,25 @@
 	{
 		for (int32_t x = 0; x < FONT1_CHAR_W; x++)
 		{
-			if (srcPtr[x] != 0)
-			{
-				const int32_t r = (RGB32_R(pixVal) * fade) >> 8;
-				const int32_t g = (RGB32_G(pixVal) * fade) >> 8;
-				const int32_t b = (RGB32_B(pixVal) * fade) >> 8;
+			const uint32_t srcPixel = srcPtr[x];
+			if (srcPixel == 0)
+				continue;
 
-				dstPtr[x] = RGB32(r, g, b) | 0xFF000000;
-			}
+			const uint32_t dstPixel = dstPtr[x];
+
+			const int32_t srcR = RGB32_R(pixVal);
+			const int32_t srcG = RGB32_G(pixVal);
+			const int32_t srcB = RGB32_B(pixVal);
+
+			int32_t dstR = RGB32_R(dstPixel);
+			int32_t dstG = RGB32_G(dstPixel);
+			int32_t dstB = RGB32_B(dstPixel);
+
+			dstR = ((dstR * (65536-alpha)) + (srcR * alpha)) >> 16;
+			dstG = ((dstG * (65536-alpha)) + (srcG * alpha)) >> 16;
+			dstB = ((dstB * (65536-alpha)) + (srcB * alpha)) >> 16;
+
+			dstPtr[x] = RGB32(dstR, dstG, dstB) | palNum;
 		}
 
 		srcPtr += FONT1_WIDTH;
@@ -621,7 +636,7 @@
 	}
 }
 
-void textOutFade(uint16_t x, uint16_t y, uint8_t paletteIndex, const char *textPtr, int32_t fade) // for about screen
+void textOutAlpha(uint16_t x, uint16_t y, uint8_t paletteIndex, const char *textPtr, uint32_t alpha)
 {
 	char chr;
 	uint16_t currX;
@@ -628,6 +643,12 @@
 
 	assert(textPtr != NULL);
 
+	if (alpha >= 65536)
+	{
+		textOut(x, y, paletteIndex, textPtr);
+		return;
+	}
+
 	currX = x;
 	while (true)
 	{
@@ -635,7 +656,7 @@
 		if (chr == '\0')
 			break;
 
-		charOutFade(currX, y, paletteIndex, chr, fade);
+		charOutAlpha(currX, y, paletteIndex, chr, alpha);
 		currX += charWidth(chr);
 	}
 }
@@ -808,14 +829,11 @@
 {
 	assert(xPos < SCREEN_W && yPos < SCREEN_H && (xPos + w) <= SCREEN_W && (yPos + h) <= SCREEN_H);
 
-	const uint32_t width = w * sizeof (int32_t);
+	const uint32_t pitch = w * sizeof (int32_t);
 
 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
-	for (int32_t y = 0; y < h; y++)
-	{
-		memset(dstPtr, 0, width);
-		dstPtr += SCREEN_W;
-	}
+	for (int32_t y = 0; y < h; y++, dstPtr += SCREEN_W)
+		memset(dstPtr, 0, pitch);
 }
 
 void fillRect(uint16_t xPos, uint16_t yPos, uint16_t w, uint16_t h, uint8_t paletteIndex)
@@ -834,7 +852,7 @@
 	}
 }
 
-void blit32(uint16_t xPos, uint16_t yPos, const uint32_t* srcPtr, uint16_t w, uint16_t h)
+void blit32(uint16_t xPos, uint16_t yPos, const uint32_t *srcPtr, uint16_t w, uint16_t h)
 {
 	assert(srcPtr != NULL && xPos < SCREEN_W && yPos < SCREEN_H && (xPos + w) <= SCREEN_W && (yPos + h) <= SCREEN_H);
 
@@ -852,24 +870,40 @@
 	}
 }
 
-void blit32Fade(uint16_t xPos, uint16_t yPos, const uint32_t* srcPtr, uint16_t w, uint16_t h, int32_t fade) // for about screen
+void blit32Alpha(uint16_t xPos, uint16_t yPos, const uint32_t *srcPtr, uint16_t w, uint16_t h, uint32_t alpha)
 {
 	assert(srcPtr != NULL && xPos < SCREEN_W && yPos < SCREEN_H && (xPos + w) <= SCREEN_W && (yPos + h) <= SCREEN_H);
 
+	if (alpha >= 65536)
+	{
+		blit32(xPos, yPos, srcPtr, w, h);
+		return;
+	}
+
 	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
 	for (int32_t y = 0; y < h; y++)
 	{
 		for (int32_t x = 0; x < w; x++)
 		{
-			const uint32_t pixel = srcPtr[x];
-			if (pixel != 0x00FF00)
-			{
-				const int32_t r = (RGB32_R(pixel) * fade) >> 8;
-				const int32_t g = (RGB32_G(pixel) * fade) >> 8;
-				const int32_t b = (RGB32_B(pixel) * fade) >> 8;
+			const uint32_t srcPixel = srcPtr[x];
+			if (srcPixel == 0x00FF00)
+				continue;
 
-				dstPtr[x] = RGB32(r, g, b) | 0xFF000000; // most significant 8 bits = palette number. 0xFF because no true palette
-			}
+			const uint32_t dstPixel = dstPtr[x];
+
+			const int32_t srcR = RGB32_R(srcPixel);
+			const int32_t srcG = RGB32_G(srcPixel);
+			const int32_t srcB = RGB32_B(srcPixel);
+
+			int32_t dstR = RGB32_R(dstPixel);
+			int32_t dstG = RGB32_G(dstPixel);
+			int32_t dstB = RGB32_B(dstPixel);
+
+			dstR = ((dstR * (65536-alpha)) + (srcR * alpha)) >> 16;
+			dstG = ((dstG * (65536-alpha)) + (srcG * alpha)) >> 16;
+			dstB = ((dstB * (65536-alpha)) + (srcB * alpha)) >> 16;
+
+			dstPtr[x] = RGB32(dstR, dstG, dstB) | 0xFF000000; // most significant 8 bits = palette number. 0xFF because no true palette
 		}
 
 		srcPtr += w;
--- a/src/ft2_gui.h
+++ b/src/ft2_gui.h
@@ -79,7 +79,8 @@
 void clearRect(uint16_t xPos, uint16_t yPos, uint16_t w, uint16_t h);
 void fillRect(uint16_t xPos, uint16_t yPos, uint16_t w, uint16_t h, uint8_t paletteIndex);
 void drawFramework(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t type);
-void blit32(uint16_t xPos, uint16_t yPos, const uint32_t* srcPtr, uint16_t w, uint16_t h);
+void blit32(uint16_t xPos, uint16_t yPos, const uint32_t *srcPtr, uint16_t w, uint16_t h);
+void blit32Alpha(uint16_t xPos, uint16_t yPos, const uint32_t *srcPtr, uint16_t w, uint16_t h, uint32_t alpha);
 void blit(uint16_t xPos, uint16_t yPos, const uint8_t *srcPtr, uint16_t w, uint16_t h);
 void blitClipX(uint16_t xPos, uint16_t yPos, const uint8_t *srcPtr, uint16_t w, uint16_t h, uint16_t clipX);
 void blitFast(uint16_t xPos, uint16_t yPos, const uint8_t *srcPtr, uint16_t w, uint16_t h); // no transparency/colorkey
@@ -90,6 +91,7 @@
 void textOutTiny(int32_t xPos, int32_t yPos, char *str, uint32_t color); // A..Z/a..z and 0..9
 void textOutTinyOutline(int32_t xPos, int32_t yPos, char *str); // A..Z/a..z and 0..9
 void charOut(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, char chr);
+void charOutAlpha(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, char chr, uint32_t alpha);
 void charOutBg(uint16_t xPos, uint16_t yPos, uint8_t fgPalette, uint8_t bgPalette, char chr);
 void charOutShadow(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, uint8_t shadowPaletteIndex, char chr);
 void charOutClipX(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, char chr, uint16_t clipX);
@@ -97,6 +99,7 @@
 void charOutShadow(uint16_t x, uint16_t y, uint8_t paletteIndex, uint8_t shadowPaletteIndex, char chr);
 void charOutOutlined(uint16_t x, uint16_t y, uint8_t paletteIndex, char chr);
 void textOut(uint16_t x, uint16_t y, uint8_t paletteIndex, const char *textPtr);
+void textOutAlpha(uint16_t x, uint16_t y, uint8_t paletteIndex, const char *textPtr, uint32_t alpha);
 void textOutBorder(uint16_t x, uint16_t y, uint8_t paletteIndex, uint8_t borderPaletteIndex, const char *textPtr);
 void textOutFixed(uint16_t x, uint16_t y, uint8_t fgPaltete, uint8_t bgPalette, const char *textPtr);
 void bigTextOut(uint16_t x, uint16_t y, uint8_t paletteIndex, const char *textPtr);
@@ -117,7 +120,3 @@
 void hideTopScreen(void);
 void showTopScreen(bool restoreScreens);
 void showBottomScreen(void);
-
-// for about screen
-void textOutFade(uint16_t x, uint16_t y, uint8_t paletteIndex, const char *textPtr, int32_t fade);
-void blit32Fade(uint16_t xPos, uint16_t yPos, const uint32_t* srcPtr, uint16_t w, uint16_t h, int32_t fade);
--- a/src/ft2_header.h
+++ b/src/ft2_header.h
@@ -12,7 +12,7 @@
 #endif
 #include "ft2_replayer.h"
 
-#define PROG_VER_STR "1.66"
+#define PROG_VER_STR "1.67"
 
 // do NOT change these! It will only mess things up...