hacked support for both 16 and 32 bpp framebuffers
[fbgfx] / src / tunnel.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include <imago2.h>
5 #include "tpool.h"
6 #include "tunnel.h"
7
8 #define TEX_FNAME       "data/grid.png"
9 #define TEX_USCALE      4
10 #define TEX_VSCALE      2
11
12 #define USCALE  2
13 #define VSCALE  1
14
15 extern unsigned long time_msec;
16
17 static void (*draw_tunnel_range)(void*, int, int);
18
19 static void draw_tunnel_range16(void *pixels, int starty, int num_lines);
20 static void draw_tunnel_range32(void *pixels, int starty, int num_lines);
21 static int count_bits(unsigned int x);
22 static int count_zeros(unsigned int x);
23
24 static int xsz, ysz, vxsz, vysz;
25 static unsigned int *tunnel_map;
26 static unsigned char *tunnel_fog;
27
28 static int tex_xsz, tex_ysz;
29 static unsigned int *tex_pixels;
30 static int tex_xshift, tex_yshift;
31 static unsigned int tex_xmask, tex_ymask;
32
33 static struct thread_pool *tpool;
34
35
36 int init_tunnel(int x, int y, int bpp)
37 {
38         int i, j, n;
39         unsigned int *tmap;
40         unsigned char *fog;
41         float aspect = (float)x / (float)y;
42
43         switch(bpp) {
44         case 16:
45                 draw_tunnel_range = draw_tunnel_range16;
46                 break;
47         case 32:
48                 draw_tunnel_range = draw_tunnel_range32;
49                 break;
50         default:
51                 fprintf(stderr, "unsupported color depth: %d\n", bpp);
52                 return -1;
53         }
54
55         xsz = x;
56         ysz = y;
57         vxsz = xsz / USCALE;
58         vysz = ysz / VSCALE;
59
60         if(!(tunnel_map = malloc(vxsz * vysz * sizeof *tunnel_map))) {
61                 fprintf(stderr, "failed to allocate tunnel map\n");
62                 return -1;
63         }
64         if(!(tunnel_fog = malloc(vxsz * vysz))) {
65                 fprintf(stderr, "failed to allocate tunnel fog map\n");
66                 return -1;
67         }
68
69         tmap = tunnel_map;
70         fog = tunnel_fog;
71
72         for(i=0; i<vysz; i++) {
73                 float y = 2.0 * (float)i / (float)vysz - 1.0;
74                 for(j=0; j<vxsz; j++) {
75                         float x = aspect * (2.0 * (float)j / (float)vxsz - 1.0);
76                         float tu = atan2(y, x) / M_PI * 0.5 + 0.5;
77                         float d = sqrt(x * x + y * y);
78                         float tv = d == 0.0 ? 0.0 : 1.0 / d;
79
80                         int tx = (int)(tu * 65535.0 * TEX_USCALE) & 0xffff;
81                         int ty = (int)(tv * 65535.0 * TEX_VSCALE) & 0xffff;
82
83                         int f = (int)(d * 95.0);
84
85                         *tmap++ = (tx << 16) | ty;
86                         *fog++ = f > 255 ? 255 : f;
87                 }
88         }
89
90         if(!(tex_pixels = img_load_pixels(TEX_FNAME, &tex_xsz, &tex_ysz, IMG_FMT_RGBA32))) {
91                 fprintf(stderr, "failed to load image " TEX_FNAME "\n");
92                 return -1;
93         }
94         if((count_bits(tex_xsz) | count_bits(tex_ysz)) != 1) {
95                 fprintf(stderr, "non-pow2 image (%dx%d)\n", tex_xsz, tex_ysz);
96                 return -1;
97         }
98
99         n = count_zeros(tex_xsz);
100         for(i=0; i<n; i++) {
101                 tex_xmask |= 1 << i;
102         }
103         tex_xshift = n;
104
105         n = count_zeros(tex_ysz);
106         for(i=0; i<n; i++) {
107                 tex_ymask |= 1 << i;
108         }
109         tex_yshift = n;
110
111         if(!(tpool = tpool_create(0))) {
112                 fprintf(stderr, "failed to create thread pool\n");
113                 return -1;
114         }
115
116         return 0;
117 }
118
119 void destroy_tunnel(void)
120 {
121         tpool_destroy(tpool);
122         free(tunnel_map);
123         free(tunnel_fog);
124 }
125
126 #define NUM_WORK_ITEMS  32
127
128 static struct work {
129         void *pixels;
130         int starty, num_lines;
131 } work[NUM_WORK_ITEMS];
132
133 static void work_func(void *cls)
134 {
135         struct work *w = (struct work*)cls;
136         draw_tunnel_range(w->pixels, w->starty, w->num_lines);
137 }
138
139 void draw_tunnel(void *pixels)
140 {
141         int i, num_lines = vysz / NUM_WORK_ITEMS;
142         for(i=0; i<NUM_WORK_ITEMS; i++) {
143                 work[i].pixels = pixels;
144                 work[i].starty = i * num_lines;
145                 work[i].num_lines = num_lines;
146
147                 tpool_enqueue(tpool, work + i, work_func, 0);
148         }
149         tpool_wait(tpool);
150 }
151
152 static void tunnel_color(int *rp, int *gp, int *bp, long toffs, unsigned int tpacked, int fog)
153 {
154         int r, g, b;
155         unsigned int col;
156         unsigned int tx = (((tpacked >> 16) & 0xffff) << tex_xshift) >> 16;
157         unsigned int ty = ((tpacked & 0xffff) << tex_yshift) >> 16;
158         tx += toffs;
159         ty += toffs << 1;
160
161         tx &= tex_xmask;
162         ty &= tex_ymask;
163
164         col = tex_pixels[(ty << tex_xshift) + tx];
165         r = col & 0xff;
166         g = (col >> 8) & 0xff;
167         b = (col >> 16) & 0xff;
168
169         *rp = (r * fog) >> 8;
170         *gp = (g * fog) >> 8;
171         *bp = (b * fog) >> 8;
172 }
173
174 #define PACK_RGB16(r, g, b) \
175         (((((r) >> 3) & 0x1f) << 11) | ((((g) >> 2) & 0x3f) << 5) | ((b) & 0x1f))
176 #define PACK_RGB32(r, g, b) \
177         ((((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff))
178
179 #define PUTPIXEL(pixtype, col) \
180         do { \
181                 int k; \
182                 pixtype *ptr = pixels; \
183                 for(k=0; k<VSCALE; k++) { \
184                         switch(USCALE) { \
185                         case 4: \
186                                 ptr[3] = col; \
187                         case 3: \
188                                 ptr[2] = col; \
189                         case 2: \
190                                 ptr[1] = col; \
191                         case 1: \
192                                 *ptr = col; \
193                         } \
194                         ptr += xsz; \
195                 } \
196         } while(0)
197
198 static void draw_tunnel_range16(void *pix, int starty, int num_lines)
199 {
200         int i, j;
201         unsigned int *tmap = tunnel_map + starty * vxsz;
202         unsigned char *fog = tunnel_fog + starty * vxsz;
203
204         long toffs = time_msec / 4;
205         unsigned short *pixels = (unsigned short*)pix + starty * xsz * VSCALE;
206
207         for(i=0; i<num_lines; i++) {
208                 for(j=0; j<vxsz; j++) {
209                         unsigned int col;
210                         int r, g, b;
211
212                         tunnel_color(&r, &g, &b, toffs, *tmap++, *fog++);
213                         col = PACK_RGB16(r, g, b);
214
215                         PUTPIXEL(unsigned short, col);
216                         pixels += USCALE;
217                 }
218                 pixels += xsz * (VSCALE - 1);
219         }
220 }
221
222 static void draw_tunnel_range32(void *pix, int starty, int num_lines)
223 {
224         int i, j;
225         unsigned int *tmap = tunnel_map + starty * vxsz;
226         unsigned char *fog = tunnel_fog + starty * vxsz;
227
228         long toffs = time_msec / 4;
229         unsigned int *pixels = (unsigned int*)pix + starty * xsz * VSCALE;
230
231         for(i=0; i<num_lines; i++) {
232                 for(j=0; j<vxsz; j++) {
233                         unsigned int col;
234                         int r, g, b;
235
236                         tunnel_color(&r, &g, &b, toffs, *tmap++, *fog++);
237                         col = PACK_RGB32(r, g, b);
238
239                         PUTPIXEL(unsigned int, col);
240                         pixels += USCALE;
241                 }
242                 pixels += xsz * (VSCALE - 1);
243         }
244 }
245
246 static int count_bits(unsigned int x)
247 {
248         int i, nbits = 0;
249         for(i=0; i<32; i++) {
250                 if(x & 1) ++nbits;
251                 x >>= 1;
252         }
253         return nbits;
254 }
255
256 static int count_zeros(unsigned int x)
257 {
258         int i, num = 0;
259         for(i=0; i<32; i++) {
260                 if(x & 1) break;
261                 ++num;
262                 x >>= 1;
263         }
264         return num;
265 }