Applied displacement to reflection
[dosdemo] / src / mike.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <assert.h>
6 #include "imago2.h"
7 #include "demo.h"
8 #include "screen.h"
9
10 #define BG_FILENAME "data/grise.png"
11
12 #define MIN_SCROLL 32
13 #define MAX_SCROLL (backgroundW - fb_width - MIN_SCROLL)
14
15 #define FAR_SCROLL_SPEED 50.0f
16 #define NEAR_SCROLL_SPEED 400.0f
17
18 #define HORIZON_HEIGHT 100
19 #define REFLECTION_HEIGHT (240 - HORIZON_HEIGHT)
20
21 #define NORMALMAP_SCANLINE 372
22
23 static int init(void);
24 static void destroy(void);
25 static void start(long trans_time);
26 static void stop(long trans_time);
27 static void draw(void);
28
29 static void convert32To16(unsigned int *src32, unsigned short *dst16, unsigned int pixelCount);
30 static void processNormal();
31 static void initScrollTables();
32 static void updateScrollTables(float dt);
33
34 static unsigned short *background = 0;
35 static unsigned int backgroundW = 0;
36 static unsigned int backgroundH = 0;
37
38 static unsigned int lastFrameTime = 0;
39 static float lastFrameDuration = 0.0f;
40
41 static short *displacementMap;
42
43 static float scrollSpeedTable[REFLECTION_HEIGHT];
44 static float scrollTable[REFLECTION_HEIGHT];
45 static int scrollTableRounded[REFLECTION_HEIGHT];
46 static int scrollModTable[REFLECTION_HEIGHT];
47
48 static struct screen scr = {
49         "mike",
50         init,
51         destroy,
52         start,
53         stop,
54         draw
55 };
56
57 struct screen *mike_screen(void)
58 {
59         return &scr;
60 }
61
62
63 static int init(void)
64 {
65         if (!(background = img_load_pixels(BG_FILENAME, &backgroundW, &backgroundH, IMG_FMT_RGBA32))) {
66                 fprintf(stderr, "failed to load image " BG_FILENAME "\n");
67                 return -1;
68         }
69
70         /* Convert to 16bpp */
71         convert32To16((unsigned int*)background, background, backgroundW * NORMALMAP_SCANLINE); /* Normalmap will keep its 32 bit color */
72
73         processNormal();
74
75         initScrollTables();
76
77         return 0;
78 }
79
80 static void destroy(void)
81 {
82         //img_free_pixels(background);
83 }
84
85 static void start(long trans_time)
86 {
87         lastFrameTime = time_msec;
88 }
89
90 static void stop(long trans_time)
91 {
92 }
93
94 static void draw(void)
95 {       
96         int scroll = MIN_SCROLL + (MAX_SCROLL - MIN_SCROLL) * mouse_x / fb_width;
97         unsigned short *dst = fb_pixels;
98         unsigned short *src = background + scroll;
99         int scanline = 0;
100         int i = 0;
101         short *disp;
102         int d;
103
104         lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f;
105         lastFrameTime = time_msec;
106
107         for (scanline = 0; scanline < fb_height; scanline++) {
108                 memcpy(dst, src, fb_width * 2);
109                 src += backgroundW;
110                 dst += fb_width;
111         }
112         
113         updateScrollTables(lastFrameDuration);
114
115         dst = (unsigned short*) fb_pixels + HORIZON_HEIGHT * fb_width;
116         src = background + HORIZON_HEIGHT * backgroundW;
117         disp = displacementMap;
118         for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
119                 for (i = 0; i < fb_width; i++) {
120                         d = disp[(i + scrollTableRounded[scanline]) % scrollModTable[scanline]];
121                         *dst++ = src[i + scroll + d];
122                 }
123                 src += backgroundW;
124         }
125 }
126
127 /* src and dst can be the same */
128 static void convert32To16(unsigned int *src32, unsigned short *dst16, unsigned int pixelCount) {
129         unsigned int p;
130         while (pixelCount) {
131                 p = *src32++;
132                 *dst16++ =      ((p << 8) & 0xF800)             /* R */
133                         |               ((p >> 5) & 0x07E0)             /* G */
134                         |               ((p >> 19) & 0x001F);   /* B */
135                 pixelCount--;
136         }
137 }
138
139 /* Normal map preprocessing */
140 /* Scale normal with depth and unpack R component (horizontal component) */
141 static void processNormal() {
142         int scanline;
143         unsigned int *normalmap = (unsigned int*)background;
144         normalmap += NORMALMAP_SCANLINE * backgroundW;
145         unsigned short *dst = normalmap;
146         displacementMap = (short*)dst;
147         short *dst2 = displacementMap;
148         float scale;
149         int i;
150         int x;
151         short maxDisplacement = 0;
152         short minDisplacement = 256;
153
154         for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
155                 scale = 2.0f - (float)scanline / ((float)REFLECTION_HEIGHT - 1);
156                 scrollModTable[scanline] = (int) (backgroundW / scale + 0.5f);
157                 for (i = 0; i < backgroundW; i++) {
158                         x = (int)(i * scale + 0.5f);
159                         if (x < background) {
160                                 *dst = (unsigned short)normalmap[x] & 0xFF;
161                                 if ((short)*dst > maxDisplacement) maxDisplacement = (short)(*dst);
162                                 if ((short)*dst < minDisplacement) minDisplacement = (short)(*dst);
163                         } else {
164                                 *dst = 0;
165                         }
166                         dst++;
167                 }
168                 normalmap += backgroundW;
169         }
170
171         if (maxDisplacement == minDisplacement) {
172                 printf("Warning: grise normalmap fucked up\n");
173                 return;
174         }
175
176         /* Second pass - subtract half maximum displacement to displace in both directions */
177         for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
178                 for (i = 0; i < backgroundW; i++) {
179                         /* Remember that MIN_SCROLL is the padding around the screen, so ti's the maximum displacement we can get (positive & negative) */
180                         *dst2 = 2 * MIN_SCROLL * (*dst2 - minDisplacement) / (maxDisplacement - minDisplacement) - MIN_SCROLL;
181                         dst2++;
182                 }
183         }
184 }
185
186 static void initScrollTables() {
187         int i = 0;
188         float scrollSpeed = FAR_SCROLL_SPEED;
189         float speedIncrement = (NEAR_SCROLL_SPEED - FAR_SCROLL_SPEED) / ((float) (REFLECTION_HEIGHT - 1));
190         for (i = 0; i < REFLECTION_HEIGHT; i++) {
191                 scrollSpeedTable[i] = scrollSpeed;
192                 scrollSpeed += speedIncrement;
193                 scrollTable[i] = 0.0f;
194                 scrollTableRounded[i] = 0;
195         }
196 }
197
198
199 static void updateScrollTables(float dt) {
200         int i = 0;
201         for (i = 0; i < REFLECTION_HEIGHT; i++) {
202                 scrollTable[i] += scrollSpeedTable[i] * dt;
203                 scrollTableRounded[i] = (int)(scrollTable[i] + 0.5f) % scrollModTable[i];
204         }
205 }