1 #include <stdio.h> // sprintf()
2 #include <math.h>
3 #include "ft2_header.h"
4 #include "ft2_gui.h"
5 #include "ft2_pattern_ed.h"
6 #include "ft2_bmp.h"
7 #include "ft2_video.h"
8 #include "ft2_structs.h"
9 
10 #define NUM_STARS 2048
11 #define ABOUT_SCREEN_W 626
12 #define ABOUT_SCREEN_H 167
13 #define ABOUT_LOGO_W 449
14 #define ABOUT_LOGO_H 110
15 #define ABOUT_TEXT_W 349
16 #define ABOUT_TEXT_H 29
17 
18 typedef struct
19 {
20 	float x, y, z;
21 } vector_t;
22 
23 typedef struct
24 {
25 	vector_t x, y, z;
26 } matrix_t;
27 
28 static char *customText1 = "Clone by Olav \"8bitbubsy\" S\025rensen";
29 static char *customText2 = "https://16-bits.org";
30 static char customText3[64];
31 
32 static int16_t customText1Y, customText2Y, customText3Y;
33 static int16_t customText1X, customText2X, customText3X;
34 static int32_t lastStarScreenPos[NUM_STARS], fadeValue;
35 static uint32_t randSeed, frameCounter;
36 static float f2pi;
37 static vector_t starPoints[NUM_STARS], rotation;
38 static matrix_t matrix;
39 
seedAboutScreenRandom(uint32_t newseed)40 void seedAboutScreenRandom(uint32_t newseed)
41 {
42 	randSeed = newseed;
43 }
44 
random32(void)45 static int32_t random32(void)
46 {
47 	randSeed *= 134775813;
48 	randSeed += 1;
49 	return randSeed;
50 }
51 
rotateMatrix(void)52 static void rotateMatrix(void)
53 {
54 	const float xx = rotation.x * f2pi;
55 	const float sa = sinf(xx);
56 	const float ca = cosf(xx);
57 
58 	const float yy = rotation.y * f2pi;
59 	const float sb = sinf(yy);
60 	const float cb = cosf(yy);
61 
62 	const float zz = rotation.z * f2pi;
63 	const float sc = sinf(zz);
64 	const float cc = cosf(zz);
65 
66 	// x
67 	matrix.x.x = (ca * cc) + (sc * sa * sb);
68 	matrix.y.x = sa * cb;
69 	matrix.z.x = (cc * sa * sb) - (ca * sc);
70 
71 	// y
72 	matrix.x.y = (sc * ca * sb) - (sa * cc);
73 	matrix.y.y = ca * cb;
74 	matrix.z.y = (sa * sc) + (cc * ca * sb);
75 
76 	// z
77 	matrix.x.z = cb * sc;
78 	matrix.y.z = 0.0f - sb;
79 	matrix.z.z = cb * cc;
80 }
81 
aboutInit(void)82 static void aboutInit(void)
83 {
84 	f2pi = (float)(2.0 * 4.0 * atan(1.0)); // M_PI can not be trusted
85 
86 	vector_t *s = starPoints;
87 	for (int32_t i = 0; i < NUM_STARS; i++, s++)
88 	{
89 		s->x = (float)(random32() * (1.0 / (UINT32_MAX+1.0)));
90 		s->y = (float)(random32() * (1.0 / (UINT32_MAX+1.0)));
91 		s->z = (float)(random32() * (1.0 / (UINT32_MAX+1.0)));
92 	}
93 
94 	rotation.x = rotation.y = rotation.z = 0.0f;
95 	for (int32_t i = 0; i < NUM_STARS; i++)
96 		lastStarScreenPos[i] = -1;
97 }
98 
starfield(void)99 static void starfield(void)
100 {
101 	vector_t *star = starPoints;
102 	for (int16_t i = 0; i < NUM_STARS; i++, star++)
103 	{
104 		// erase last star pixel
105 		int32_t screenBufferPos = lastStarScreenPos[i];
106 		if (screenBufferPos >= 0)
107 		{
108 			if (!(video.frameBuffer[screenBufferPos] & 0xFF000000))
109 				video.frameBuffer[screenBufferPos] = video.palette[PAL_BCKGRND];
110 
111 			lastStarScreenPos[i] = -1;
112 		}
113 
114 		star->z += 0.00015f;
115 		if (star->z >= 0.5f) star->z -= 1.0f;
116 
117 		const float z = (matrix.x.z * star->x) + (matrix.y.z * star->y) + (matrix.z.z * star->z) + 0.5f;
118 		if (z <= 0.0f)
119 			continue;
120 
121 		float y = (((matrix.x.y * star->x) + (matrix.y.y * star->y) + (matrix.z.y * star->z)) / z) * 400.0f;
122 		y += 2.0f + (ABOUT_SCREEN_H/2.0f);
123 
124 		const int32_t outY = (int32_t)(y + 0.5f); // rounded
125 		if ((uint32_t)outY > 2+ABOUT_SCREEN_H)
126 			continue;
127 
128 		float x = (((matrix.x.x * star->x) + (matrix.y.x * star->y) + (matrix.z.x * star->z)) / z) * 400.0f;
129 		x += 2.0f + (ABOUT_SCREEN_W/2.0f);
130 
131 		const int32_t outX = (int32_t)(x + 0.5f); // rounded
132 		if ((uint32_t)outX > 2+ABOUT_SCREEN_W)
133 			continue;
134 
135 		// render star pixel if the pixel under it is the background key
136 		screenBufferPos = ((uint32_t)outY * SCREEN_W) + (uint32_t)outX;
137 		if ((video.frameBuffer[screenBufferPos] >> 24) == PAL_BCKGRND)
138 		{
139 			int32_t d = (int32_t)(z * 255.0f);
140 			if (d > 255)
141 				d = 255;
142 
143 			d ^= 255;
144 
145 			int32_t r = d - 75;
146 			if (r < 0)
147 				r = 0;
148 
149 			int32_t g = d - 38;
150 			if (g < 0)
151 				g = 0;
152 
153 			int32_t b = d + 64;
154 			if (b > 255)
155 				b = 255;
156 
157 			video.frameBuffer[screenBufferPos] = RGB32(r, g, b);
158 			lastStarScreenPos[i] = screenBufferPos;
159 		}
160 	}
161 }
162 
aboutFrame(void)163 void aboutFrame(void)
164 {
165 	rotateMatrix();
166 	starfield();
167 
168 	rotation.x -= 0.00011f;
169 	rotation.z += 0.00006f;
170 
171 	// fade in stuff after 1/3th of a second
172 	if (fadeValue < 256 && ++frameCounter >= (int32_t)((VBLANK_HZ/3.0)+0.5))
173 	{
174 		blit32Fade(91, 31, bmp.ft2AboutLogo, ABOUT_LOGO_W, ABOUT_LOGO_H, fadeValue);
175 		textOutFade(customText1X, customText1Y, PAL_FORGRND, customText1, fadeValue);
176 		textOutFade(customText2X, customText2Y, PAL_FORGRND, customText2, fadeValue);
177 		textOutFade(customText3X, customText3Y, PAL_FORGRND, customText3, fadeValue);
178 
179 		fadeValue += 3;
180 		if (fadeValue > 256)
181 			fadeValue = 256;
182 	}
183 }
184 
showAboutScreen(void)185 void showAboutScreen(void) // called once when About screen is opened
186 {
187 	if (ui.extended)
188 		exitPatternEditorExtended();
189 
190 	hideTopScreen();
191 
192 	drawFramework(0, 0, 632, 173, FRAMEWORK_TYPE1);
193 	drawFramework(2, 2, 628, 169, FRAMEWORK_TYPE2);
194 
195 	showPushButton(PB_EXIT_ABOUT);
196 
197 	sprintf(customText3, "v%s (%s)", PROG_VER_STR, __DATE__);
198 	customText1X = (SCREEN_W - textWidth(customText1)) >> 1;
199 	customText2X = (SCREEN_W-8) - textWidth(customText2);
200 	customText3X = (SCREEN_W-8) - textWidth(customText3);
201 	customText1Y = 157;
202 	customText2Y = 157-12;
203 	customText3Y = 157;
204 
205 	aboutInit();
206 	frameCounter = 0;
207 	fadeValue = 0;
208 	ui.aboutScreenShown = true;
209 }
210 
hideAboutScreen(void)211 void hideAboutScreen(void)
212 {
213 	hidePushButton(PB_EXIT_ABOUT);
214 	ui.aboutScreenShown = false;
215 }
216 
exitAboutScreen(void)217 void exitAboutScreen(void)
218 {
219 	hideAboutScreen();
220 	showTopScreen(true);
221 }
222