backported build fixes and warnings cleanup from dos
[dosdemo] / src / scr / 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.075f
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 MESH_RANDOM_SEED 173
31
32 #define MIN_FOGGED 40
33
34 #define CAMERA_DISTANCE 1.1f
35
36 /* TODO: Load palette from file */
37 static unsigned short palette[256];
38
39 typedef unsigned int PointSprite;
40 #define MAX_POINT_SPRITES 1024
41 static PointSprite pointSprites[MAX_POINT_SPRITES];
42 int pointSpriteCount = 0;
43 #define PACK_POINT_SPRITE(x, y, col) ((col << 16) | (x << 8) | y)
44 #define UNPACK_COLOR(ps) (ps >> 16)
45 #define UNPACK_X(ps) ((ps >> 8) & 0xFF)
46 #define UNPACK_Y(ps) (ps & 0xFF)
47
48 typedef struct {
49         float x,y,z;
50 } MyVertex ;
51
52 MyVertex vertexBuffer[VERTEX_COUNT];
53 MyVertex vertexBufferAnimated[VERTEX_COUNT];
54 MyVertex vertexBufferProjected[VERTEX_COUNT];
55
56 void clearBlurBuffer();
57 void applyBlur();
58 void blitEffect();
59 void thunder(int x0, int y0, int x1, int y1, unsigned char c0, unsigned char c1, int seed, int randomness, int depth);
60
61 void initMesh();
62 void projectMesh();
63 void animateMesh();
64 void renderMeshToPointSprites(int seed);
65 void renderPointSprites();
66 unsigned char fog(float z);
67 void sortPointSprites();
68
69 static int init(void);
70 static void destroy(void);
71 static void start(long trans_time);
72 static void draw(void);
73
74 static unsigned int lastFrameTime = 0;
75 static float lastFrameDuration = 0.0f;
76 static struct screen scr = {
77         "thunder",
78         init,
79         destroy,
80         start,
81         0,
82         draw
83 };
84
85 struct screen *thunder_screen(void)
86 {
87         return &scr;
88 }
89
90 static int init(void)
91 {
92         int i = 0;
93
94         blurBuffer = malloc(BLUR_BUFFER_SIZE);
95         blurBuffer2 = malloc(BLUR_BUFFER_SIZE);
96
97         clearBlurBuffer();
98
99         /* For now, map to blue */
100         for (i = 0; i < 256; i++) {
101                 palette[i] = (i * i) >> 11;
102         }
103
104         initMesh();
105
106         return 0;
107 }
108
109 static void destroy(void)
110 {
111         free(blurBuffer);
112         blurBuffer = 0;
113         
114         free(blurBuffer2);
115         blurBuffer2 = 0;
116 }
117
118 static void start(long trans_time)
119 {
120         lastFrameTime = time_msec;
121 }
122
123
124 static float remainingThunderDuration = THUNDER_SECONDS;
125 static int thunderPattern = 0;
126
127 static void draw(void)
128 {
129         lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f;
130         lastFrameTime = time_msec;
131
132         remainingThunderDuration -= lastFrameDuration;
133         if (remainingThunderDuration <= 0) {
134                 thunderPattern++;
135                 remainingThunderDuration = THUNDER_SECONDS;
136         }
137         
138         animateMesh();
139         projectMesh();
140         renderMeshToPointSprites(thunderPattern);
141         sortPointSprites();
142         renderPointSprites();
143         
144         
145         applyBlur();
146         blitEffect();
147
148         
149
150         swap_buffers(0);
151 }
152
153 void clearBlurBuffer() {
154         /* Clear the whole buffer (including its padding ) */
155         memset(blurBuffer, 0, BLUR_BUFFER_SIZE);
156         memset(blurBuffer2, 0, BLUR_BUFFER_SIZE);
157 }
158
159
160 void applyBlur() {
161         int i, j;
162         unsigned char *tmp;
163         unsigned char *src = blurBuffer + BLUR_BUFFER_WIDTH + 1;
164         unsigned char *dst = blurBuffer2 + BLUR_BUFFER_WIDTH + 1;
165
166         for (j = 0; j < 120; j++) {
167                 for (i = 0; i < 160; i++) {
168                         *dst = (*(src - 1) + *(src + 1) + *(src - BLUR_BUFFER_WIDTH) + *(src + BLUR_BUFFER_WIDTH)) >> 2;
169                         
170                         if (*dst > BLUR_DARKEN) *dst -= BLUR_DARKEN;
171                         else *dst = 0;
172
173                         dst++;
174                         src++;
175                 }
176                 /* Just skip the padding since we went through the scanline in the inner loop (except from the padding) */
177                 src += 2;
178                 dst += 2;
179         }
180
181         /* Swap blur buffers */
182         tmp = blurBuffer;
183         blurBuffer = blurBuffer2;
184         blurBuffer2 = tmp;
185 }
186
187 void blitEffect() {
188         unsigned int *dst1 = (unsigned int*) fb_pixels;
189         unsigned int *dst2 = dst1 + 160; /* We're writing two pixels at once */
190         unsigned char *src1 = blurBuffer + BLUR_BUFFER_WIDTH + 1;
191         unsigned char *src2 = src1 + BLUR_BUFFER_WIDTH;
192         unsigned char tl, tr, bl, br;
193         int i, j;
194
195         for (j = 0; j < 120; j++) {
196                 for (i = 0; i < 160; i++) {
197                         tl = *src1;
198                         tr = (*src1 + *(src1 + 1)) >> 1;
199                         bl = (*src1 + *src2) >> 1;
200                         br = (tr + ((*src2 + *(src2 + 1)) >> 1)) >> 1;
201
202                         /* Pack 2 pixels in each 32 bit word */
203                         *dst1 = (palette[tr] << 16) | palette[tl];
204                         *dst2 = (palette[br] << 16) | palette[bl];
205
206                         dst1++;
207                         src1++;
208                         dst2++;
209                         src2++;
210                 }
211                 /* Again, skip padding */
212                 src1 += 2;
213                 src2 += 2;
214
215                 /* For now, skip a scanline */
216                 dst1 += 160;
217                 dst2 += 160;
218         }
219
220 }
221
222 void thunder(int x0, int y0, int x1, int y1, unsigned char c0, unsigned char c1, int seed, int randomness, int depth) {
223         int mx, my, i, j;
224         unsigned char *dst;
225         unsigned char mc;
226
227         if (randomness <= 0) randomness = 1;
228         mx = ((x0 + x1) >> 1) + rand() % randomness - randomness / 2;
229         my = ((y0 + y1) >> 1) + rand() % randomness - randomness / 2;
230         mc = (c0 + c1) >> 1;
231
232         if (depth <= 0) return;
233
234         /* Insert a new sprite */
235         if (pointSpriteCount >= MAX_POINT_SPRITES) {
236                 printf("PROBLEM");
237                 return;
238         }
239         pointSprites[pointSpriteCount++] = PACK_POINT_SPRITE(mx, my, mc);
240
241         srand(seed);
242
243         thunder(x0, y0, mx, my, c0, mc, rand(), randomness >> 1, depth-1);
244         thunder(mx, my, x1, y1, mc, c1, rand(), randomness >> 1, depth - 1);
245 }
246
247 MyVertex randomVertex() {
248         MyVertex ret;
249         float l;
250
251         ret.x = rand() % 200 - 100; if (ret.x == 0) ret.x = 1;
252         ret.y = rand() % 200 - 100; if (ret.y == 0) ret.y = 1;
253         ret.z = rand() % 200 - 100; if (ret.z == 0) ret.z = 1;
254         
255         /* Normalize */
256         l = sqrt(ret.x * ret.x + ret.y * ret.y + ret.z * ret.z);
257         ret.x /= l;
258         ret.y /= l;
259         ret.z /= l;
260
261         return ret;
262 }
263
264 void initMesh() {
265         int i;
266
267         srand(MESH_RANDOM_SEED);
268
269         for (i = 0; i < VERTEX_COUNT; i++) {
270                 vertexBuffer[i] = randomVertex();
271         }
272 }
273
274 void animateMesh() {
275         int i = 0;
276         MyVertex bx, by, bz;
277         float yRot;
278
279         yRot = ROTATION_SPEED * time_msec / 1000.0f;
280
281         /* Create rotated basis */
282         bx.x = cos(yRot);
283         bx.y = 0.0f;
284         bx.z = sin(yRot);
285
286         by.x = 0.0f;
287         by.y = 1.0f;
288         by.z = 0.0f;
289
290         bz.x = cos(yRot + M_PI/2.0f);
291         bz.y = 0.0f;
292         bz.z = sin(yRot + M_PI/2.0f);
293
294         for (i = 0; i < VERTEX_COUNT; i++) {
295                 MyVertex v1, v2;
296                 v1 = vertexBuffer[i];
297
298
299                 v1.y *= sin(time_msec / 1000.0f + v1.x + v1.z);
300
301                 /* O re panaia mou */
302                 v2.x = v1.x * bx.x + v1.y * by.x + v1.z * bz.x;
303                 v2.y = v1.x * bx.y + v1.y * by.y + v1.z * bz.y;
304                 v2.z = v1.x * bx.z + v1.y * by.z + v1.z * bz.z;
305
306                 v2.z += CAMERA_DISTANCE;
307
308                 vertexBufferAnimated[i] = v2;
309         }
310 }
311
312 void projectMesh() {
313         int i = 0;
314
315         for (i = 0; i < VERTEX_COUNT; i++) {
316
317                 if (vertexBufferAnimated[i].z <= NEAR_PLANE) {
318                         vertexBufferProjected[i].x = vertexBufferProjected[i].y = 1000.0f;
319                         vertexBufferProjected[i].z = -1.0f;
320                         continue;
321                 }
322
323                 vertexBufferProjected[i].x = vertexBufferAnimated[i].x * PERSPECTIVE_NEUTRAL_DEPTH / vertexBufferAnimated[i].z;
324                 vertexBufferProjected[i].y = vertexBufferAnimated[i].y * PERSPECTIVE_NEUTRAL_DEPTH / vertexBufferAnimated[i].z;
325         }
326 }
327
328 void renderMeshToPointSprites(int seed) {
329         int vertex, j;
330         int sx, sy;
331         unsigned char color;
332         unsigned char *dst;
333         unsigned char fogAtOrigin;
334
335         fogAtOrigin = fog(CAMERA_DISTANCE);
336
337         pointSpriteCount = 0;
338         srand(seed);
339
340         for (vertex = 0; vertex < VERTEX_COUNT; vertex++) {
341                 sx = (int)(vertexBufferProjected[vertex].x * 80) + 80;
342                 sy = (int)(vertexBufferProjected[vertex].y * 60) + 60;
343
344                 thunder(80, 60, sx, sy, fogAtOrigin, fog(vertexBufferAnimated[vertex].z), rand(), THUNDER_RANDOMNESS, 5);
345         }
346 }
347
348 void renderPointSprites() {
349         int i,j;
350         PointSprite sprite;
351         unsigned char *dst;
352         int sx, sy;
353         unsigned char color;
354
355         for (i = 0; i < pointSpriteCount; i++) {
356                 sprite = pointSprites[i];
357
358                 sx = UNPACK_X(sprite);
359                 sy = UNPACK_Y(sprite);
360
361                 if (sx < THUNDER_RECT_SIZE || sx >= 160 - THUNDER_RECT_SIZE || sy < THUNDER_RECT_SIZE || sy >= 120 - THUNDER_RECT_SIZE) continue;
362
363                 dst = blurBuffer + BLUR_BUFFER_WIDTH + 1 + sx + sy * BLUR_BUFFER_WIDTH;
364
365                 color = UNPACK_COLOR(sprite);
366
367                 for (j = 0; j < THUNDER_RECT_SIZE; j++) {
368                         memset(dst, color, THUNDER_RECT_SIZE);
369                         dst += BLUR_BUFFER_WIDTH;
370                 }
371         }
372 }
373
374 unsigned char fog(float z) {
375         unsigned int ret = (unsigned int) (((-(z - CAMERA_DISTANCE)) * 0.5f + 0.5f) * (255.0f - MIN_FOGGED)) + MIN_FOGGED;
376         if (ret > 255) ret = 255;
377         return (unsigned char)ret;
378 }
379
380 void sort(PointSprite *begin, PointSprite *end) {\r
381         PointSprite pivotValue;\r
382         size_t sz;\r
383         PointSprite *left, *right;\r
384         int leftCond, rightCond;\r
385         PointSprite tmp;\r
386 \r
387         sz = end - begin;\r
388 \r
389         if (sz < 2) return; /* already sorted */\r
390         if (sz == 2) {\r
391                 /* trivial case */\r
392                 if (begin[1] < begin[0]) {\r
393                         tmp = begin[0];\r
394                         begin[0] = begin[1];\r
395                         begin[1] = tmp;\r
396                         return;\r
397                 }\r
398         }\r
399 \r
400         /* minimum 3 elements from now on */\r
401 \r
402         /* choose a pivot near the middle, since we frequently sort already sorted arrays */\r
403         pivotValue = begin[sz / 2];\r
404 \r
405         left = begin;\r
406         right = end - 1;\r
407 \r
408         while (right > left) {\r
409                 /* check if left and right elements meet the conditions */\r
410                 leftCond = pivotValue >= *left;\r
411                 rightCond = pivotValue < *right;\r
412 \r
413                 if (!leftCond && !rightCond) {\r
414                         tmp = *left;\r
415                         *left = *right;\r
416                         *right = tmp;\r
417                         left++;\r
418                         right--;\r
419                 }\r
420                 else if (leftCond && rightCond) {\r
421                         left++;\r
422                         right--;\r
423                 }\r
424                 else if (leftCond) {\r
425                         left++;\r
426                 }\r
427                 else {\r
428                         right--;\r
429                 }\r
430         }\r
431 \r
432         /* recursion */\r
433         sort(begin, left);\r
434         sort(left, end);\r
435 }\r
436
437 void sortPointSprites() {
438         sort(pointSprites, pointSprites + pointSpriteCount);
439 }
440