fixed the tunnel precalc to produce a continuous 10 bit depth value
[gbajam21] / tools / tungen.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdint.h>
5 #include <math.h>
6
7 struct vec2 {
8         int x, y;
9 };
10
11 int main(int argc, char **argv)
12 {
13         int i, j, frm, imgrad, out_nlines, xsz = 240, ysz = 160, texsz = 128;
14         int half_y = 0;
15         int center = 0;
16         struct vec2 *tunbuf, *tun;
17         float prev_r;
18         struct vec2 *buf, *ptr;
19         char *endp;
20         int num_frames = 1;
21
22         for(i=1; i<argc; i++) {
23                 if(argv[i][0] == '-') {
24                         if(argv[i][2] != 0) goto invalopt;
25                         switch(argv[i][1]) {
26                         case 's':
27                                 if(sscanf(argv[++i], "%dx%d", &xsz, &ysz) != 2 || xsz <= 1 || ysz <= 1) {
28                                         fprintf(stderr, "-s must be followed by WxH\n");
29                                         return 1;
30                                 }
31                                 break;
32
33                         case 't':
34                                 if(!(texsz = atoi(argv[++i])) || texsz > 256) {
35                                         fprintf(stderr, "-t must be followed by the texture size (1-256)\n");
36                                         return 1;
37                                 }
38                                 break;
39
40                         case 'y':
41                                 half_y = 1;
42                                 break;
43
44                         case 'c':
45                                 if(!argv[++i]) {
46                                         fprintf(stderr, "-c must be followed by a center pixel\n");
47                                         return 1;
48                                 }
49                                 center = strtol(argv[i], &endp, 10);
50                                 if(endp == argv[i]) {
51                                         fprintf(stderr, "-c invalid center position: %s\n", argv[i]);
52                                         return 1;
53                                 }
54                                 break;
55
56                         case 'n':
57                                 if(!argv[++i]) {
58                                         fprintf(stderr, "-n must be followed by the number of frames\n");
59                                         return 1;
60                                 }
61                                 if(!(num_frames = atoi(argv[i]))) {
62                                         fprintf(stderr, "-n invalid number of frames: %s\n", argv[i]);
63                                         return 1;
64                                 }
65                                 break;
66
67                         default:
68                                 goto invalopt;
69                         }
70                 } else {
71 invalopt:       fprintf(stderr, "invalid argument: %s\n", argv[i]);
72                         return 1;
73                 }
74         }
75
76         out_nlines = half_y ? ysz / 2 : ysz;
77
78         if(!(buf = malloc(xsz * ysz * sizeof *buf))) {
79                 perror("failed to allocate buffer");
80                 return 1;
81         }
82         imgrad = sqrt(xsz * xsz + ysz * ysz);
83
84         FILE *fp = fopen("tun_preview.ppm", "wb");
85         if(fp) {
86                 fprintf(fp, "P6\n%d %d\n255\n", xsz, out_nlines * num_frames);
87         }
88
89
90         for(frm=0; frm<num_frames; frm++) {
91                 int coffs = num_frames > 1 ? frm * center / (num_frames - 1) : center;
92
93                 memset(buf, 0xff, xsz * ysz * sizeof *buf);
94
95 #define UDIV    2048
96 #define VDIV    32768
97                 prev_r = 0.0f;
98 #pragma omp parallel for private(i, j, prev_r, ptr) schedule(dynamic)
99                 for(i=0; i<VDIV; i++) {
100                         float v = (float)(VDIV - i) / (float)VDIV;
101                         float r = 4.0 / v + 16;
102                         float z = v * coffs;
103
104                         /* don't bother drawing rings < 1 pixel apart */
105                         if(r < 0 || fabs(r - prev_r) < 0.05) continue;
106
107                         for(j=0; j<UDIV; j++) {
108                                 float u = (float)j / (float)(UDIV - 1);
109                                 float theta = 2.0f * u * M_PI;
110
111                                 int x = (int)(cos(theta) * r - z) + xsz / 2;
112                                 int y = (int)(sin(theta) * r) + ysz / 2;
113
114                                 if(x >= 0 && x < xsz && y >= 0 && y < ysz) {
115                                         ptr = buf + y * xsz + x;
116                                         ptr->x = (j << 8) / UDIV;
117                                         ptr->y = ((VDIV - i) << 11) / VDIV;
118                                 }
119                         }
120                         prev_r = r;
121                 }
122
123                 ptr = buf;
124                 for(i=0; i<out_nlines; i++) {
125                         for(j=0; j<xsz; j++) {
126                                 int u = ptr->x;
127                                 int v = ptr->y;
128                                 int r = (u << 3) & 0xff;
129                                 int g = (v >> 3) & 0xff;
130
131                                 /*if(v > 2.0) r = g = b = 0;*/
132
133                                 ptr++;
134
135                                 uint16_t out = ((uint16_t)u & 0x3f) | (((uint16_t)v & 0x3ff) << 6);
136                                 fwrite(&out, sizeof out, 1, stdout);
137
138                                 if(fp) {
139                                         fputc(r, fp);
140                                         fputc(g, fp);
141                                         fputc(0, fp);
142                                 }
143                         }
144                 }
145
146         }
147         fflush(stdout);
148
149         if(fp) fclose(fp);
150         return 0;
151 }