reorganized the source code
[dosdemo] / src / scr / thunder.c
diff --git a/src/scr/thunder.c b/src/scr/thunder.c
new file mode 100644 (file)
index 0000000..cacb7b5
--- /dev/null
@@ -0,0 +1,441 @@
+/* thunder. c */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include "imago2.h"
+#include "demo.h"
+#include "screen.h"
+
+/* Render blur in half x half dimenstions. Add one pixel padding in all 
+ * directions (2 pixels horizontally, 2 pixels vertically).
+ */
+#define BLUR_BUFFER_WIDTH (320/2 + 2)
+#define BLUR_BUFFER_HEIGHT (240/2 + 2)
+#define BLUR_BUFFER_SIZE (BLUR_BUFFER_WIDTH * BLUR_BUFFER_HEIGHT)
+static unsigned char *blurBuffer, *blurBuffer2;
+
+#define BLUR_DARKEN 4
+
+#define THUNDER_RECT_SIZE 2
+#define THUNDER_RANDOMNESS 16
+#define THUNDER_SECONDS 0.075f
+
+#define VERTEX_COUNT 12
+#define PERSPECTIVE_NEUTRAL_DEPTH 0.5f
+#define NEAR_PLANE 0.01f
+#define ROTATION_SPEED 1.5f
+
+#define MESH_RANDOM_SEED 173
+
+#define MIN_FOGGED 40
+
+#define CAMERA_DISTANCE 1.1f
+
+/* TODO: Load palette from file */
+static unsigned short palette[256];
+
+typedef unsigned int PointSprite;
+#define MAX_POINT_SPRITES 1024
+static PointSprite pointSprites[MAX_POINT_SPRITES];
+int pointSpriteCount = 0;
+#define PACK_POINT_SPRITE(x, y, col) ((col << 16) | (x << 8) | y)
+#define UNPACK_COLOR(ps) (ps >> 16)
+#define UNPACK_X(ps) ((ps >> 8) & 0xFF)
+#define UNPACK_Y(ps) (ps & 0xFF)
+
+typedef struct {
+       float x,y,z;
+} MyVertex ;
+
+MyVertex vertexBuffer[VERTEX_COUNT];
+MyVertex vertexBufferAnimated[VERTEX_COUNT];
+MyVertex vertexBufferProjected[VERTEX_COUNT];
+
+void clearBlurBuffer();
+void applyBlur();
+void blitEffect();
+void thunder(int x0, int y0, int x1, int y1, unsigned char c0, unsigned char c1, int seed, int randomness, int depth);
+
+void initMesh();
+void projectMesh();
+void animateMesh();
+void renderMeshToPointSprites(int seed);
+void renderPointSprites();
+unsigned char fog(float z);
+void sortPointSprites();
+
+static int init(void);
+static void destroy(void);
+static void start(long trans_time);
+static void stop(long trans_time);
+static void draw(void);
+
+static unsigned int lastFrameTime = 0;
+static float lastFrameDuration = 0.0f;
+static struct screen scr = {
+       "thunder",
+       init,
+       destroy,
+       start,
+       0,
+       draw
+};
+
+struct screen *thunder_screen(void)
+{
+       return &scr;
+}
+
+static int init(void)
+{
+       int i = 0;
+
+       blurBuffer = malloc(BLUR_BUFFER_SIZE);
+       blurBuffer2 = malloc(BLUR_BUFFER_SIZE);
+
+       clearBlurBuffer();
+
+       /* For now, map to blue */
+       for (i = 0; i < 256; i++) {
+               palette[i] = (i * i) >> 11;
+       }
+
+       initMesh();
+
+       return 0;
+}
+
+static void destroy(void)
+{
+       free(blurBuffer);
+       blurBuffer = 0;
+       
+       free(blurBuffer2);
+       blurBuffer2 = 0;
+}
+
+static void start(long trans_time)
+{
+       lastFrameTime = time_msec;
+}
+
+
+static float remainingThunderDuration = THUNDER_SECONDS;
+static int thunderPattern = 0;
+
+static void draw(void)
+{
+       lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f;
+       lastFrameTime = time_msec;
+
+       remainingThunderDuration -= lastFrameDuration;
+       if (remainingThunderDuration <= 0) {
+               thunderPattern++;
+               remainingThunderDuration = THUNDER_SECONDS;
+       }
+       
+       animateMesh();
+       projectMesh();
+       renderMeshToPointSprites(thunderPattern);
+       sortPointSprites();
+       renderPointSprites();
+       
+       
+       applyBlur();
+       blitEffect();
+
+       
+
+       swap_buffers(0);
+}
+
+void clearBlurBuffer() {
+       /* Clear the whole buffer (including its padding ) */
+       memset(blurBuffer, 0, BLUR_BUFFER_SIZE);
+       memset(blurBuffer2, 0, BLUR_BUFFER_SIZE);
+}
+
+
+void applyBlur() {
+       int i, j;
+       unsigned char *tmp;
+       unsigned char *src = blurBuffer + BLUR_BUFFER_WIDTH + 1;
+       unsigned char *dst = blurBuffer2 + BLUR_BUFFER_WIDTH + 1;
+
+       for (j = 0; j < 120; j++) {
+               for (i = 0; i < 160; i++) {
+                       *dst = (*(src - 1) + *(src + 1) + *(src - BLUR_BUFFER_WIDTH) + *(src + BLUR_BUFFER_WIDTH)) >> 2;
+                       
+                       if (*dst > BLUR_DARKEN) *dst -= BLUR_DARKEN;
+                       else *dst = 0;
+
+                       dst++;
+                       src++;
+               }
+               /* Just skip the padding since we went through the scanline in the inner loop (except from the padding) */
+               src += 2;
+               dst += 2;
+       }
+
+       /* Swap blur buffers */
+       tmp = blurBuffer;
+       blurBuffer = blurBuffer2;
+       blurBuffer2 = tmp;
+}
+
+void blitEffect() {
+       unsigned int *dst1 = (unsigned int*) fb_pixels;
+       unsigned int *dst2 = dst1 + 160; /* We're writing two pixels at once */
+       unsigned char *src1 = blurBuffer + BLUR_BUFFER_WIDTH + 1;
+       unsigned char *src2 = src1 + BLUR_BUFFER_WIDTH;
+       unsigned char tl, tr, bl, br;
+       int i, j;
+
+       for (j = 0; j < 120; j++) {
+               for (i = 0; i < 160; i++) {
+                       tl = *src1;
+                       tr = (*src1 + *(src1 + 1)) >> 1;
+                       bl = (*src1 + *src2) >> 1;
+                       br = (tr + ((*src2 + *(src2 + 1)) >> 1)) >> 1;
+
+                       /* Pack 2 pixels in each 32 bit word */
+                       *dst1 = (palette[tr] << 16) | palette[tl];
+                       *dst2 = (palette[br] << 16) | palette[bl];
+
+                       dst1++;
+                       src1++;
+                       dst2++;
+                       src2++;
+               }
+               /* Again, skip padding */
+               src1 += 2;
+               src2 += 2;
+
+               /* For now, skip a scanline */
+               dst1 += 160;
+               dst2 += 160;
+       }
+
+}
+
+void thunder(int x0, int y0, int x1, int y1, unsigned char c0, unsigned char c1, int seed, int randomness, int depth) {
+       int mx, my, i, j;
+       unsigned char *dst;
+       unsigned char mc;
+
+       if (randomness <= 0) randomness = 1;
+       mx = ((x0 + x1) >> 1) + rand() % randomness - randomness / 2;
+       my = ((y0 + y1) >> 1) + rand() % randomness - randomness / 2;
+       mc = (c0 + c1) >> 1;
+
+       if (depth <= 0) return;
+
+       /* Insert a new sprite */
+       if (pointSpriteCount >= MAX_POINT_SPRITES) {
+               printf("PROBLEM");
+               return;
+       }
+       pointSprites[pointSpriteCount++] = PACK_POINT_SPRITE(mx, my, mc);
+
+       srand(seed);
+
+       thunder(x0, y0, mx, my, c0, mc, rand(), randomness >> 1, depth-1);
+       thunder(mx, my, x1, y1, mc, c1, rand(), randomness >> 1, depth - 1);
+}
+
+MyVertex randomVertex() {
+       MyVertex ret;
+       float l;
+
+       ret.x = rand() % 200 - 100; if (ret.x == 0) ret.x = 1;
+       ret.y = rand() % 200 - 100; if (ret.y == 0) ret.y = 1;
+       ret.z = rand() % 200 - 100; if (ret.z == 0) ret.z = 1;
+       
+       // Normalize
+       l = sqrt(ret.x * ret.x + ret.y * ret.y + ret.z * ret.z);
+       ret.x /= l;
+       ret.y /= l;
+       ret.z /= l;
+
+       return ret;
+}
+
+void initMesh() {
+       int i;
+
+       srand(MESH_RANDOM_SEED);
+
+       for (i = 0; i < VERTEX_COUNT; i++) {
+               vertexBuffer[i] = randomVertex();
+       }
+}
+
+void animateMesh() {
+       int i = 0;
+       MyVertex bx, by, bz;
+       float yRot;
+
+       yRot = ROTATION_SPEED * time_msec / 1000.0f;
+
+       /* Create rotated basis */
+       bx.x = cos(yRot);
+       bx.y = 0.0f;
+       bx.z = sin(yRot);
+
+       by.x = 0.0f;
+       by.y = 1.0f;
+       by.z = 0.0f;
+
+       bz.x = cos(yRot + M_PI/2.0f);
+       bz.y = 0.0f;
+       bz.z = sin(yRot + M_PI/2.0f);
+
+       for (i = 0; i < VERTEX_COUNT; i++) {
+               MyVertex v1, v2;
+               v1 = vertexBuffer[i];
+
+
+               v1.y *= sin(time_msec / 1000.0f + v1.x + v1.z);
+
+               /* O re panaia mou */
+               v2.x = v1.x * bx.x + v1.y * by.x + v1.z * bz.x;
+               v2.y = v1.x * bx.y + v1.y * by.y + v1.z * bz.y;
+               v2.z = v1.x * bx.z + v1.y * by.z + v1.z * bz.z;
+
+               v2.z += CAMERA_DISTANCE;
+
+               vertexBufferAnimated[i] = v2;
+       }
+}
+
+void projectMesh() {
+       int i = 0;
+
+       for (i = 0; i < VERTEX_COUNT; i++) {
+
+               if (vertexBufferAnimated[i].z <= NEAR_PLANE) {
+                       vertexBufferProjected[i].x = vertexBufferProjected[i].y = 1000.0f;
+                       vertexBufferProjected[i].z = -1.0f;
+                       continue;
+               }
+
+               vertexBufferProjected[i].x = vertexBufferAnimated[i].x * PERSPECTIVE_NEUTRAL_DEPTH / vertexBufferAnimated[i].z;
+               vertexBufferProjected[i].y = vertexBufferAnimated[i].y * PERSPECTIVE_NEUTRAL_DEPTH / vertexBufferAnimated[i].z;
+       }
+}
+
+void renderMeshToPointSprites(int seed) {
+       int vertex, j;
+       int sx, sy;
+       unsigned char color;
+       unsigned char *dst;
+       unsigned char fogAtOrigin;
+
+       fogAtOrigin = fog(CAMERA_DISTANCE);
+
+       pointSpriteCount = 0;
+       srand(seed);
+
+       for (vertex = 0; vertex < VERTEX_COUNT; vertex++) {
+               sx = (int)(vertexBufferProjected[vertex].x * 80) + 80;
+               sy = (int)(vertexBufferProjected[vertex].y * 60) + 60;
+
+               thunder(80, 60, sx, sy, fogAtOrigin, fog(vertexBufferAnimated[vertex].z), rand(), THUNDER_RANDOMNESS, 5);
+       }
+}
+
+void renderPointSprites() {
+       int i,j;
+       PointSprite sprite;
+       unsigned char *dst;
+       int sx, sy;
+       unsigned char color;
+
+       for (i = 0; i < pointSpriteCount; i++) {
+               sprite = pointSprites[i];
+
+               sx = UNPACK_X(sprite);
+               sy = UNPACK_Y(sprite);
+
+               if (sx < THUNDER_RECT_SIZE || sx >= 160 - THUNDER_RECT_SIZE || sy < THUNDER_RECT_SIZE || sy >= 120 - THUNDER_RECT_SIZE) continue;
+
+               dst = blurBuffer + BLUR_BUFFER_WIDTH + 1 + sx + sy * BLUR_BUFFER_WIDTH;
+
+               color = UNPACK_COLOR(sprite);
+
+               for (j = 0; j < THUNDER_RECT_SIZE; j++) {
+                       memset(dst, color, THUNDER_RECT_SIZE);
+                       dst += BLUR_BUFFER_WIDTH;
+               }
+       }
+}
+
+unsigned char fog(float z) {
+       unsigned int ret = (unsigned int) (((-(z - CAMERA_DISTANCE)) * 0.5f + 0.5f) * (255.0f - MIN_FOGGED)) + MIN_FOGGED;
+       if (ret > 255) ret = 255;
+       return (unsigned char)ret;
+}
+
+void sort(PointSprite *begin, PointSprite *end) {\r
+       PointSprite pivotValue;\r
+       size_t sz;\r
+       PointSprite *left, *right;\r
+       int leftCond, rightCond;\r
+       PointSprite tmp;\r
+\r
+       sz = end - begin;\r
+\r
+       if (sz < 2) return; /* already sorted */\r
+       if (sz == 2) {\r
+               /* trivial case */\r
+               if (begin[1] < begin[0]) {\r
+                       tmp = begin[0];\r
+                       begin[0] = begin[1];\r
+                       begin[1] = tmp;\r
+                       return;\r
+               }\r
+       }\r
+\r
+       /* minimum 3 elements from now on */\r
+\r
+       /* choose a pivot near the middle, since we frequently sort already sorted arrays */\r
+       pivotValue = begin[sz / 2];\r
+\r
+       left = begin;\r
+       right = end - 1;\r
+\r
+       while (right > left) {\r
+               /* check if left and right elements meet the conditions */\r
+               leftCond = pivotValue >= *left;\r
+               rightCond = pivotValue < *right;\r
+\r
+               if (!leftCond && !rightCond) {\r
+                       tmp = *left;\r
+                       *left = *right;\r
+                       *right = tmp;\r
+                       left++;\r
+                       right--;\r
+               }\r
+               else if (leftCond && rightCond) {\r
+                       left++;\r
+                       right--;\r
+               }\r
+               else if (leftCond) {\r
+                       left++;\r
+               }\r
+               else {\r
+                       right--;\r
+               }\r
+       }\r
+\r
+       /* recursion */\r
+       sort(begin, left);\r
+       sort(left, end);\r
+}\r
+
+void sortPointSprites() {
+       sort(pointSprites, pointSprites + pointSpriteCount);
+}
+