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