Moved RleBitmap to its own module and created minifx screen to experiment
[dosdemo] / src / minifx.c
1 #include "demo.h"
2 #include "imago2.h"
3 #include "screen.h"
4 #include <assert.h>
5 #include <math.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include <RleBitmap.h>
11
12 /* APPROX. 170 FPS Minimum */
13
14 static int init(void);
15 static void destroy(void);
16 static void start(long trans_time);
17 static void stop(long trans_time);
18 static void draw(void);
19
20 static void updatePropeller(float t, RleBitmap *rle);
21
22 static unsigned short *backBuffer;
23
24 static unsigned char miniFXBuffer[1024];
25
26 static long lastFrameTime = 0;
27
28 static struct screen scr = {"minifx", init, destroy, start, 0, draw};
29
30 struct screen *minifx_screen(void) {
31         return &scr;
32 }
33
34 static int init(void) {
35         /* Allocate back buffer */
36         backBuffer = (unsigned short *)calloc(FB_WIDTH * FB_HEIGHT, sizeof(unsigned short));
37
38         return 0;
39 }
40
41 static void destroy(void) {
42         free(backBuffer);
43         backBuffer = 0;
44 }
45
46 static void start(long trans_time) { lastFrameTime = time_msec; }
47
48 static void draw(void) {
49         long lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f;
50         lastFrameTime = time_msec;
51     
52     int clearColor = 0x888888;
53     unsigned short clearColor16 = ((clearColor << 8) & 0xF800)     /* R */
54                            | ((clearColor >> 5) & 0x07E0)   /* G */
55                            | ((clearColor >> 19) & 0x001F); /* B */
56     for (int i=0; i<FB_WIDTH * FB_HEIGHT; i++) {
57         backBuffer[i] = clearColor16;
58     }
59
60     /* For now create / destroy in each frame. We will manage these later */
61     RleBitmap *rle = rleCreate(32, 32);
62     
63     updatePropeller(time_msec / 1000.0f, rle);
64     int stride = FB_WIDTH;
65     /*
66     rleBlit(rle, backBuffer, FB_WIDTH, FB_HEIGHT, stride,
67                         100, 100);
68     */
69     
70     rleBlitScale(rle, backBuffer, FB_WIDTH, FB_HEIGHT, stride, 50,
71                   50, 3.0, 3.0);
72     
73     rleDestroy(rle);
74
75         /* Blit effect to framebuffer */
76     memcpy(fb_pixels, backBuffer, FB_WIDTH * FB_HEIGHT * sizeof(unsigned short));
77         swap_buffers(0);
78 }
79
80
81 #define PROPELLER_CIRCLE_RADIUS 18
82 #define PROPELLER_CIRCLE_RADIUS_SQ (PROPELLER_CIRCLE_RADIUS * PROPELLER_CIRCLE_RADIUS)
83
84 static struct {
85         int circleX[3];
86         int circleY[3];
87 } propellerState;
88
89 static void updatePropeller(float t, RleBitmap *rle) {
90     
91     t *= 0.1; /* Slow-mo to see what happens */
92         int i, j;
93         int cx, cy, count = 0;
94         unsigned char *dst;
95         float x = 0.0f;
96         float y = 18.0f;
97         float nx, ny;
98         float cost, sint;
99         static float sin120 = 0.86602540378f;
100         static float cos120 = -0.5f;
101
102         /* Rotate */
103         sint = sin(t);
104         cost = cos(t);
105         nx = x * cost - y * sint;
106         ny = y * cost + x * sint;
107         x = nx;
108         y = ny;
109         propellerState.circleX[0] = (int)(x + 0.5f) + 16;
110         propellerState.circleY[0] = (int)(y + 0.5f) + 16;
111
112         /* Rotate by 120 degrees, for the second circle */
113         nx = x * cos120 - y * sin120;
114         ny = y * cos120 + x * sin120;
115         x = nx;
116         y = ny;
117         propellerState.circleX[1] = (int)(x + 0.5f) + 16;
118         propellerState.circleY[1] = (int)(y + 0.5f) + 16;
119
120         /* 3rd circle */
121         nx = x * cos120 - y * sin120;
122         ny = y * cos120 + x * sin120;
123         x = nx;
124         y = ny;
125         propellerState.circleX[2] = (int)(x + 0.5f) + 16;
126         propellerState.circleY[2] = (int)(y + 0.5f) + 16;
127
128         /* Write effect to the mini fx buffer*/
129         dst = miniFXBuffer;
130         for (j = 0; j < 32; j++) {
131                 for (i = 0; i < 32; i++) {
132                         count = 0;
133
134                         /* First circle */
135                         cx = propellerState.circleX[0] - i;
136                         cy = propellerState.circleY[0] - j;
137                         if (cx * cx + cy * cy < PROPELLER_CIRCLE_RADIUS_SQ)
138                                 count++;
139
140                         /* 2nd circle */
141                         cx = propellerState.circleX[1] - i;
142                         cy = propellerState.circleY[1] - j;
143                         if (cx * cx + cy * cy < PROPELLER_CIRCLE_RADIUS_SQ)
144                                 count++;
145
146                         /* 3rd circle */
147                         cx = propellerState.circleX[2] - i;
148                         cy = propellerState.circleY[2] - j;
149                         if (cx * cx + cy * cy < PROPELLER_CIRCLE_RADIUS_SQ)
150                                 count++;
151
152                         *dst++ = count >= 2;
153                 }
154         }
155
156         /* Then, encode to rle */
157         rleEncode(rle, miniFXBuffer, 32, 32);
158
159         /* Distribute the produced streaks so that they don't produce garbage when interpolated */
160         rleDistributeStreaks(rle);
161 }