Fog and sorting
authorMichael Georgoulopoulos <mgeorgoulopoulos@gmail.com>
Sun, 16 Oct 2016 23:26:16 +0000 (02:26 +0300)
committerMichael Georgoulopoulos <mgeorgoulopoulos@gmail.com>
Sun, 16 Oct 2016 23:26:16 +0000 (02:26 +0300)
src/thunder.c

index db25bb2..59843c2 100644 (file)
@@ -27,11 +27,26 @@ static unsigned char *blurBuffer, *blurBuffer2;
 #define NEAR_PLANE 0.01f
 #define ROTATION_SPEED 1.5f
 
+#define MESH_RANDOM_SEED 173
+
+#define MIN_FOGGED 40
+
+#define CAMERA_DISTANCE 1.1f
+
 #define PI 3.14159f
 
 /* 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 ;
@@ -43,12 +58,15 @@ MyVertex vertexBufferProjected[VERTEX_COUNT];
 void clearBlurBuffer();
 void applyBlur();
 void blitEffect();
-void thunder(int x0, int y0, int x1, int y1, int seed, int randomness, int depth);
+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 renderMesh(int seed);
+void renderMeshToPointSprites(int seed);
+void renderPointSprites();
+unsigned char fog(float z);
+void sortPointSprites();
 
 static int init(void);
 static void destroy(void);
@@ -122,7 +140,9 @@ static void draw(void)
        
        animateMesh();
        projectMesh();
-       renderMesh(thunderPattern);
+       renderMeshToPointSprites(thunderPattern);
+       sortPointSprites();
+       renderPointSprites();
        
        
        applyBlur();
@@ -202,27 +222,29 @@ void blitEffect() {
 
 }
 
-void thunder(int x0, int y0, int x1, int y1, int seed, int randomness, int depth) {
+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;
-       dst = blurBuffer + BLUR_BUFFER_WIDTH + 1 + mx + my * BLUR_BUFFER_WIDTH;
+       mc = (c0 + c1) >> 1;
 
        if (depth <= 0) return;
-       if (mx < THUNDER_RECT_SIZE || mx >= 160 - THUNDER_RECT_SIZE || my < THUNDER_RECT_SIZE || my >= 120 - THUNDER_RECT_SIZE) return;
 
-       srand(seed);
-
-       for (j = 0; j < THUNDER_RECT_SIZE; j++) {
-               memset(dst, 255, THUNDER_RECT_SIZE);
-               dst += BLUR_BUFFER_WIDTH;
+       /* 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, rand(), randomness >> 1, depth-1);
-       thunder(mx, my, x1, y1, rand(), randomness >> 1, depth - 1);
+       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() {
@@ -245,6 +267,8 @@ MyVertex randomVertex() {
 void initMesh() {
        int i;
 
+       srand(MESH_RANDOM_SEED);
+
        for (i = 0; i < VERTEX_COUNT; i++) {
                vertexBuffer[i] = randomVertex();
        }
@@ -275,12 +299,12 @@ void animateMesh() {
                v1 = vertexBuffer[i];
 
                /* 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 += 1.00f;
+               v2.z += CAMERA_DISTANCE;
 
                vertexBufferAnimated[i] = v2;
        }
@@ -302,19 +326,116 @@ void projectMesh() {
        }
 }
 
-void renderMesh(int seed) {
+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;
 
-               /*if (sx < THUNDER_RECT_SIZE || sx >= 160 - THUNDER_RECT_SIZE || sy < THUNDER_RECT_SIZE || sy >= 120 - THUNDER_RECT_SIZE) return;*/
+               thunder(80, 60, sx, sy, fogAtOrigin, fog(vertexBufferAnimated[vertex].z), rand(), THUNDER_RANDOMNESS, 5);
+       }
+}
 
-               thunder(80, 60, sx, sy, 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;
+               }
        }
-}
\ No newline at end of file
+}
+
+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);
+}
+