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