7cff960cfdd6718f9d4bac8cdb4c8f2d6e139b76
[csgray] / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include "csgray.h"
6
7 static int save_image(const char *fname, float *pix, int xsz, int ysz);
8 static int parse_opt(int argc, char **argv);
9
10 static int width = 800, height = 600;
11 static const char *out_fname = "output.ppm";
12
13 int main(int argc, char **argv)
14 {
15         csg_object *oa, *ob, *oc;
16         float *pixels;
17
18         if(parse_opt(argc, argv) == -1) {
19                 return 1;
20         }
21
22         if(csg_init() == -1) {
23                 return 1;
24         }
25
26         if(!(pixels = malloc(width * height * 3 * sizeof *pixels))) {
27                 perror("failed to allocate framebuffer");
28                 return 1;
29         }
30
31         oa = csg_sphere(0, 0, 0, 1);
32         ob = csg_sphere(0, 1, 0, 0.8);
33         oc = csg_union(oa, ob);
34
35         csg_add_object(oc);
36
37         csg_render_image(pixels, width, height);
38         save_image(out_fname, pixels, width, height);
39
40         csg_destroy();
41         return 0;
42 }
43
44 static int save_image(const char *fname, float *pix, int xsz, int ysz)
45 {
46         int i;
47         FILE *fp;
48
49         if(!(fp = fopen(fname, "wb"))) {
50                 fprintf(stderr, "failed to open %s for writing: %s\n", fname, strerror(errno));
51                 return -1;
52         }
53
54         fprintf(fp, "P6\n%d %d\n65535\n", xsz, ysz);
55
56         for(i=0; i<xsz * ysz; i++) {
57                 unsigned int r = *pix++ * 65535.0f;
58                 unsigned int g = *pix++ * 65535.0f;
59                 unsigned int b = *pix++ * 65535.0f;
60
61                 if(r > 0xffff) r = 0xffff;
62                 if(g > 0xffff) g = 0xffff;
63                 if(b > 0xffff) b = 0xffff;
64
65                 fputc(r >> 8, fp);
66                 fputc(r, fp);
67                 fputc(g >> 8, fp);
68                 fputc(g, fp);
69                 fputc(b >> 8, fp);
70                 fputc(b, fp);
71         }
72         fclose(fp);
73         return 0;
74 }
75
76 static void print_usage(const char *argv0)
77 {
78         printf("Usage: %s [options] <csg file>\n", argv0);
79         printf("Options:\n");
80         printf(" -s <WxH>  output image resolution\n");
81         printf(" -o <file> output image file\n");
82         printf(" -h        print usage information and exit\n");
83 }
84
85 static int parse_opt(int argc, char **argv)
86 {
87         int i;
88
89         for(i=1; i<argc; i++) {
90                 if(argv[i][0] == '-') {
91                         if(argv[i][2] == 0) {
92                                 switch(argv[i][1]) {
93                                 case 's':
94                                         if(sscanf(argv[++i], "%dx%d", &width, &height) != 2) {
95                                                 fprintf(stderr, "-s must be followed by WIDTHxHEIGHT\n");
96                                                 return -1;
97                                         }
98                                         break;
99
100                                 case 'o':
101                                         out_fname = argv[++i];
102                                         break;
103
104                                 case 'h':
105                                         print_usage(argv[0]);
106                                         exit(0);
107
108                                 default:
109                                         fprintf(stderr, "invalid option: %s\n", argv[i]);
110                                         return -1;
111                                 }
112                         } else {
113                                 fprintf(stderr, "invalid option: %s\n", argv[i]);
114                                 return -1;
115                         }
116                 } else {
117                         fprintf(stderr, "unexpected argument: %s\n", argv[i]);
118                         return -1;
119                 }
120         }
121         return 0;
122 }