Added normalmap + parallax scrolling
[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 float scrollSpeedTable[REFLECTION_HEIGHT];
42 static float scrollTable[REFLECTION_HEIGHT];
43 static int scrollTableRounded[REFLECTION_HEIGHT];
44 static int scrollModTable[REFLECTION_HEIGHT];
45
46 static struct screen scr = {
47         "mike",
48         init,
49         destroy,
50         start,
51         stop,
52         draw
53 };
54
55 struct screen *mike_screen(void)
56 {
57         return &scr;
58 }
59
60
61 static int init(void)
62 {
63         if (!(background = img_load_pixels(BG_FILENAME, &backgroundW, &backgroundH, IMG_FMT_RGBA32))) {
64                 fprintf(stderr, "failed to load image " BG_FILENAME "\n");
65                 return -1;
66         }
67
68         /* Convert to 16bpp */
69         convert32To16((unsigned int*)background, background, backgroundW * NORMALMAP_SCANLINE); /* Normalmap will keep its 32 bit color */
70
71         processNormal();
72
73         initScrollTables();
74
75         return 0;
76 }
77
78 static void destroy(void)
79 {
80         //img_free_pixels(background);
81 }
82
83 static void start(long trans_time)
84 {
85         lastFrameTime = time_msec;
86 }
87
88 static void stop(long trans_time)
89 {
90 }
91
92 static void draw(void)
93 {       
94         int scroll = MIN_SCROLL + (MAX_SCROLL - MIN_SCROLL) * mouse_x / fb_width;
95         unsigned short *dst = fb_pixels;
96         unsigned short *src = background + scroll;
97         int scanline = 0;
98         int i = 0;
99
100         lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f;
101         lastFrameTime = time_msec;
102
103         for (scanline = 0; scanline < fb_height; scanline++) {
104                 memcpy(dst, src, fb_width * 2);
105                 src += backgroundW;
106                 dst += fb_width;
107         }
108         
109         updateScrollTables(lastFrameDuration);
110
111         dst = fb_pixels;
112         dst += 100 * fb_width;
113         src = background + NORMALMAP_SCANLINE * backgroundW * 2;
114         for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
115                 for (i = 0; i < fb_width; i++) {
116                         *dst++ = src[(i + scrollTableRounded[scanline]) % scrollModTable[scanline]];
117                 }
118                 src += backgroundW;
119         }
120 }
121
122 /* src and dst can be the same */
123 static void convert32To16(unsigned int *src32, unsigned short *dst16, unsigned int pixelCount) {
124         unsigned int p;
125         while (pixelCount) {
126                 p = *src32++;
127                 *dst16++ =      ((p << 8) & 0xF800)             /* R */
128                         |               ((p >> 5) & 0x07E0)             /* G */
129                         |               ((p >> 19) & 0x001F);   /* B */
130                 pixelCount--;
131         }
132 }
133
134 /* Normal map preprocessing */
135 /* Scale normal with depth and unpack R component (horizontal component) */
136 static void processNormal() {
137         int scanline;
138         unsigned int *normalmap = (unsigned int*)background;
139         normalmap += NORMALMAP_SCANLINE * backgroundW;
140         unsigned short *dst = normalmap;
141         float scale;
142         int i;
143         int x;
144
145         for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
146                 scale = 2.0f - (float)scanline / ((float)REFLECTION_HEIGHT - 1);
147                 scrollModTable[scanline] = (int) (backgroundW / scale + 0.5f);
148                 for (i = 0; i < backgroundW; i++) {
149                         x = (int)(i * scale + 0.5f);
150                         *dst++ = x < backgroundW ? normalmap[x] & 0xFF : 0;
151                 }
152                 normalmap += backgroundW;
153         }
154 }
155
156 static void initScrollTables() {
157         int i = 0;
158         float scrollSpeed = FAR_SCROLL_SPEED;
159         float speedIncrement = (NEAR_SCROLL_SPEED - FAR_SCROLL_SPEED) / ((float) (REFLECTION_HEIGHT - 1));
160         for (i = 0; i < REFLECTION_HEIGHT; i++) {
161                 scrollSpeedTable[i] = scrollSpeed;
162                 scrollSpeed += speedIncrement;
163                 scrollTable[i] = 0.0f;
164                 scrollTableRounded[i] = 0;
165         }
166 }
167
168
169 static void updateScrollTables(float dt) {
170         int i = 0;
171         for (i = 0; i < REFLECTION_HEIGHT; i++) {
172                 scrollTable[i] += scrollSpeedTable[i] * dt;
173                 scrollTableRounded[i] = (int)(scrollTable[i] + 0.5f) % scrollModTable[i];
174         }
175 }