added specular
[csgray] / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <errno.h>
6 #include "csgray.h"
7
8 #define DFL_WIDTH       800
9 #define DFL_HEIGHT      600
10 #define DFL_GAMMA       2.2f
11 #define DFL_OUTFILE     "output.ppm"
12
13 static int save_image(const char *fname, float *pix, int xsz, int ysz);
14 static int parse_opt(int argc, char **argv);
15
16 static int width = DFL_WIDTH, height = DFL_HEIGHT;
17 static float inv_gamma = 1.0f / DFL_GAMMA;
18 static const char *out_fname = DFL_OUTFILE;
19
20 int main(int argc, char **argv)
21 {
22         csg_object *oa, *ob, *oc, *obj;
23         float *pixels;
24
25         if(parse_opt(argc, argv) == -1) {
26                 return 1;
27         }
28
29         if(csg_init() == -1) {
30                 return 1;
31         }
32
33         if(!(pixels = malloc(width * height * 3 * sizeof *pixels))) {
34                 perror("failed to allocate framebuffer");
35                 return 1;
36         }
37
38         csg_view(0, 0, 5, 0, 0, 0);
39
40         oa = csg_sphere(0, 0, 0, 1);
41         csg_color(oa, 1, 0.1, 0.05);
42         csg_roughness(oa, 0.3);
43         ob = csg_sphere(0.3, 0.7, 0.7, 0.7);
44         csg_color(ob, 0.2, 0.3, 1);
45         csg_roughness(ob, 0.3);
46         oc = csg_subtraction(oa, ob);
47
48         oa = oc;
49
50         ob = csg_sphere(-0.9, -0.1, 0.7, 0.5);
51         csg_color(ob, 1, 0.9, 0.2);
52         csg_roughness(ob, 0.3);
53
54         oc = csg_subtraction(oa, ob);
55
56         csg_add_object(oc);
57
58         obj = csg_plane(0, -1, 0, 0, 1, 0);
59         csg_color(obj, 0.4, 0.7, 0.4);
60         csg_add_object(obj);
61
62         obj = csg_null(-4, 10, 10);
63         csg_emission(obj, 80, 80, 80);
64         csg_add_object(obj);
65
66         csg_render_image(pixels, width, height);
67         save_image(out_fname, pixels, width, height);
68
69         csg_destroy();
70         return 0;
71 }
72
73 static int save_image(const char *fname, float *pix, int xsz, int ysz)
74 {
75         int i;
76         FILE *fp;
77
78         if(!(fp = fopen(fname, "wb"))) {
79                 fprintf(stderr, "failed to open %s for writing: %s\n", fname, strerror(errno));
80                 return -1;
81         }
82
83         fprintf(fp, "P6\n%d %d\n255\n", xsz, ysz);
84
85         for(i=0; i<xsz * ysz; i++) {
86                 unsigned int r = pow(*pix++, inv_gamma) * 255.0f;
87                 unsigned int g = pow(*pix++, inv_gamma) * 255.0f;
88                 unsigned int b = pow(*pix++, inv_gamma) * 255.0f;
89
90                 if(r > 255) r = 255;
91                 if(g > 255) g = 255;
92                 if(b > 255) b = 255;
93
94                 fputc(r, fp);
95                 fputc(g, fp);
96                 fputc(b, fp);
97         }
98         fclose(fp);
99         return 0;
100 }
101
102 static void print_usage(const char *argv0)
103 {
104         printf("Usage: %s [options] <csg file>\n", argv0);
105         printf("Options:\n");
106         printf(" -s <WxH>   output image resolution (default: %dx%d)\n", DFL_WIDTH, DFL_HEIGHT);
107         printf(" -g <gamma> set output gamma (default: %g)\n", DFL_GAMMA);
108         printf(" -o <file>  output image file (default: %s)\n", DFL_OUTFILE);
109         printf(" -h         print usage information and exit\n");
110 }
111
112 static int parse_opt(int argc, char **argv)
113 {
114         int i;
115
116         for(i=1; i<argc; i++) {
117                 if(argv[i][0] == '-') {
118                         if(argv[i][2] == 0) {
119                                 switch(argv[i][1]) {
120                                 case 's':
121                                         if(sscanf(argv[++i], "%dx%d", &width, &height) != 2) {
122                                                 fprintf(stderr, "-s must be followed by WIDTHxHEIGHT\n");
123                                                 return -1;
124                                         }
125                                         break;
126
127                                 case 'g':
128                                         if((inv_gamma = atof(argv[++i])) == 0.0f) {
129                                                 fprintf(stderr, "-g must be followed by a non-zero gamma value\n");
130                                                 return -1;
131                                         }
132                                         inv_gamma = 1.0f / inv_gamma;
133                                         break;
134
135                                 case 'o':
136                                         out_fname = argv[++i];
137                                         break;
138
139                                 case 'h':
140                                         print_usage(argv[0]);
141                                         exit(0);
142
143                                 default:
144                                         fprintf(stderr, "invalid option: %s\n", argv[i]);
145                                         return -1;
146                                 }
147                         } else {
148                                 fprintf(stderr, "invalid option: %s\n", argv[i]);
149                                 return -1;
150                         }
151                 } else {
152                         fprintf(stderr, "unexpected argument: %s\n", argv[i]);
153                         return -1;
154                 }
155         }
156         return 0;
157 }