]> Dogcows Code - chaz/rasterize/blob - scene.cc
finishing fifth project
[chaz/rasterize] / scene.cc
1
2 /*
3 * CS5600 University of Utah
4 * Charles McGarvey
5 * mcgarvey@eng.utah.edu
6 */
7
8 #include <cerrno>
9 #include <cmath>
10
11 #include "contact.hh"
12 #include "light.hh"
13 #include "plane.hh"
14 #include "sphere.hh"
15 #include "triangle.hh"
16 #include "vec.hh"
17
18 #include "scene.hh"
19
20
21 static int _scene_add_light(scene_t* s, FILE* file);
22 static int _scene_add_sphere(scene_t* s, FILE* file);
23 static int _scene_add_plane(scene_t* s, FILE* file);
24 static int _scene_add_triangle(scene_t* s, FILE* file);
25
26
27 struct scene
28 {
29 int w, h;
30 vec_t eye;
31 vec_t screenCenter;
32 vec_t screenU;
33 vec_t screenV;
34 list_t* lights;
35 list_t* objects;
36 color_t ambient;
37 };
38
39
40 scene_t* scene_alloc(FILE* file)
41 {
42 int w, h;
43 double eyeX, eyeY, eyeZ, spotX, spotY, spotZ, upX, upY, upZ;
44 double fovy, aspect;
45 double aR, aG, aB;
46 if (fscanf(file, "U5 %d %d %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
47 &w, &h,
48 &eyeX, &eyeY, &eyeZ, &spotX, &spotY, &spotZ, &upX, &upY, &upZ,
49 &fovy, &aspect,
50 &aR, &aG, &aB) != 16) {
51 fprintf(stderr, "Cannot read scene header.\n");
52 return NULL;
53 }
54
55 vec_t eye = vec_new(eyeX, eyeY, eyeZ);
56 vec_t spot = vec_new(spotX, spotY, spotZ);
57 vec_t up = vec_new(upX, upY, upZ);
58 scal_t d = S(1.0) / scal_tan((scal_t)fovy * S(0.5));
59
60 vec_t look = vec_normalize(vec_sub(spot, eye));
61 vec_t screenCenter = vec_scale(look, d);
62 vec_t screenU = vec_normalize(vec_cross(look, up));
63 vec_t screenV = vec_cross(screenU, look);
64 screenU = vec_scale(screenU, (scal_t)aspect);
65
66 scene_t* s = (scene_t*)mem_alloc(sizeof(scene_t));
67 s->w = w;
68 s->h = h;
69 s->eye = eye;
70 s->screenCenter = screenCenter;
71 s->screenU = screenU;
72 s->screenV = screenV;
73 s->lights = NULL;
74 s->objects = NULL;
75 s->ambient = color_new((scal_t)aR, (scal_t)aG, (scal_t)aB, S(1.0));
76
77 char type;
78 while (fscanf(file, " %c", &type) == 1) {
79 switch (type) {
80 case 'l':
81 if (_scene_add_light(s, file) != 0) {
82 goto fail;
83 }
84 break;
85
86 case 's':
87 if (_scene_add_sphere(s, file) != 0) {
88 goto fail;
89 }
90 break;
91
92 case 'p':
93 if (_scene_add_plane(s, file) != 0) {
94 goto fail;
95 }
96 break;
97
98 case 't':
99 if (_scene_add_triangle(s, file) != 0) {
100 goto fail;
101 }
102 break;
103
104 case 'X':
105 goto done;
106
107 default:
108 fprintf(stderr, "Unknown identifier: %c\n", type);
109 }
110 }
111
112 done:
113 if (s->objects) list_reverse(&s->objects);
114 return s;
115
116 fail:
117 scene_destroy(s);
118 return NULL;
119 }
120
121 void scene_destroy(scene_t* s)
122 {
123 if (s->lights) list_destroy(&s->lights);
124 if (s->objects) list_destroy(&s->objects);
125 mem_free(s);
126 }
127
128
129 /*
130 * Add a light to the scene.
131 */
132 static int _scene_add_light(scene_t* s, FILE* file)
133 {
134 double lx, ly, lz, r, g, b;
135 if (fscanf(file, " %lf %lf %lf %lf %lf %lf",
136 &lx, &ly, &lz, &r, &g, &b) != 6) {
137 fprintf(stderr, "Cannot read light values from scene.\n");
138 return -1;
139 }
140 light_t* l = light_alloc(
141 vec_new(lx, ly, lz),
142 color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0))
143 );
144 list_push2(&s->lights, l, mem_free);
145 return 0;
146 }
147
148 static int _scene_add_sphere(scene_t* s, FILE* file)
149 {
150 double x, y, z, radius, r, g, b;
151 if (fscanf(file, " %lf %lf %lf %lf %lf %lf %lf",
152 &x, &y, &z, &radius, &r, &g, &b) != 7) {
153 fprintf(stderr, "Cannot read sphere values from scene.\n");
154 return -1;
155 }
156 rt::element* sphere = new rt::sphere(
157 vec_new((scal_t)x, (scal_t)y, (scal_t)z),
158 (scal_t)radius
159 );
160 sphere->material(color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0)));
161 list_push2(&s->objects, sphere, DTOR(rt::sphere_destroy));
162 return 0;
163 }
164
165 static int _scene_add_plane(scene_t* s, FILE* file)
166 {
167 double x, y, z, nx, ny, nz, r, g, b;
168 if (fscanf(file, " %lf %lf %lf %lf %lf %lf %lf %lf %lf",
169 &x, &y, &z, &nx, &ny, &nz, &r, &g, &b) != 9) {
170 fprintf(stderr, "Cannot read plane values from scene.\n");
171 return -1;
172 }
173 rt::element* plane = new rt::plane(
174 vec_new((scal_t)x, (scal_t)y, (scal_t)z),
175 vec_new((scal_t)nx, (scal_t)ny, (scal_t)nz)
176 );
177 plane->material(color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0)));
178 list_push2(&s->objects, plane, DTOR(rt::plane_destroy));
179 return 0;
180 }
181
182 static int _scene_add_triangle(scene_t* s, FILE* file)
183 {
184 double x1, y1, z1, x2, y2, z2, x3, y3, z3, r, g, b;
185 if (fscanf(file, " %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
186 &x1, &y1, &z1, &x2, &y2, &z2, &x3, &y3, &z3, &r, &g, &b) != 12) {
187 fprintf(stderr, "Cannot read triangle values from scene.\n");
188 return -1;
189 }
190 rt::element* triangle = new rt::triangle(
191 vec_new((scal_t)x1, (scal_t)y1, (scal_t)z1),
192 vec_new((scal_t)x2, (scal_t)y2, (scal_t)z2),
193 vec_new((scal_t)x3, (scal_t)y3, (scal_t)z3)
194 );
195 triangle->material(color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0)));
196 list_push2(&s->objects, triangle, DTOR(rt::triangle_destroy));
197 return 0;
198 }
199
200
201 list_t* scene_elements(const scene_t* s)
202 {
203 return s->objects;
204 }
205
206 list_t* scene_lights(const scene_t* s)
207 {
208 return s->lights;
209 }
210
211 color_t scene_ambient(const scene_t* s)
212 {
213 return s->ambient;
214 }
215
216
217 raster_t* scene_render(const scene_t* s)
218 {
219 #if VERBOSITY >= 3
220 timer_start();
221 #endif
222
223 raster_t* p = raster_alloc(s->w, s->h, COLOR_BLACK);
224
225 /*for (list_t* i = s->lights; i; i = i->link) {*/
226 /*raster_light(p, *(light_t*)i->val);*/
227 /*}*/
228
229 raster_t* texture = raster_import("texture.bmp");
230 if (texture == NULL) {
231 texture = raster_import("texture.ppm");
232 }
233
234 if (s->objects && texture != NULL) {
235 rt::element* obj = (rt::element*)s->objects->val;
236 obj->texture(texture);
237 #if VERBOSITY >= 3
238 printf("Loaded texture file; will texture first scene object.\n");
239 #endif
240 }
241
242 #if VERBOSITY >= 3
243 printf("rendering scene...\n");
244 #endif
245
246 scal_t wh = S(2.0) / (scal_t)s->w;
247 scal_t hh = S(2.0) / (scal_t)s->h;
248
249 for (int y = 0; y < s->h; ++y) {
250 for (int x = 0; x < s->w; ++x) {
251 color_t* pixel = raster_color(p, x, y);
252 scal_t u = (scal_t)x * wh - S(1.0);
253 scal_t v = (scal_t)y * hh - S(1.0);
254 vec_t rayDirection = vec_add2(s->screenCenter,
255 vec_scale(s->screenU, u), vec_scale(s->screenV, v));
256
257 ray_t ray = ray_normalize(ray_new(s->eye, rayDirection));
258
259 rt::element* nearestObj = 0;
260 contact_t nearestHit;
261
262 // find the nearest object along the ray
263 for (list_t* i = s->objects; i; i = i->link) {
264 rt::element* obj = (rt::element*)i->val;
265 contact_t hit;
266 if (obj->intersect(ray, hit) && (!nearestObj || hit.d < nearestHit.d)) {
267 nearestObj = obj;
268 nearestHit = hit;
269 }
270 }
271
272 if (nearestObj) {
273 *pixel = nearestObj->cast(nearestHit, s);
274 }
275 }
276 }
277
278 #if VERBOSITY >= 3
279 long dt = timer_stop();
280 printf("render complete!\ntime\t%.3fms\n", (float)dt / 1000.0f);
281 #endif
282
283 if (texture) {
284 raster_destroy(texture);
285 }
286
287 return p;
288 }
289
This page took 0.044207 seconds and 4 git commands to generate.