Many thunders from origin to random points on a rotating sphere
[dosdemo] / src / thunder.c
1 /* thunder. c */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <math.h>
6 #include <assert.h>
7 #include "imago2.h"
8 #include "demo.h"
9 #include "screen.h"
10
11 /* Render blur in half x half dimenstions. Add one pixel padding in all 
12  * directions (2 pixels horizontally, 2 pixels vertically).
13  */
14 #define BLUR_BUFFER_WIDTH (320/2 + 2)
15 #define BLUR_BUFFER_HEIGHT (240/2 + 2)
16 #define BLUR_BUFFER_SIZE (BLUR_BUFFER_WIDTH * BLUR_BUFFER_HEIGHT)
17 static unsigned char *blurBuffer, *blurBuffer2;
18
19 #define BLUR_DARKEN 4
20
21 #define THUNDER_RECT_SIZE 2
22 #define THUNDER_RANDOMNESS 16
23 #define THUNDER_SECONDS 0.1f
24
25 #define VERTEX_COUNT 12
26 #define PERSPECTIVE_NEUTRAL_DEPTH 0.5f
27 #define NEAR_PLANE 0.01f
28 #define ROTATION_SPEED 1.5f
29
30 #define PI 3.14159f
31
32 /* TODO: Load palette from file */
33 static unsigned short palette[256];
34
35 typedef struct {
36         float x,y,z;
37 } MyVertex ;
38
39 MyVertex vertexBuffer[VERTEX_COUNT];
40 MyVertex vertexBufferAnimated[VERTEX_COUNT];
41 MyVertex vertexBufferProjected[VERTEX_COUNT];
42
43 void clearBlurBuffer();
44 void applyBlur();
45 void blitEffect();
46 void thunder(int x0, int y0, int x1, int y1, int seed, int randomness, int depth);
47
48 void initMesh();
49 void projectMesh();
50 void animateMesh();
51 void renderMesh(int seed);
52
53 static int init(void);
54 static void destroy(void);
55 static void start(long trans_time);
56 static void stop(long trans_time);
57 static void draw(void);
58
59 static unsigned int lastFrameTime = 0;
60 static float lastFrameDuration = 0.0f;
61 static struct screen scr = {
62         "thunder",
63         init,
64         destroy,
65         start,
66         0,
67         draw
68 };
69
70 struct screen *thunder_screen(void)
71 {
72         return &scr;
73 }
74
75 static int init(void)
76 {
77         int i = 0;
78
79         blurBuffer = malloc(BLUR_BUFFER_SIZE);
80         blurBuffer2 = malloc(BLUR_BUFFER_SIZE);
81
82         clearBlurBuffer();
83
84         /* For now, map to blue */
85         for (i = 0; i < 256; i++) {
86                 palette[i] = (i * i) >> 11;
87         }
88
89         initMesh();
90
91         return 0;
92 }
93
94 static void destroy(void)
95 {
96         free(blurBuffer);
97         blurBuffer = 0;
98         
99         free(blurBuffer2);
100         blurBuffer2 = 0;
101 }
102
103 static void start(long trans_time)
104 {
105         lastFrameTime = time_msec;
106 }
107
108
109 static float remainingThunderDuration = THUNDER_SECONDS;
110 static int thunderPattern = 0;
111
112 static void draw(void)
113 {
114         lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f;
115         lastFrameTime = time_msec;
116
117         remainingThunderDuration -= lastFrameDuration;
118         if (remainingThunderDuration <= 0) {
119                 thunderPattern++;
120                 remainingThunderDuration = THUNDER_SECONDS;
121         }
122         
123         animateMesh();
124         projectMesh();
125         renderMesh(thunderPattern);
126         
127         
128         applyBlur();
129         blitEffect();
130
131         
132
133         swap_buffers(0);
134 }
135
136 void clearBlurBuffer() {
137         /* Clear the whole buffer (including its padding ) */
138         memset(blurBuffer, 0, BLUR_BUFFER_SIZE);
139         memset(blurBuffer2, 0, BLUR_BUFFER_SIZE);
140 }
141
142
143 void applyBlur() {
144         int i, j;
145         unsigned char *tmp;
146         unsigned char *src = blurBuffer + BLUR_BUFFER_WIDTH + 1;
147         unsigned char *dst = blurBuffer2 + BLUR_BUFFER_WIDTH + 1;
148
149         for (j = 0; j < 120; j++) {
150                 for (i = 0; i < 160; i++) {
151                         *dst = (*(src - 1) + *(src + 1) + *(src - BLUR_BUFFER_WIDTH) + *(src + BLUR_BUFFER_WIDTH)) >> 2;
152                         
153                         if (*dst > BLUR_DARKEN) *dst -= BLUR_DARKEN;
154                         else *dst = 0;
155
156                         dst++;
157                         src++;
158                 }
159                 /* Just skip the padding since we went through the scanline in the inner loop (except from the padding) */
160                 src += 2;
161                 dst += 2;
162         }
163
164         /* Swap blur buffers */
165         tmp = blurBuffer;
166         blurBuffer = blurBuffer2;
167         blurBuffer2 = tmp;
168 }
169
170 void blitEffect() {
171         unsigned int *dst1 = (unsigned int*) vmem_back;
172         unsigned int *dst2 = dst1 + 160; /* We're writing two pixels at once */
173         unsigned char *src1 = blurBuffer + BLUR_BUFFER_WIDTH + 1;
174         unsigned char *src2 = src1 + BLUR_BUFFER_WIDTH;
175         unsigned char tl, tr, bl, br;
176         int i, j;
177
178         for (j = 0; j < 120; j++) {
179                 for (i = 0; i < 160; i++) {
180                         tl = *src1;
181                         tr = (*src1 + *(src1 + 1)) >> 1;
182                         bl = (*src1 + *src2) >> 1;
183                         br = tr + ((*src2 + *(src2 + 1)) >> 1) >> 1;
184
185                         /* Pack 2 pixels in each 32 bit word */
186                         *dst1 = (palette[tr] << 16) | palette[tl];
187                         *dst2 = (palette[br] << 16) | palette[bl];
188
189                         dst1++;
190                         src1++;
191                         dst2++;
192                         src2++;
193                 }
194                 /* Again, skip padding */
195                 src1 += 2;
196                 src2 += 2;
197
198                 /* For now, skip a scanline */
199                 dst1 += 160;
200                 dst2 += 160;
201         }
202
203 }
204
205 void thunder(int x0, int y0, int x1, int y1, int seed, int randomness, int depth) {
206         int mx, my, i, j;
207         unsigned char *dst;
208
209         if (randomness <= 0) randomness = 1;
210         mx = ((x0 + x1) >> 1) + rand() % randomness - randomness / 2;
211         my = ((y0 + y1) >> 1) + rand() % randomness - randomness / 2;
212         dst = blurBuffer + BLUR_BUFFER_WIDTH + 1 + mx + my * BLUR_BUFFER_WIDTH;
213
214         if (depth <= 0) return;
215         if (mx < THUNDER_RECT_SIZE || mx >= 160 - THUNDER_RECT_SIZE || my < THUNDER_RECT_SIZE || my >= 120 - THUNDER_RECT_SIZE) return;
216
217         srand(seed);
218
219         for (j = 0; j < THUNDER_RECT_SIZE; j++) {
220                 memset(dst, 255, THUNDER_RECT_SIZE);
221                 dst += BLUR_BUFFER_WIDTH;
222         }
223
224         thunder(x0, y0, mx, my, rand(), randomness >> 1, depth-1);
225         thunder(mx, my, x1, y1, rand(), randomness >> 1, depth - 1);
226 }
227
228 MyVertex randomVertex() {
229         MyVertex ret;
230         float l;
231
232         ret.x = rand() % 200 - 100; if (ret.x == 0) ret.x = 1;
233         ret.y = rand() % 200 - 100; if (ret.y == 0) ret.y = 1;
234         ret.z = rand() % 200 - 100; if (ret.z == 0) ret.z = 1;
235         
236         // Normalize
237         l = sqrt(ret.x * ret.x + ret.y * ret.y + ret.z * ret.z);
238         ret.x /= l;
239         ret.y /= l;
240         ret.z /= l;
241
242         return ret;
243 }
244
245 void initMesh() {
246         int i;
247
248         for (i = 0; i < VERTEX_COUNT; i++) {
249                 vertexBuffer[i] = randomVertex();
250         }
251 }
252
253 void animateMesh() {
254         int i = 0;
255         MyVertex bx, by, bz;
256         float yRot;
257
258         yRot = ROTATION_SPEED * time_msec / 1000.0f;
259
260         /* Create rotated basis */
261         bx.x = cos(yRot);
262         bx.y = 0.0f;
263         bx.z = sin(yRot);
264
265         by.x = 0.0f;
266         by.y = 1.0f;
267         by.z = 0.0f;
268
269         bz.x = cos(yRot + PI/2.0f);
270         bz.y = 0.0f;
271         bz.z = sin(yRot + PI/2.0f);
272
273         for (i = 0; i < VERTEX_COUNT; i++) {
274                 MyVertex v1, v2;
275                 v1 = vertexBuffer[i];
276
277                 /* O re panaia mou */
278                 v2.x = v1.x * bx.x + v1.y * by.x + v1.z * bz.x;
279                 v2.y = v1.x * bx.y + v1.y * by.y + v1.z * bz.y;
280                 v2.z = v1.x * bx.z + v1.y * by.z + v1.z * bz.z;
281                 
282
283                 v2.z += 1.00f;
284
285                 vertexBufferAnimated[i] = v2;
286         }
287 }
288
289 void projectMesh() {
290         int i = 0;
291
292         for (i = 0; i < VERTEX_COUNT; i++) {
293
294                 if (vertexBufferAnimated[i].z <= NEAR_PLANE) {
295                         vertexBufferProjected[i].x = vertexBufferProjected[i].y = 1000.0f;
296                         vertexBufferProjected[i].z = -1.0f;
297                         continue;
298                 }
299
300                 vertexBufferProjected[i].x = vertexBufferAnimated[i].x * PERSPECTIVE_NEUTRAL_DEPTH / vertexBufferAnimated[i].z;
301                 vertexBufferProjected[i].y = vertexBufferAnimated[i].y * PERSPECTIVE_NEUTRAL_DEPTH / vertexBufferAnimated[i].z;
302         }
303 }
304
305 void renderMesh(int seed) {
306         int vertex, j;
307         int sx, sy;
308         unsigned char *dst;
309
310         srand(seed);
311
312         for (vertex = 0; vertex < VERTEX_COUNT; vertex++) {
313                 sx = (int)(vertexBufferProjected[vertex].x * 80) + 80;
314                 sy = (int)(vertexBufferProjected[vertex].y * 60) + 60;
315
316                 /*if (sx < THUNDER_RECT_SIZE || sx >= 160 - THUNDER_RECT_SIZE || sy < THUNDER_RECT_SIZE || sy >= 120 - THUNDER_RECT_SIZE) return;*/
317
318                 thunder(80, 60, sx, sy, rand(), THUNDER_RANDOMNESS, 5);         
319         }
320 }