11 /* Render blur in half x half dimenstions. Add one pixel padding in all
12 * directions (2 pixels horizontally, 2 pixels vertically).
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;
21 #define THUNDER_RECT_SIZE 2
22 #define THUNDER_RANDOMNESS 16
23 #define THUNDER_SECONDS 0.075f
25 #define VERTEX_COUNT 12
26 #define PERSPECTIVE_NEUTRAL_DEPTH 0.5f
27 #define NEAR_PLANE 0.01f
28 #define ROTATION_SPEED 1.5f
30 #define MESH_RANDOM_SEED 173
34 #define CAMERA_DISTANCE 1.1f
36 /* TODO: Load palette from file */
37 static unsigned short palette[256];
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)
52 MyVertex vertexBuffer[VERTEX_COUNT];
53 MyVertex vertexBufferAnimated[VERTEX_COUNT];
54 MyVertex vertexBufferProjected[VERTEX_COUNT];
56 void clearBlurBuffer();
59 void thunder(int x0, int y0, int x1, int y1, unsigned char c0, unsigned char c1, int seed, int randomness, int depth);
64 void renderMeshToPointSprites(int seed);
65 void renderPointSprites();
66 unsigned char fog(float z);
67 void sortPointSprites();
69 static int init(void);
70 static void destroy(void);
71 static void start(long trans_time);
72 static void stop(long trans_time);
73 static void draw(void);
75 static unsigned int lastFrameTime = 0;
76 static float lastFrameDuration = 0.0f;
77 static struct screen scr = {
86 struct screen *thunder_screen(void)
95 blurBuffer = malloc(BLUR_BUFFER_SIZE);
96 blurBuffer2 = malloc(BLUR_BUFFER_SIZE);
100 /* For now, map to blue */
101 for (i = 0; i < 256; i++) {
102 palette[i] = (i * i) >> 11;
110 static void destroy(void)
119 static void start(long trans_time)
121 lastFrameTime = time_msec;
125 static float remainingThunderDuration = THUNDER_SECONDS;
126 static int thunderPattern = 0;
128 static void draw(void)
130 lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f;
131 lastFrameTime = time_msec;
133 remainingThunderDuration -= lastFrameDuration;
134 if (remainingThunderDuration <= 0) {
136 remainingThunderDuration = THUNDER_SECONDS;
141 renderMeshToPointSprites(thunderPattern);
143 renderPointSprites();
154 void clearBlurBuffer() {
155 /* Clear the whole buffer (including its padding ) */
156 memset(blurBuffer, 0, BLUR_BUFFER_SIZE);
157 memset(blurBuffer2, 0, BLUR_BUFFER_SIZE);
164 unsigned char *src = blurBuffer + BLUR_BUFFER_WIDTH + 1;
165 unsigned char *dst = blurBuffer2 + BLUR_BUFFER_WIDTH + 1;
167 for (j = 0; j < 120; j++) {
168 for (i = 0; i < 160; i++) {
169 *dst = (*(src - 1) + *(src + 1) + *(src - BLUR_BUFFER_WIDTH) + *(src + BLUR_BUFFER_WIDTH)) >> 2;
171 if (*dst > BLUR_DARKEN) *dst -= BLUR_DARKEN;
177 /* Just skip the padding since we went through the scanline in the inner loop (except from the padding) */
182 /* Swap blur buffers */
184 blurBuffer = blurBuffer2;
189 unsigned int *dst1 = (unsigned int*) fb_pixels;
190 unsigned int *dst2 = dst1 + 160; /* We're writing two pixels at once */
191 unsigned char *src1 = blurBuffer + BLUR_BUFFER_WIDTH + 1;
192 unsigned char *src2 = src1 + BLUR_BUFFER_WIDTH;
193 unsigned char tl, tr, bl, br;
196 for (j = 0; j < 120; j++) {
197 for (i = 0; i < 160; i++) {
199 tr = (*src1 + *(src1 + 1)) >> 1;
200 bl = (*src1 + *src2) >> 1;
201 br = (tr + ((*src2 + *(src2 + 1)) >> 1)) >> 1;
203 /* Pack 2 pixels in each 32 bit word */
204 *dst1 = (palette[tr] << 16) | palette[tl];
205 *dst2 = (palette[br] << 16) | palette[bl];
212 /* Again, skip padding */
216 /* For now, skip a scanline */
223 void thunder(int x0, int y0, int x1, int y1, unsigned char c0, unsigned char c1, int seed, int randomness, int depth) {
228 if (randomness <= 0) randomness = 1;
229 mx = ((x0 + x1) >> 1) + rand() % randomness - randomness / 2;
230 my = ((y0 + y1) >> 1) + rand() % randomness - randomness / 2;
233 if (depth <= 0) return;
235 /* Insert a new sprite */
236 if (pointSpriteCount >= MAX_POINT_SPRITES) {
240 pointSprites[pointSpriteCount++] = PACK_POINT_SPRITE(mx, my, mc);
244 thunder(x0, y0, mx, my, c0, mc, rand(), randomness >> 1, depth-1);
245 thunder(mx, my, x1, y1, mc, c1, rand(), randomness >> 1, depth - 1);
248 MyVertex randomVertex() {
252 ret.x = rand() % 200 - 100; if (ret.x == 0) ret.x = 1;
253 ret.y = rand() % 200 - 100; if (ret.y == 0) ret.y = 1;
254 ret.z = rand() % 200 - 100; if (ret.z == 0) ret.z = 1;
257 l = sqrt(ret.x * ret.x + ret.y * ret.y + ret.z * ret.z);
268 srand(MESH_RANDOM_SEED);
270 for (i = 0; i < VERTEX_COUNT; i++) {
271 vertexBuffer[i] = randomVertex();
280 yRot = ROTATION_SPEED * time_msec / 1000.0f;
282 /* Create rotated basis */
291 bz.x = cos(yRot + M_PI/2.0f);
293 bz.z = sin(yRot + M_PI/2.0f);
295 for (i = 0; i < VERTEX_COUNT; i++) {
297 v1 = vertexBuffer[i];
300 v1.y *= sin(time_msec / 1000.0f + v1.x + v1.z);
302 /* O re panaia mou */
303 v2.x = v1.x * bx.x + v1.y * by.x + v1.z * bz.x;
304 v2.y = v1.x * bx.y + v1.y * by.y + v1.z * bz.y;
305 v2.z = v1.x * bx.z + v1.y * by.z + v1.z * bz.z;
307 v2.z += CAMERA_DISTANCE;
309 vertexBufferAnimated[i] = v2;
316 for (i = 0; i < VERTEX_COUNT; i++) {
318 if (vertexBufferAnimated[i].z <= NEAR_PLANE) {
319 vertexBufferProjected[i].x = vertexBufferProjected[i].y = 1000.0f;
320 vertexBufferProjected[i].z = -1.0f;
324 vertexBufferProjected[i].x = vertexBufferAnimated[i].x * PERSPECTIVE_NEUTRAL_DEPTH / vertexBufferAnimated[i].z;
325 vertexBufferProjected[i].y = vertexBufferAnimated[i].y * PERSPECTIVE_NEUTRAL_DEPTH / vertexBufferAnimated[i].z;
329 void renderMeshToPointSprites(int seed) {
334 unsigned char fogAtOrigin;
336 fogAtOrigin = fog(CAMERA_DISTANCE);
338 pointSpriteCount = 0;
341 for (vertex = 0; vertex < VERTEX_COUNT; vertex++) {
342 sx = (int)(vertexBufferProjected[vertex].x * 80) + 80;
343 sy = (int)(vertexBufferProjected[vertex].y * 60) + 60;
345 thunder(80, 60, sx, sy, fogAtOrigin, fog(vertexBufferAnimated[vertex].z), rand(), THUNDER_RANDOMNESS, 5);
349 void renderPointSprites() {
356 for (i = 0; i < pointSpriteCount; i++) {
357 sprite = pointSprites[i];
359 sx = UNPACK_X(sprite);
360 sy = UNPACK_Y(sprite);
362 if (sx < THUNDER_RECT_SIZE || sx >= 160 - THUNDER_RECT_SIZE || sy < THUNDER_RECT_SIZE || sy >= 120 - THUNDER_RECT_SIZE) continue;
364 dst = blurBuffer + BLUR_BUFFER_WIDTH + 1 + sx + sy * BLUR_BUFFER_WIDTH;
366 color = UNPACK_COLOR(sprite);
368 for (j = 0; j < THUNDER_RECT_SIZE; j++) {
369 memset(dst, color, THUNDER_RECT_SIZE);
370 dst += BLUR_BUFFER_WIDTH;
375 unsigned char fog(float z) {
376 unsigned int ret = (unsigned int) (((-(z - CAMERA_DISTANCE)) * 0.5f + 0.5f) * (255.0f - MIN_FOGGED)) + MIN_FOGGED;
377 if (ret > 255) ret = 255;
378 return (unsigned char)ret;
381 void sort(PointSprite *begin, PointSprite *end) {
\r
382 PointSprite pivotValue;
\r
384 PointSprite *left, *right;
\r
385 int leftCond, rightCond;
\r
390 if (sz < 2) return; /* already sorted */
\r
393 if (begin[1] < begin[0]) {
\r
395 begin[0] = begin[1];
\r
401 /* minimum 3 elements from now on */
\r
403 /* choose a pivot near the middle, since we frequently sort already sorted arrays */
\r
404 pivotValue = begin[sz / 2];
\r
409 while (right > left) {
\r
410 /* check if left and right elements meet the conditions */
\r
411 leftCond = pivotValue >= *left;
\r
412 rightCond = pivotValue < *right;
\r
414 if (!leftCond && !rightCond) {
\r
421 else if (leftCond && rightCond) {
\r
425 else if (leftCond) {
\r
438 void sortPointSprites() {
439 sort(pointSprites, pointSprites + pointSpriteCount);