3 * CS5600 University of Utah
5 * mcgarvey@eng.utah.edu
22 int left
, right
, bottom
, top
;
26 mat_t modelviewprojection
;
29 const model_t
* current
;
45 raster_t
* raster_alloc(int width
, int height
, color_t fill
)
47 assert(0 < width
&& 0 < height
&& "zero-dimension raster not allowed");
48 size_t size
= width
* height
;
50 raster_t
* p
= (raster_t
*)mem_alloc(sizeof(raster_t
));
51 p
->pixels
= (color_t
*)mem_alloc(sizeof(color_t
) * size
);
54 raster_clear(p
, fill
);
55 raster_viewport(p
, 0, 0, width
, height
);
56 p
->model
= p
->view
= p
->projection
= MAT_IDENTITY
;
61 p
->ambient
= color_new(S(0.2), S(0.2), S(0.2), S(1.0));
63 p
->specular
= COLOR_WHITE
;
64 p
->shininess
= S(1.0);
67 p
->zbuf
= (scal_t
*)mem_alloc(sizeof(scal_t
) * size
);
68 for (size_t i
= 0; i
< size
; ++i
) {
75 void raster_destroy(raster_t
* p
)
80 list_destroy(&p
->lights
);
86 void raster_printstats(raster_t
* p
)
89 unsigned drawn
= p
->total
- p
->clipped
- p
->culled
;
90 float percent
= 100.0f
* (float)drawn
/ (float)p
->total
;
93 "drawn\t%u (%6.2f%%)\n"
94 "total\t%u\n", p
->culled
, p
->clipped
, drawn
, percent
, p
->total
);
99 color_t
raster_color(const raster_t
* p
, vec_t pt
)
101 int u
= (int)((scal_t
)p
->w
* pt
.x
);
102 int v
= (int)((scal_t
)p
->h
* pt
.y
);
103 return p
->pixels
[p
->w
* (p
->h
- v
- 1) + u
];
106 int raster_width(const raster_t
* p
)
111 int raster_height(const raster_t
* p
)
116 void* raster_data(const raster_t
* p
)
118 size_t size
= p
->w
* p
->h
;
119 rgba_t
* data
= mem_alloc(size
* sizeof(rgba_t
));
121 for (int i
= 0; i
< size
; ++i
) {
122 data
[i
] = rgba_from_color(p
->pixels
[i
]);
128 void raster_clear(raster_t
* p
, color_t fill
)
130 size_t size
= p
->w
* p
->h
;
131 for (int i
= 0; i
< size
; ++i
) {
142 void raster_viewport(raster_t
* p
, int x
, int y
, int width
, int height
)
145 p
->right
= x
+ width
;
148 p
->viewport
= MAT_VIEWPORT(x
, y
, width
, height
);
151 void raster_model(raster_t
* p
, const mat_t
* transform
)
153 p
->model
= *transform
;
157 void raster_view(raster_t
* p
, const mat_t
* transform
)
159 p
->view
= *transform
;
163 void raster_projection(raster_t
* p
, const mat_t
* transform
)
165 p
->projection
= *transform
;
170 void raster_eye(raster_t
* p
, vec_t eye
)
177 void raster_ambient(raster_t
* p
, color_t ambient
)
180 p
->ambient
= ambient
;
184 void raster_light(raster_t
* p
, light_t light
)
187 light_t
* l
= light_copy(light
);
188 list_push2(&p
->lights
, l
, mem_free
);
192 void raster_material(raster_t
* p
, color_t specular
, scal_t shininess
)
195 p
->specular
= specular
;
196 p
->shininess
= shininess
;
201 #define _DO_OR_DIE(X) if ((X) <= 0) goto fail
203 int raster_export_ppm(const raster_t
* p
, const char* filename
)
205 FILE* file
= fopen(filename
, "w");
207 fail
: fprintf(stderr
, "Cannot write to %s: %s\n", filename
, strerror(errno
));
211 _DO_OR_DIE(fprintf(file
, "P3\n%u %u\n255\n", p
->w
, p
->h
));
212 for (int y
= (int)p
->h
- 1; y
>= 0; --y
) {
213 for (int x
= 0; x
< p
->w
; ++x
) {
215 color_split(p
->pixels
[y
* p
->w
+ x
], &r
, &g
, &b
, NULL
);
216 _DO_OR_DIE(fprintf(file
, "%hhu %hhu %hhu\n", r
, g
, b
));
224 int raster_export_bmp(const raster_t
* p
, const char* filename
)
227 * This function was adapted from sample code provided with the assignment
230 FILE* file
= fopen(filename
, "wb");
232 fail
: fprintf(stderr
, "Cannot write to %s: %s\n", filename
, strerror(errno
));
236 uint16_t magicNumber
= 0x4D42;
237 uint16_t reserved0
= 0;//0x4D41;
238 uint16_t reserved1
= 0;//0x5454;
239 uint32_t dataOffset
= 54;
240 uint32_t infoHeaderSize
= 40;
241 uint32_t width
= p
->w
;
242 uint32_t height
= p
->h
;
243 uint16_t colorPlanes
= 1;
244 uint16_t bitsPerPixel
= 32;
245 uint32_t compression
= 0;
246 uint32_t dataSize
= width
* height
* bitsPerPixel
/ 8;
247 uint32_t horizontalResolution
= 2835;
248 uint32_t verticalResolution
= 2835;
249 uint32_t paletteColorCount
= 0;
250 uint32_t importantPaletteColorCount
= 0;
251 uint32_t fileSize
= 54 + dataSize
;
254 * Check the return values to avoid loud warnings.
256 _DO_OR_DIE(fwrite(&magicNumber
, sizeof(magicNumber
), 1, file
));
257 _DO_OR_DIE(fwrite(&fileSize
, sizeof(fileSize
), 1, file
));
258 _DO_OR_DIE(fwrite(&reserved0
, sizeof(reserved0
), 1, file
));
259 _DO_OR_DIE(fwrite(&reserved1
, sizeof(reserved1
), 1, file
));
260 _DO_OR_DIE(fwrite(&dataOffset
, sizeof(dataOffset
), 1, file
));
261 _DO_OR_DIE(fwrite(&infoHeaderSize
, sizeof(infoHeaderSize
), 1, file
));
262 _DO_OR_DIE(fwrite(&width
, sizeof(width
), 1, file
));
263 _DO_OR_DIE(fwrite(&height
, sizeof(height
), 1, file
));
264 _DO_OR_DIE(fwrite(&colorPlanes
, sizeof(colorPlanes
), 1, file
));
265 _DO_OR_DIE(fwrite(&bitsPerPixel
, sizeof(bitsPerPixel
), 1, file
));
266 _DO_OR_DIE(fwrite(&compression
, sizeof(compression
), 1, file
));
267 _DO_OR_DIE(fwrite(&dataSize
, sizeof(dataSize
), 1, file
));
268 _DO_OR_DIE(fwrite(&horizontalResolution
, sizeof(horizontalResolution
), 1, file
));
269 _DO_OR_DIE(fwrite(&verticalResolution
, sizeof(verticalResolution
), 1, file
));
270 _DO_OR_DIE(fwrite(&paletteColorCount
, sizeof(paletteColorCount
), 1, file
));
271 _DO_OR_DIE(fwrite(&importantPaletteColorCount
, sizeof(importantPaletteColorCount
), 1, file
));
273 size_t size
= width
* height
;
274 for (int i
= 0; i
< size
; ++i
)
277 rgbachan_t b
, g
, r
, a
;
279 color_split(p
->pixels
[i
], &argb
.r
, &argb
.g
, &argb
.b
, &argb
.a
);
280 _DO_OR_DIE(fwrite(&argb
, sizeof(argb
), 1, file
));
288 raster_t
* raster_import(const char* filename
)
291 char* ext
= strrchr(filename
, '.');
297 if (strcmp(ext
, "bmp") == 0) {
298 return raster_import_bmp(filename
);
300 if (strcmp(ext
, "ppm") == 0) {
301 return raster_import_ppm(filename
);
305 fprintf(stderr
, "Unknown file type: %s", filename
);
309 raster_t
* raster_import_ppm(const char* filename
)
311 FILE* file
= fopen(filename
, "r");
313 fprintf(stderr
, "Cannot read from %s: %s\n", filename
, strerror(errno
));
318 if (fscanf(file
, "P3 %d %d 255 ", &w
, &h
) != 2) {
319 fprintf(stderr
, "Cannot read header from %s: %s\n", filename
, strerror(errno
));
323 raster_t
* p
= raster_alloc(w
, h
, COLOR_WHITE
);
325 for (int y
= h
- 1; y
>= 0; --y
) {
326 for (int x
= 0; x
< w
; ++x
) {
328 /* mingw32 does not like %hhu conversion type */
329 if (fscanf(file
, "%hu %hu %hu ", &r
, &g
, &b
) != 3) {
330 fprintf(stderr
, "Failed reading color values from %s: %s\n", filename
, strerror(errno
));
336 rgbachan_t r
, g
, b
, a
;
339 u
.chan
.r
= (rgbachan_t
)r
;
340 u
.chan
.g
= (rgbachan_t
)g
;
341 u
.chan
.b
= (rgbachan_t
)b
;
343 p
->pixels
[y
* w
+ x
] = color_from_rgba(u
.rgba
);
353 fprintf(stderr
, "Unexpected file format in %s: %s\n", filename
, strerror(errno
));
357 raster_t
* raster_import_bmp(const char* filename
)
359 FILE* file
= fopen(filename
, "rb");
361 fprintf(stderr
, "Cannot read from %s: %s\n", filename
, strerror(errno
));
365 uint16_t magicNumber
;
366 uint16_t reserved0
;//0x4D41;
367 uint16_t reserved1
;//0x5454;
369 uint32_t infoHeaderSize
;
372 uint16_t colorPlanes
;
373 uint16_t bitsPerPixel
;
374 uint32_t compression
;
376 uint32_t horizontalResolution
;
377 uint32_t verticalResolution
;
378 uint32_t paletteColorCount
;
379 uint32_t importantPaletteColorCount
;
384 _DO_OR_DIE(fread(&magicNumber
, sizeof(magicNumber
), 1, file
));
385 _DO_OR_DIE(fread(&fileSize
, sizeof(fileSize
), 1, file
));
386 _DO_OR_DIE(fread(&reserved0
, sizeof(reserved0
), 1, file
));
387 _DO_OR_DIE(fread(&reserved1
, sizeof(reserved1
), 1, file
));
388 _DO_OR_DIE(fread(&dataOffset
, sizeof(dataOffset
), 1, file
));
389 _DO_OR_DIE(fread(&infoHeaderSize
, sizeof(infoHeaderSize
), 1, file
));
390 _DO_OR_DIE(fread(&width
, sizeof(width
), 1, file
));
391 _DO_OR_DIE(fread(&height
, sizeof(height
), 1, file
));
392 _DO_OR_DIE(fread(&colorPlanes
, sizeof(colorPlanes
), 1, file
));
393 _DO_OR_DIE(fread(&bitsPerPixel
, sizeof(bitsPerPixel
), 1, file
));
394 _DO_OR_DIE(fread(&compression
, sizeof(compression
), 1, file
));
395 _DO_OR_DIE(fread(&dataSize
, sizeof(dataSize
), 1, file
));
396 _DO_OR_DIE(fread(&horizontalResolution
, sizeof(horizontalResolution
), 1, file
));
397 _DO_OR_DIE(fread(&verticalResolution
, sizeof(verticalResolution
), 1, file
));
398 _DO_OR_DIE(fread(&paletteColorCount
, sizeof(paletteColorCount
), 1, file
));
399 _DO_OR_DIE(fread(&importantPaletteColorCount
, sizeof(importantPaletteColorCount
), 1, file
));
401 p
= raster_alloc((int)width
, (int)height
, COLOR_WHITE
);
403 size_t size
= width
* height
;
404 for (int i
= 0; i
< size
; ++i
)
409 rgbachan_t r
, g
, b
, a
;
412 _DO_OR_DIE(fread(&u
, sizeof(u
), 1, file
));
413 rgbachan_t t
= u
.chan
.r
;
424 p
->pixels
[i
] = color_from_rgba(u
.rgba
);
435 fprintf(stderr
, "Unexpected file format in %s: %s\n", filename
, strerror(errno
));
442 void raster_draw_model(raster_t
* p
, const model_t
* model
)
445 #define PROGRESS_FMT "\033[80D\033[2K %s\t %9d / %d"
449 model_transformation(model
, &p
->model
);
451 raster_material(p
, model_specular(model
), model_shininess(model
));
453 IF_RENDER_PROGRESS(tri
= 0);
454 array_it_t it
= array_begin(model_geometry(model
));
455 for (tri_t
* t
; t
= array_it_tri_next(&it
);) {
457 if (++tri
% 100 == 0) {
458 printf(PROGRESS_FMT
, model_name(model
), tri
, model_size(model
));
462 raster_draw_tri(p
, t
);
465 printf(PROGRESS_FMT
"\n", model_name(model
), tri
, model_size(model
));
471 * See if the triangle is at all visible in the viewport. Also, minimize the
472 * rectangle around the area that includes the triangle.
475 bool _try_clip(tri_t t
, int* left
, int* right
, int* bottom
, int* top
)
478 aabb_t box
= tri_aabb(t
);
479 if (box
.min
.z
< S(-1.0) || S(1.0) < box
.max
.z
) {
482 *left
= imax((int)scal_floor(box
.min
.x
), *left
);
483 *right
= imin((int)scal_ceil(box
.max
.x
), *right
);
484 if (*right
<= *left
) {
487 *bottom
= imax((int)scal_floor(box
.min
.y
), *bottom
);
488 *top
= imin((int)scal_ceil(box
.max
.y
), *top
);
489 if (*top
<= *bottom
) {
497 * See whether or not we need to draw based on the orientation of the
501 bool _try_cull_backface(tri_t t
)
504 vec_t n
= tri_normal(t
);
513 * Determine what color is associated with the given vertex.
516 color_t
_do_phong_lighting(raster_t
* p
, vert_t vert
)
519 vert
.c
= color_mult(vert
.c
, model_tcolor(p
->current
, vert
.t
));
522 color_t color
= COLOR_BLACK
;
524 for (list_t
* i
= p
->lights
; i
; i
= i
->link
) {
525 light_t light
= *(light_t
*)i
->val
;
527 vec_t lpos
= light
.v
;
530 vec_t l
= vec_normalize(vec_sub(lpos
, mpos
));
531 vec_t r
= vec_normalize(vec_sub(vec_scale(n
, S(2.0) * vec_dot(n
, l
)), l
));
532 vec_t v
= vec_normalize(vec_sub(vpos
, mpos
));
534 scal_t kd
= scal_max(vec_dot(l
, n
), S(0.0));
535 color_t Id
= color_scale2(light
.d
, vert
.c
, kd
);
536 scal_t ks
= scal_pow(scal_max(vec_dot(r
, v
), S(0.0)), p
->shininess
);
537 color_t Is
= color_scale2(light
.s
, p
->specular
, ks
);
539 color
= color_add2(color
, Id
, Is
);
541 color_t Ia
= color_mult(p
->ambient
, vert
.c
);
542 return color_clamp(color_add(color
, Ia
));
548 void raster_draw_tri(raster_t
* p
, const tri_t
* triangle
)
550 IF_RASTER_STATS(++p
->total
);
553 // need to recalculate the model-view-projection matrix if any one of its
554 // composing matrices have been changed
556 p
->modelviewprojection
= mat_mult(p
->view
, p
->model
);
557 p
->modelviewprojection
= mat_mult(p
->projection
, p
->modelviewprojection
);
561 t
= tri_transform(t
, p
->modelviewprojection
);
563 // save w-values for texture mapping perspective correction
570 if (!_try_cull_backface(t
)) {
571 IF_RASTER_STATS(++p
->culled
);
575 t
= tri_transform(t
, p
->viewport
);
578 int right
= p
->right
;
579 int bottom
= p
->bottom
;
582 if (!_try_clip(t
, &left
, &right
, &bottom
, &top
)) {
583 IF_RASTER_STATS(++p
->clipped
);
588 tri_t tl
= tri_transform(*triangle
, p
->model
);
595 vert_t tv
= vert_new(tri_midpoint(tl
));
596 tv
.n
= vec_normalize(tri_normal(tl
));
597 tv
.c
= tri_color(tl
);
598 color_t color
= _do_phong_lighting(p
, tv
);
599 #elif LIGHTING == 2 && SMOOTH_COLOR
600 color_t color1
= _do_phong_lighting(p
, tl
.a
);
601 color_t color2
= _do_phong_lighting(p
, tl
.b
);
602 color_t color3
= _do_phong_lighting(p
, tl
.c
);
603 #elif LIGHTING == 2 && !SMOOTH_COLOR
604 color_t c
= tri_color(t
);
605 tl
.a
.c
= tl
.b
.c
= tl
.c
.c
= c
;
606 color_t color1
= _do_phong_lighting(p
, tl
.a
);
607 color_t color2
= _do_phong_lighting(p
, tl
.b
);
608 color_t color3
= _do_phong_lighting(p
, tl
.c
);
609 #elif !LIGHTING && SMOOTH_COLOR
610 color_t color1
= t
.a
.c
;
611 color_t color2
= t
.b
.c
;
612 color_t color3
= t
.c
.c
;
614 color_t color
= tri_color(t
);
617 for (int y
= bottom
; y
< top
; ++y
) {
618 for (int x
= left
; x
< right
; ++x
) {
619 vec_t v
= vec_new((scal_t
)x
, (scal_t
)y
, S(0.0));
621 if (tri_barycentric(t
, b
, v
)) {
624 scal_t
* n
= p
->zbuf
+ y
* p
->w
+ x
;
625 if (S(-1.0) < v
.z
&& v
.z
< *n
) {
627 color_t
* c
= p
->pixels
+ y
* p
->w
+ x
;
630 #if LIGHTING == 2 || (!LIGHTING && SMOOTH_COLOR)
631 newC
= color_interp2(color1
, color2
, color3
, b
);
632 #elif LIGHTING == 3 && SMOOTH_COLOR
633 newC
= _do_phong_lighting(p
, tri_interp(tl
, b
));
634 #elif LIGHTING == 3 && !SMOOTH_COLOR
635 vert_t d
= vert_new(tri_point(t
, b
));
637 d
.n
= tri_normal2(t
, b
);
638 newC
= _do_phong_lighting(p
, d
);
644 *c
= color_blend(*c
, newC
);