10 /* APPROX. 170 FPS Minimum */
12 #define BG_FILENAME "data/grise.png"
15 #define MAX_SCROLL (backgroundW - fb_width - MIN_SCROLL)
17 #define FAR_SCROLL_SPEED 50.0f
18 #define NEAR_SCROLL_SPEED 400.0f
20 #define HORIZON_HEIGHT 100
21 #define REFLECTION_HEIGHT (240 - HORIZON_HEIGHT)
23 #define NORMALMAP_SCANLINE 372
25 static int init(void);
26 static void destroy(void);
27 static void start(long trans_time);
28 static void stop(long trans_time);
29 static void draw(void);
31 static void convert32To16(unsigned int *src32, unsigned short *dst16, unsigned int pixelCount);
32 static void processNormal();
33 static void initScrollTables();
34 static void updateScrollTables(float dt);
36 static unsigned short *background = 0;
37 static unsigned int backgroundW = 0;
38 static unsigned int backgroundH = 0;
40 static unsigned int lastFrameTime = 0;
41 static float lastFrameDuration = 0.0f;
43 static short *displacementMap;
45 static float scrollScaleTable[REFLECTION_HEIGHT];
46 static float scrollTable[REFLECTION_HEIGHT];
47 static int scrollTableRounded[REFLECTION_HEIGHT];
48 static int scrollModTable[REFLECTION_HEIGHT];
49 static float nearScrollAmount = 0.0f;
51 static struct screen scr = {
60 struct screen *mike_screen(void)
68 if (!(background = img_load_pixels(BG_FILENAME, &backgroundW, &backgroundH, IMG_FMT_RGBA32))) {
69 fprintf(stderr, "failed to load image " BG_FILENAME "\n");
73 /* Convert to 16bpp */
74 convert32To16((unsigned int*)background, background, backgroundW * NORMALMAP_SCANLINE); /* Normalmap will keep its 32 bit color */
83 static void destroy(void)
85 //img_free_pixels(background);
88 static void start(long trans_time)
90 lastFrameTime = time_msec;
93 static void stop(long trans_time)
97 static void draw(void)
99 int scroll = MIN_SCROLL + (MAX_SCROLL - MIN_SCROLL) * mouse_x / fb_width;
100 unsigned short *dst = fb_pixels;
101 unsigned short *src = background + scroll;
107 lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f;
108 lastFrameTime = time_msec;
110 for (scanline = 0; scanline < fb_height; scanline++) {
111 memcpy(dst, src, fb_width * 2);
116 updateScrollTables(lastFrameDuration);
118 dst = (unsigned short*) fb_pixels + HORIZON_HEIGHT * fb_width;
119 src = background + HORIZON_HEIGHT * backgroundW;
120 disp = displacementMap;
121 for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
122 for (i = 0; i < fb_width; i++) {
123 d = disp[(i + scrollTableRounded[scanline]) % scrollModTable[scanline]];
124 *dst++ = src[i + scroll + d];
131 /* src and dst can be the same */
132 static void convert32To16(unsigned int *src32, unsigned short *dst16, unsigned int pixelCount) {
136 *dst16++ = ((p << 8) & 0xF800) /* R */
137 | ((p >> 5) & 0x07E0) /* G */
138 | ((p >> 19) & 0x001F); /* B */
143 /* Normal map preprocessing */
144 /* Scale normal with depth and unpack R component (horizontal component) */
145 static void processNormal() {
149 short maxDisplacement = 0;
150 short minDisplacement = 256;
153 unsigned int *normalmap = (unsigned int*)background;
154 normalmap += NORMALMAP_SCANLINE * backgroundW;
155 dst = (unsigned short*)normalmap;
156 displacementMap = (short*)dst;
157 dst2 = displacementMap;
159 for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
160 scrollModTable[scanline] = (int) (backgroundW / scrollScaleTable[scanline] + 0.5f);
161 for (i = 0; i < backgroundW; i++) {
162 x = (int)(i * scrollScaleTable[scanline] + 0.5f);
163 if (x < backgroundW) {
164 *dst = (unsigned short)(normalmap[x] >> 8) & 0xFF;
165 if ((short)*dst > maxDisplacement) maxDisplacement = (short)(*dst);
166 if ((short)*dst < minDisplacement) minDisplacement = (short)(*dst);
172 normalmap += backgroundW;
175 if (maxDisplacement == minDisplacement) {
176 printf("Warning: grise normalmap fucked up\n");
180 /* Second pass - subtract half maximum displacement to displace in both directions */
181 for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
182 for (i = 0; i < backgroundW; i++) {
183 /* Remember that MIN_SCROLL is the padding around the screen, so ti's the maximum displacement we can get (positive & negative) */
184 *dst2 = 2 * MIN_SCROLL * (*dst2 - minDisplacement) / (maxDisplacement - minDisplacement) - MIN_SCROLL;
185 *dst2 = (short)((float)*dst2 / scrollScaleTable[scanline] + 0.5f); /* Displacements must also scale with distance*/
191 static float distanceScale(int scanline) {
193 farScale = (float)NEAR_SCROLL_SPEED / (float)FAR_SCROLL_SPEED;
194 t = (float)scanline / ((float)REFLECTION_HEIGHT - 1);
195 return 1.0f / (1.0f / farScale + (1.0f - 1.0f / farScale) * t);
198 static void initScrollTables() {
200 for (i = 0; i < REFLECTION_HEIGHT; i++) {
201 scrollScaleTable[i] = distanceScale(i);
202 scrollTable[i] = 0.0f;
203 scrollTableRounded[i] = 0;
208 static void updateScrollTables(float dt) {
211 nearScrollAmount += dt * NEAR_SCROLL_SPEED;
212 nearScrollAmount = (float) fmod(nearScrollAmount, 512.0f);
214 for (i = 0; i < REFLECTION_HEIGHT; i++) {
215 scrollTable[i] = nearScrollAmount / scrollScaleTable[i];
216 scrollTableRounded[i] = (int)(scrollTable[i] + 0.5f) % scrollModTable[i];