3 * CS5600 University of Utah
5 * mcgarvey@eng.utah.edu
22 int left
, right
, bottom
, top
;
26 mat_t modelviewprojection
;
38 #define IF_RASTER_STATS(X) X
40 #define IF_RASTER_STATS(X)
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
;
60 p
->ambient
= color_new(S(0.05), S(0.05), S(0.05), S(1.0));
63 /*= light_new(COLOR_WHITE, vec_new(S(-2.0), S(4.0), S(0.0)));*/
64 p
->zbuf
= (scal_t
*)mem_alloc(sizeof(scal_t
) * size
);
65 for (size_t i
= 0; i
< size
; ++i
) {
72 void raster_destroy(raster_t
* p
)
80 void raster_printstats(raster_t
* p
)
83 unsigned drawn
= p
->total
- p
->clipped
- p
->culled
;
84 float percent
= 100.0f
* (float)drawn
/ (float)p
->total
;
87 "drawn\t%u (%6.2f%%)\n"
88 "total\t%u\n", p
->culled
, p
->clipped
, drawn
, percent
, p
->total
);
93 void raster_clear(raster_t
* p
, color_t fill
)
95 size_t size
= p
->w
* p
->h
;
96 for (int i
= 0; i
< size
; ++i
) {
107 void raster_viewport(raster_t
* p
, int x
, int y
, int width
, int height
)
110 p
->right
= x
+ width
;
113 p
->viewport
= MAT_VIEWPORT(x
, y
, width
, height
);
116 void raster_model(raster_t
* p
, const mat_t
* transform
)
118 p
->model
= *transform
;
122 void raster_view(raster_t
* p
, const mat_t
* transform
)
124 p
->view
= *transform
;
128 void raster_projection(raster_t
* p
, const mat_t
* transform
)
130 p
->projection
= *transform
;
135 void raster_eye(raster_t
* p
, vec_t eye
)
142 void raster_light(raster_t
* p
, light_t light
)
145 light_t
* l
= (light_t
*)mem_alloc(sizeof(light_t
));
146 memcpy(l
, &light
, sizeof(light_t
));
147 list_push2(&p
->lights
, l
, mem_free
);
152 #define _CHECK_WRITE(X) if ((X) <= 0) goto fail
154 int raster_export_ppm(const raster_t
* p
, const char* filename
)
156 FILE* file
= fopen(filename
, "w");
158 fail
: fprintf(stderr
, "Cannot write to %s: %s\n", filename
, strerror(errno
));
162 _CHECK_WRITE(fprintf(file
, "P3\n%u %u\n255\n", p
->w
, p
->h
));
163 for (int y
= (int)p
->h
- 1; y
>= 0; --y
) {
164 for (int x
= 0; x
< p
->w
; ++x
) {
166 color_split(p
->pixels
[y
* p
->w
+ x
], &r
, &g
, &b
, NULL
);
167 _CHECK_WRITE(fprintf(file
, "%hhu %hhu %hhu\n", r
, g
, b
));
175 int raster_export_bmp(const raster_t
* p
, const char* filename
)
178 * This function was adapted from sample code provided with the assignment
181 FILE* file
= fopen(filename
, "wb");
183 fail
: fprintf(stderr
, "Cannot write to %s: %s\n", filename
, strerror(errno
));
187 uint16_t magicNumber
= 0x4D42;
188 uint16_t reserved0
= 0;//0x4D41;
189 uint16_t reserved1
= 0;//0x5454;
190 uint32_t dataOffset
= 54;
191 uint32_t infoHeaderSize
= 40;
192 uint32_t width
= p
->w
;
193 uint32_t height
= p
->h
;
194 uint16_t colorPlanes
= 1;
195 uint16_t bitsPerPixel
= 32;
196 uint32_t compression
= 0;
197 uint32_t dataSize
= width
* height
* bitsPerPixel
/ 8;
198 uint32_t horizontalResolution
= 2835;
199 uint32_t verticalResolution
= 2835;
200 uint32_t paletteColorCount
= 0;
201 uint32_t importantPaletteColorCount
= 0;
202 uint32_t fileSize
= 54 + dataSize
;
205 * Check the return values to avoid loud warnings.
207 _CHECK_WRITE(fwrite(&magicNumber
, sizeof(magicNumber
), 1, file
));
208 _CHECK_WRITE(fwrite(&fileSize
, sizeof(fileSize
), 1, file
));
209 _CHECK_WRITE(fwrite(&reserved0
, sizeof(reserved0
), 1, file
));
210 _CHECK_WRITE(fwrite(&reserved1
, sizeof(reserved1
), 1, file
));
211 _CHECK_WRITE(fwrite(&dataOffset
, sizeof(dataOffset
), 1, file
));
212 _CHECK_WRITE(fwrite(&infoHeaderSize
, sizeof(infoHeaderSize
), 1, file
));
213 _CHECK_WRITE(fwrite(&width
, sizeof(width
), 1, file
));
214 _CHECK_WRITE(fwrite(&height
, sizeof(height
), 1, file
));
215 _CHECK_WRITE(fwrite(&colorPlanes
, sizeof(colorPlanes
), 1, file
));
216 _CHECK_WRITE(fwrite(&bitsPerPixel
, sizeof(bitsPerPixel
), 1, file
));
217 _CHECK_WRITE(fwrite(&compression
, sizeof(compression
), 1, file
));
218 _CHECK_WRITE(fwrite(&dataSize
, sizeof(dataSize
), 1, file
));
219 _CHECK_WRITE(fwrite(&horizontalResolution
, sizeof(horizontalResolution
), 1, file
));
220 _CHECK_WRITE(fwrite(&verticalResolution
, sizeof(verticalResolution
), 1, file
));
221 _CHECK_WRITE(fwrite(&paletteColorCount
, sizeof(paletteColorCount
), 1, file
));
222 _CHECK_WRITE(fwrite(&importantPaletteColorCount
, sizeof(importantPaletteColorCount
), 1, file
));
224 size_t size
= width
* height
;
225 for (int i
= 0; i
< size
; ++i
)
227 rgbachan_t a
, r
, g
, b
;
228 color_split(p
->pixels
[i
], &r
, &g
, &b
, &a
);
229 uint32_t argb
= PACK(argb
, 3, a
);
230 argb
= PACK(argb
, 2, r
);
231 argb
= PACK(argb
, 1, g
);
232 argb
= PACK(argb
, 0, b
);
233 _CHECK_WRITE(fwrite(&argb
, sizeof(argb
), 1, file
));
244 * See if the triangle is at all visible in the viewport. Also, minimize the
245 * rectangle around the area that includes the triangle.
248 bool _try_clip(tri_t t
, int* left
, int* right
, int* bottom
, int* top
)
251 aabb_t box
= tri_aabb(t
);
252 if (box
.min
.z
< S(-1.0) || S(1.0) < box
.max
.z
) {
255 *left
= imax((int)scal_floor(box
.min
.x
), *left
);
256 *right
= imin((int)scal_ceil(box
.max
.x
), *right
);
257 if (*right
<= *left
) {
260 *bottom
= imax((int)scal_floor(box
.min
.y
), *bottom
);
261 *top
= imin((int)scal_ceil(box
.max
.y
), *top
);
262 if (*top
<= *bottom
) {
270 * See whether or not we need to draw based on the orientation of the
274 bool _try_cull_backface(tri_t t
)
277 vec_t n
= tri_normal(t
);
286 * Determine what color is associated with the given vertex.
289 color_t
_get_vertex_color(raster_t
* p
, vert_t vert
)
292 color_t color
= COLOR_BLACK
;
293 for (list_t
* i
= p
->lights
; i
; i
= i
->link
) {
294 light_t light
= *(light_t
*)i
->val
;
296 vec_t lpos
= light
.position
;
299 vec_t l
= vec_normalize(vec_sub(lpos
, mpos
));
300 vec_t r
= vec_sub(vec_scale(n
, S(2.0) * vec_dot(n
, l
)), l
);
301 vec_t v
= vec_normalize(vec_sub(vpos
, mpos
));
303 scal_t kd
= scal_max(vec_dot(l
, n
), S(0.0));
304 color_t Id
= color_new(
305 light
.color
.r
* vert
.c
.r
* kd
,
306 light
.color
.g
* vert
.c
.g
* kd
,
307 light
.color
.b
* vert
.c
.b
* kd
,
310 scal_t ks
= scal_pow(scal_max(vec_dot(r
, v
), S(0.0)), S(64.0));
311 color_t Is
= color_new(
312 light
.color
.r
* COLOR_WHITE
.r
* ks
,
313 light
.color
.g
* COLOR_WHITE
.g
* ks
,
314 light
.color
.b
* COLOR_WHITE
.b
* ks
,
318 color
= color_add2(color
, Id
, Is
);
320 color_t Ia
= p
->ambient
;
321 return color_clamp(color_add(color
, Ia
));
327 void raster_draw_tri(raster_t
* p
, const tri_t
* triangle
)
329 IF_RASTER_STATS(++p
->total
);
332 // need to recalculate the model-view-projection matrix if any one of its
333 // composing matrices have been changed
335 p
->modelviewprojection
= mat_mult(p
->view
, p
->model
);
336 p
->modelviewprojection
= mat_mult(p
->projection
, p
->modelviewprojection
);
339 t
= tri_transform(t
, p
->modelviewprojection
);
342 if (!_try_cull_backface(t
)) {
343 IF_RASTER_STATS(++p
->culled
);
347 t
= tri_transform(t
, p
->viewport
);
350 int right
= p
->right
;
351 int bottom
= p
->bottom
;
354 if (!_try_clip(t
, &left
, &right
, &bottom
, &top
)) {
355 IF_RASTER_STATS(++p
->clipped
);
359 tri_t temp
= tri_transform(*triangle
, p
->model
);
360 #if LIGHTING && (!FIND_NORMALS || (!SMOOTH_COLOR && FIND_NORMALS == 2))
361 temp
.a
.n
= temp
.b
.n
= temp
.c
.n
= vec_normalize(tri_normal(temp
));
364 temp
.a
.c
= tri_color(temp
);
366 color_t color1
= _get_vertex_color(p
, temp
.a
);
368 color_t color2
= _get_vertex_color(p
, temp
.b
);
369 color_t color3
= _get_vertex_color(p
, temp
.c
);
372 for (int y
= bottom
; y
< top
; ++y
) {
373 for (int x
= left
; x
< right
; ++x
) {
374 vec_t v
= vec_new((scal_t
)x
, (scal_t
)y
, S(0.0));
376 if (tri_barycentric(t
, b
, v
)) {
379 scal_t
* n
= p
->zbuf
+ y
* p
->w
+ x
;
380 if (S(-1.0) < v
.z
&& v
.z
< *n
) {
382 color_t
* c
= p
->pixels
+ y
* p
->w
+ x
;
384 *c
= color_interp2(color1
, color2
, color3
, b
);