Added boundary checks for lights, made lights bigger, moved TinyFPS to bottom of...
[dosdemo] / src / bump.c
1 // Bump effect (not moving yet of course, I have many ideas on this to commit before it's ready)
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <math.h>
7
8 #include "demo.h"
9 #include "screen.h"
10 #include "tinyfps.h"
11
12 static int init(void);
13 static void destroy(void);
14 static void start(long trans_time);
15 static void stop(long trans_time);
16 static void draw(void);
17
18 static struct screen scr = {
19         "bump",
20         init,
21         destroy,
22         start,
23         stop,
24         draw
25 };
26
27 static struct point {
28         int x, y;
29 };
30
31 #define NUM_BIG_LIGHTS 3
32 #define BIG_LIGHT_WIDTH 256
33 #define BIG_LIGHT_HEIGHT BIG_LIGHT_WIDTH
34
35 static unsigned long startingTime;
36
37 static unsigned char *heightmap;
38 static unsigned short *lightmap;
39 static int *bumpOffset;
40
41 static unsigned short *bigLight[NUM_BIG_LIGHTS];
42 static struct point bigLightPoint[NUM_BIG_LIGHTS];
43
44 struct screen *bump_screen(void)
45 {
46         return &scr;
47 }
48
49 static int init(void)
50 {
51         int i, j, x, y, c, r, g, b;
52
53         const int numBlurs = 3;
54         const int lightRadius = BIG_LIGHT_WIDTH / 2;
55
56         const int bigLightSize = BIG_LIGHT_WIDTH * BIG_LIGHT_HEIGHT;
57         const int fb_size = fb_width * fb_height;
58
59         // Just some parameters to temporary test the colors of 3 lights
60         // if every light uses it's own channel bits, it's better
61         const float rgbMul[9] = { 1.0f, 0.0f, 0.0f, 
62                                                                   0.0f, 1.0f, 0.0f,
63                                                                   0.0f, 0.0f, 1.0f};
64         initFpsFonts();
65
66         heightmap = malloc(sizeof(*heightmap) * fb_size);
67         lightmap = malloc(sizeof(*lightmap) * fb_size);
68         bumpOffset = malloc(sizeof(*bumpOffset) * fb_size);
69
70         for (i = 0; i < NUM_BIG_LIGHTS; i++)
71                 bigLight[i] = malloc(sizeof(*bigLight[i]) * bigLightSize);
72
73         memset(lightmap, 0, sizeof(*lightmap) * fb_size);
74         memset(bumpOffset, 0, sizeof(*bumpOffset) * fb_size);
75
76         // Create random junk
77         for (i = 0; i < fb_size; i++)
78                 heightmap[i] = rand() & 255;
79
80         // Blur to smooth
81         for (j = 0; j < numBlurs; j++)
82                 for (i = 0; i < fb_size; i++)
83                         heightmap[i] = (heightmap[abs((i - 1) % fb_size)] + heightmap[abs((i + 1) % fb_size)] + heightmap[abs((i - fb_width) % fb_size)] + heightmap[abs((i + fb_width) % fb_size)]) >> 2;
84
85         // Inclination precalculation
86         i = 0;
87         for (y = 0; y < fb_height; y++)
88         {
89                 for (x = 0; x < fb_width; x++)
90                 {
91                         const float offsetPower = 2.0f;
92                         int dx, dy, xp, yp;
93
94                         dx = (int)((heightmap[i] - heightmap[i + 1]) * offsetPower);
95                         dy = (int)((heightmap[i] - heightmap[i + fb_width]) * offsetPower);
96
97                         xp = x + dx;
98                         if (xp < 0) xp = 0;
99                         if (xp > fb_width - 1) xp = fb_width - 1;
100
101                         yp = y + dy;
102                         if (yp < 0) yp = 0;
103                         if (yp > fb_height - 1) yp = fb_height - 1;
104
105                         bumpOffset[i++] = yp * fb_width + xp;
106                 }
107         }
108
109         // Generate three lights
110         i = 0;
111         for (y = 0; y < BIG_LIGHT_HEIGHT; y++)
112         {
113                 int yc = y - (BIG_LIGHT_HEIGHT / 2);
114                 for (x = 0; x < BIG_LIGHT_WIDTH; x++)
115                 {
116                         int xc = x - (BIG_LIGHT_WIDTH / 2);
117                         float d = (float)sqrt(xc * xc + yc * yc);
118                         float invDist = ((float)lightRadius - (float)sqrt(xc * xc + yc * yc)) / (float)lightRadius;
119                         if (invDist < 0.0f) invDist = 0.0f;
120
121                         c = (int)(invDist * 63);
122                         r = c >> 1;
123                         g = c;
124                         b = c >> 1;
125
126                         for (j = 0; j < NUM_BIG_LIGHTS; j++)
127                         {
128                                 bigLight[j][i] = ((int)(r * rgbMul[j * 3]) << 11) | ((int)(g * rgbMul[j * 3 + 1]) << 5) | (int)(b * rgbMul[j * 3 + 2]);
129                         }
130                         i++;
131                 }
132         }
133
134         return 0;
135 }
136
137 static void destroy(void)
138 {
139 }
140
141 static void start(long trans_time)
142 {
143         startingTime = time_msec;
144 }
145
146 static void stop(long trans_time)
147 {
148 }
149
150 static void eraseArea(struct point *p, int width, int height)
151 {
152         int x, y, dx;
153         unsigned short *dst;
154
155         int x0 = p->x;
156         int y0 = p->y;
157         int x1 = p->x + width;
158         int y1 = p->y + height;
159
160         if (x0 < 0) x0 = 0;
161         if (y0 < 0) y0 = 0;
162         if (x1 > fb_width) x1 = fb_width;
163         if (y1 > fb_height) y1 = fb_height;
164
165         dx = x1 - x0;
166
167         dst = lightmap + y0 * fb_width + x0;
168
169         for (y = y0; y < y1; y++)
170         {
171                 for (x = x0; x < x1; x++)
172                 {
173                         *dst++ = 0;
174                 }
175                 dst += fb_width - dx;
176         }
177 }
178
179
180 static void renderLight(struct point *p, int width, int height, unsigned short *light)
181 {
182         int x, y, dx;
183         unsigned short *src, *dst;
184
185         int x0 = p->x;
186         int y0 = p->y;
187         int x1 = p->x + width;
188         int y1 = p->y + height;
189
190         int xl = 0;
191         int yl = 0;
192
193         if (x0 < 0)
194         {
195                 xl = -x0;
196                 x0 = 0;
197         }
198
199         if (y0 < 0)
200         {
201                 yl = -y0;
202                 y0 = 0;
203         }
204
205         if (x1 > fb_width) x1 = fb_width;
206         if (y1 > fb_height) y1 = fb_height;
207
208         dx = x1 - x0;
209
210         dst = lightmap + y0 * fb_width + x0;
211         src = light + yl * width + xl;
212
213         for (y = y0; y < y1; y++)
214         {
215                 for (x = x0; x < x1; x++)
216                 {
217                         *dst++ |= *src++;
218                 }
219                 dst += fb_width - dx;
220                 src += width - dx;
221         }
222 }
223
224 static void eraseLights()
225 {
226         int i;
227         for (i = 0; i < NUM_BIG_LIGHTS; i++)
228                 eraseArea(&bigLightPoint[i], BIG_LIGHT_WIDTH, BIG_LIGHT_HEIGHT);
229 }
230
231 static void renderLights()
232 {
233         int i;
234         for (i = 0; i < NUM_BIG_LIGHTS; i++)
235                 renderLight(&bigLightPoint[i], BIG_LIGHT_WIDTH, BIG_LIGHT_HEIGHT, bigLight[i]);
236 }
237
238 static void animateLights()
239 {
240         struct point center;
241         float dt = (float)(time_msec - startingTime) / 1000.0f;
242
243         center.x = (fb_width >> 1) - (BIG_LIGHT_WIDTH / 2);
244         center.y = (fb_height >> 1) - (BIG_LIGHT_HEIGHT / 2);
245
246         bigLightPoint[0].x = center.x + sin(1.2f * dt) * 144.0f;
247         bigLightPoint[0].y = center.y + sin(0.8f * dt) * 148.0f;
248
249         bigLightPoint[1].x = center.x + sin(1.5f * dt) * 156.0f;
250         bigLightPoint[1].y = center.y + sin(1.1f * dt) * 92.0f;
251
252         bigLightPoint[2].x = center.x + sin(2.0f * dt) * 112.0f;
253         bigLightPoint[2].y = center.y + sin(1.3f * dt) * 136.0f;
254 }
255
256 static void renderBump(unsigned short *vram)
257 {
258         int i;
259         for (i = 0; i < fb_width * fb_height; i++)
260         {
261                 unsigned short c = lightmap[bumpOffset[i]];
262                 *vram++ = c;
263         }
264 }
265
266 static void draw(void)
267 {
268         eraseLights();
269         animateLights();
270         renderLights();
271         renderBump((unsigned short*)vmem_back);
272
273         drawFps((unsigned short*)vmem_back);
274
275         swap_buffers(0);
276 }