a595ba6824e518de78eca4a33b267d79d6244695
[dosdemo] / src / scr / 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
11 static int init(void);
12 static void destroy(void);
13 static void start(long trans_time);
14 static void draw(void);
15
16 static struct screen scr = {
17         "bump",
18         init,
19         destroy,
20         start,
21         0,
22         draw
23 };
24
25 struct point {
26         int x, y;
27 };
28
29 #define NUM_BIG_LIGHTS 3
30 #define BIG_LIGHT_WIDTH 256
31 #define BIG_LIGHT_HEIGHT BIG_LIGHT_WIDTH
32
33 #define NUM_PARTICLES 64
34 #define PARTICLE_LIGHT_WIDTH 32
35 #define PARTICLE_LIGHT_HEIGHT 32
36
37
38 static unsigned long startingTime;
39
40 static unsigned char *heightmap;
41 static unsigned short *lightmap;
42 static int *bumpOffset;
43
44 static unsigned short *bigLight[NUM_BIG_LIGHTS];
45 static struct point bigLightPoint[NUM_BIG_LIGHTS];
46
47 static unsigned short *particleLight;
48 static struct point particlePoint[NUM_PARTICLES];
49
50 struct screen *bump_screen(void)
51 {
52         return &scr;
53 }
54
55 static int init(void)
56 {
57         int i, j, x, y, c, r, g, b;
58
59         const int numBlurs = 3;
60         const int lightRadius = BIG_LIGHT_WIDTH / 2;
61         const int particleRadius = PARTICLE_LIGHT_WIDTH / 2;
62
63         const int bigLightSize = BIG_LIGHT_WIDTH * BIG_LIGHT_HEIGHT;
64         const int particleLightSize = PARTICLE_LIGHT_WIDTH * PARTICLE_LIGHT_HEIGHT;
65         const int fb_size = fb_width * fb_height;
66
67         /* Just some parameters to temporary test the colors of 3 lights
68          * if every light uses it's own channel bits, it's better
69          */
70         const float rgbMul[9] = { 1.0f, 0.0f, 0.0f, 
71                                                                   0.0f, 1.0f, 0.0f,
72                                                                   0.0f, 0.0f, 1.0f};
73
74         heightmap = malloc(sizeof(*heightmap) * fb_size);
75         lightmap = malloc(sizeof(*lightmap) * fb_size);
76         bumpOffset = malloc(sizeof(*bumpOffset) * fb_size);
77
78         for (i = 0; i < NUM_BIG_LIGHTS; i++)
79                 bigLight[i] = malloc(sizeof(*bigLight[i]) * bigLightSize);
80
81         particleLight = malloc(sizeof(*particleLight) * particleLightSize);
82
83         memset(lightmap, 0, sizeof(*lightmap) * fb_size);
84         memset(bumpOffset, 0, sizeof(*bumpOffset) * fb_size);
85         memset(particlePoint, 0, sizeof(*particlePoint) * NUM_PARTICLES);
86
87         /* Create random junk */
88         for (i = 0; i < fb_size; i++)
89                 heightmap[i] = rand() & 255;
90
91         /* Blur to smooth */
92         for (j = 0; j < numBlurs; j++)
93                 for (i = 0; i < fb_size; i++)
94                         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;
95
96         /* Inclination precalculation */
97         i = 0;
98         for (y = 0; y < fb_height; y++)
99         {
100                 for (x = 0; x < fb_width; x++)
101                 {
102                         const float offsetPower = 0.75f;
103                         int dx, dy, xp, yp;
104
105                         dx = i < fb_size - 1 ? (int)((heightmap[i] - heightmap[i + 1]) * offsetPower) : 0;
106                         dy = i < fb_size - fb_width ? (int)((heightmap[i] - heightmap[i + fb_width]) * offsetPower) : 0;
107
108                         xp = x + dx;
109                         if (xp < 0) xp = 0;
110                         if (xp > fb_width - 1) xp = fb_width - 1;
111
112                         yp = y + dy;
113                         if (yp < 0) yp = 0;
114                         if (yp > fb_height - 1) yp = fb_height - 1;
115
116                         bumpOffset[i++] = yp * fb_width + xp;
117                 }
118         }
119
120         /* Generate three lights */
121         i = 0;
122         for (y = 0; y < BIG_LIGHT_HEIGHT; y++)
123         {
124                 int yc = y - (BIG_LIGHT_HEIGHT / 2);
125                 for (x = 0; x < BIG_LIGHT_WIDTH; x++)
126                 {
127                         int xc = x - (BIG_LIGHT_WIDTH / 2);
128                         float d = (float)sqrt(xc * xc + yc * yc);
129                         float invDist = ((float)lightRadius - (float)sqrt(xc * xc + yc * yc)) / (float)lightRadius;
130                         if (invDist < 0.0f) invDist = 0.0f;
131
132                         c = (int)(invDist * 63);
133                         r = c >> 1;
134                         g = c;
135                         b = c >> 1;
136
137                         for (j = 0; j < NUM_BIG_LIGHTS; j++)
138                         {
139                                 bigLight[j][i] = ((int)(r * rgbMul[j * 3]) << 11) | ((int)(g * rgbMul[j * 3 + 1]) << 5) | (int)(b * rgbMul[j * 3 + 2]);
140                         }
141                         i++;
142                 }
143         }
144
145         i = 0;
146         for (y = 0; y < PARTICLE_LIGHT_HEIGHT; y++)
147         {
148                 int yc = y - (PARTICLE_LIGHT_HEIGHT / 2);
149                 for (x = 0; x < PARTICLE_LIGHT_WIDTH; x++)
150                 {
151                         int xc = x - (PARTICLE_LIGHT_WIDTH / 2);
152
153                         float invDist = ((float)particleRadius - (float)sqrt(xc * xc + yc * yc)) / (float)particleRadius;
154                         if (invDist < 0.0f) invDist = 0.0f;
155
156                         c = (int)(pow(invDist, 0.75f) * 63);
157                         particleLight[i++] = ((c >> 1) << 11) | (c << 5) | (c >> 1);
158                 }
159         }
160
161         return 0;
162 }
163
164 static void destroy(void)
165 {
166 }
167
168 static void start(long trans_time)
169 {
170         startingTime = time_msec;
171 }
172
173 static void eraseArea(struct point *p, int width, int height)
174 {
175         int x, y, dx;
176         unsigned short *dst;
177
178         int x0 = p->x;
179         int y0 = p->y;
180         int x1 = p->x + width;
181         int y1 = p->y + height;
182
183         if (x0 < 0) x0 = 0;
184         if (y0 < 0) y0 = 0;
185         if (x1 > fb_width) x1 = fb_width;
186         if (y1 > fb_height) y1 = fb_height;
187
188         dx = x1 - x0;
189
190         dst = lightmap + y0 * fb_width + x0;
191
192         for (y = y0; y < y1; y++)
193         {
194                 for (x = x0; x < x1; x++)
195                 {
196                         *dst++ = 0;
197                 }
198                 dst += fb_width - dx;
199         }
200 }
201
202
203 static void renderLight(struct point *p, int width, int height, unsigned short *light)
204 {
205         int x, y, dx;
206         unsigned short *src, *dst;
207
208         int x0 = p->x;
209         int y0 = p->y;
210         int x1 = p->x + width;
211         int y1 = p->y + height;
212
213         int xl = 0;
214         int yl = 0;
215
216         if (x0 < 0)
217         {
218                 xl = -x0;
219                 x0 = 0;
220         }
221
222         if (y0 < 0)
223         {
224                 yl = -y0;
225                 y0 = 0;
226         }
227
228         if (x1 > fb_width) x1 = fb_width;
229         if (y1 > fb_height) y1 = fb_height;
230
231         dx = x1 - x0;
232
233         dst = lightmap + y0 * fb_width + x0;
234         src = light + yl * width + xl;
235
236         for (y = y0; y < y1; y++)
237         {
238                 for (x = x0; x < x1; x++)
239                 {
240                         *dst++ |= *src++;
241                 }
242                 dst += fb_width - dx;
243                 src += width - dx;
244         }
245 }
246
247 static void eraseLights()
248 {
249         int i;
250         for (i = 0; i < NUM_BIG_LIGHTS; i++)
251                 eraseArea(&bigLightPoint[i], BIG_LIGHT_WIDTH, BIG_LIGHT_HEIGHT);
252 }
253
254 static void renderLights()
255 {
256         int i;
257         for (i = 0; i < NUM_BIG_LIGHTS; i++)
258                 renderLight(&bigLightPoint[i], BIG_LIGHT_WIDTH, BIG_LIGHT_HEIGHT, bigLight[i]);
259 }
260
261 static void renderParticles()
262 {
263         int i;
264         for (i = 0; i < NUM_PARTICLES; i++)
265                 renderLight(&particlePoint[i], PARTICLE_LIGHT_WIDTH, PARTICLE_LIGHT_HEIGHT, particleLight);
266 }
267
268 static void animateLights()
269 {
270         struct point center;
271         float dt = (float)(time_msec - startingTime) / 1000.0f;
272         float tt = 1.0f - sin(dt);
273         float disperse = tt * 64.0f;
274
275         center.x = (fb_width >> 1) - (BIG_LIGHT_WIDTH / 2);
276         center.y = (fb_height >> 1) - (BIG_LIGHT_HEIGHT / 2);
277
278         bigLightPoint[0].x = center.x + sin(1.2f * dt) * (144.0f + disperse);
279         bigLightPoint[0].y = center.y + sin(0.8f * dt) * (148.0f + disperse);
280
281         bigLightPoint[1].x = center.x + sin(1.5f * dt) * (156.0f + disperse);
282         bigLightPoint[1].y = center.y + sin(1.1f * dt) * (92.0f + disperse);
283
284         bigLightPoint[2].x = center.x + sin(2.0f * dt) * (112.0f + disperse);
285         bigLightPoint[2].y = center.y + sin(1.3f * dt) * (136.0f + disperse);
286 }
287
288 static void renderBump(unsigned short *vram)
289 {
290         int i;
291         for (i = 0; i < fb_width * fb_height; i++)
292         {
293                 unsigned short c = lightmap[bumpOffset[i]];
294                 *vram++ = c;
295         }
296 }
297
298 static void animateParticles()
299 {
300         int i;
301         struct point center;
302         float dt = (float)(time_msec - startingTime) / 2000.0f;
303         float tt = sin(dt);
304
305         center.x = (fb_width >> 1) - (PARTICLE_LIGHT_WIDTH / 2);
306         center.y = (fb_height >> 1) - (PARTICLE_LIGHT_HEIGHT / 2);
307
308         for (i = 0; i < NUM_PARTICLES; i++)
309         {
310                 particlePoint[i].x = center.x + (sin(1.2f * (i*i*i + dt)) * 74.0f + sin(0.6f * (i + dt)) * 144.0f) * tt;
311                 particlePoint[i].y = center.y + (sin(1.8f * (i + dt)) * 68.0f + sin(0.5f * (i*i + dt)) * 132.0f) * tt;
312         }
313 }
314
315 static void draw(void)
316 {
317         memset(lightmap, 0, fb_width * fb_height * sizeof(*lightmap));
318
319         /*eraseLights();*/
320         animateLights();
321         renderLights();
322
323         animateParticles();
324         renderParticles();
325
326         renderBump((unsigned short*)fb_pixels);
327
328         swap_buffers(0);
329 }