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