X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Frasterize;a=blobdiff_plain;f=raster.c;h=9ab926a0a30030374bd0b695c5b0e990b6fc8386;hp=23b1d69d19f5f0f855ec843ff4532ee379ed6fa7;hb=3955aa40277c4b86a43b21e78d55d2fea7b643ce;hpb=c875478cdd823c7df8fdc859941bd9e5948c9315 diff --git a/raster.c b/raster.c index 23b1d69..9ab926a 100644 --- a/raster.c +++ b/raster.c @@ -26,18 +26,18 @@ struct raster mat_t modelviewprojection; mat_t viewport; bool dirty; + const model_t* current; #if LIGHTING list_t* lights; color_t ambient; vec_t eye; + color_t specular; + scal_t shininess; #endif -#if RASTER_STATS +#if VERBOSITY >= 2 unsigned total; unsigned clipped; unsigned culled; -#define IF_RASTER_STATS(X) X -#else -#define IF_RASTER_STATS(X) #endif }; @@ -55,12 +55,15 @@ raster_t* raster_alloc(int width, int height, color_t fill) raster_viewport(p, 0, 0, width, height); p->model = p->view = p->projection = MAT_IDENTITY; p->dirty = false; + p->current = NULL; #if LIGHTING - p->ambient = color_new(S(0.05), S(0.05), S(0.05), S(1.0)); + p->ambient = color_new(S(0.2), S(0.2), S(0.2), S(1.0)); p->lights = NULL; + p->specular = COLOR_WHITE; + p->shininess = S(1.0); #endif - /*= light_new(COLOR_WHITE, vec_new(S(-2.0), S(4.0), S(0.0)));*/ + p->zbuf = (scal_t*)mem_alloc(sizeof(scal_t) * size); for (size_t i = 0; i < size; ++i) { p->zbuf[i] = S(1.0); @@ -73,13 +76,16 @@ void raster_destroy(raster_t* p) { mem_free(p->pixels); mem_free(p->zbuf); +#if LIGHTING + list_destroy(&p->lights); +#endif mem_free(p); } void raster_printstats(raster_t* p) { -#if RASTER_STATS +#if VERBOSITY >= 2 unsigned drawn = p->total - p->clipped - p->culled; float percent = 100.0f * (float)drawn / (float)p->total; printf("culled\t%u\n" @@ -90,13 +96,21 @@ void raster_printstats(raster_t* p) } +color_t raster_color(const raster_t* p, vec_t pt) +{ + int u = (int)((scal_t)p->w * pt.x); + int v = (int)((scal_t)p->h * pt.y); + return p->pixels[p->w * (p->h - v - 1) + u]; +} + + void raster_clear(raster_t* p, color_t fill) { size_t size = p->w * p->h; for (int i = 0; i < size; ++i) { p->pixels[i] = fill; } -#if RASTER_STATS +#if VERBOSITY >= 2 p->total = 0; p->clipped = 0; p->culled = 0; @@ -139,17 +153,31 @@ void raster_eye(raster_t* p, vec_t eye) #endif } +void raster_ambient(raster_t* p, color_t ambient) +{ +#if LIGHTING + p->ambient = ambient; +#endif +} + void raster_light(raster_t* p, light_t light) { #if LIGHTING - light_t* l = (light_t*)mem_alloc(sizeof(light_t)); - memcpy(l, &light, sizeof(light_t)); + light_t* l = light_copy(light); list_push2(&p->lights, l, mem_free); #endif } +void raster_material(raster_t* p, color_t specular, scal_t shininess) +{ +#if LIGHTING + p->specular = specular; + p->shininess = shininess; +#endif +} + -#define _CHECK_WRITE(X) if ((X) <= 0) goto fail +#define _DO_OR_DIE(X) if ((X) <= 0) goto fail int raster_export_ppm(const raster_t* p, const char* filename) { @@ -159,12 +187,12 @@ fail: fprintf(stderr, "Cannot write to %s: %s\n", filename, strerror(errno)); return -1; } - _CHECK_WRITE(fprintf(file, "P3\n%u %u\n255\n", p->w, p->h)); + _DO_OR_DIE(fprintf(file, "P3\n%u %u\n255\n", p->w, p->h)); for (int y = (int)p->h - 1; y >= 0; --y) { for (int x = 0; x < p->w; ++x) { rgbachan_t r, g, b; color_split(p->pixels[y * p->w + x], &r, &g, &b, NULL); - _CHECK_WRITE(fprintf(file, "%hhu %hhu %hhu\n", r, g, b)); + _DO_OR_DIE(fprintf(file, "%hhu %hhu %hhu\n", r, g, b)); } } @@ -204,22 +232,22 @@ fail: fprintf(stderr, "Cannot write to %s: %s\n", filename, strerror(errno)); /* * Check the return values to avoid loud warnings. */ - _CHECK_WRITE(fwrite(&magicNumber, sizeof(magicNumber), 1, file)); - _CHECK_WRITE(fwrite(&fileSize, sizeof(fileSize), 1, file)); - _CHECK_WRITE(fwrite(&reserved0, sizeof(reserved0), 1, file)); - _CHECK_WRITE(fwrite(&reserved1, sizeof(reserved1), 1, file)); - _CHECK_WRITE(fwrite(&dataOffset, sizeof(dataOffset), 1, file)); - _CHECK_WRITE(fwrite(&infoHeaderSize, sizeof(infoHeaderSize), 1, file)); - _CHECK_WRITE(fwrite(&width, sizeof(width), 1, file)); - _CHECK_WRITE(fwrite(&height, sizeof(height), 1, file)); - _CHECK_WRITE(fwrite(&colorPlanes, sizeof(colorPlanes), 1, file)); - _CHECK_WRITE(fwrite(&bitsPerPixel, sizeof(bitsPerPixel), 1, file)); - _CHECK_WRITE(fwrite(&compression, sizeof(compression), 1, file)); - _CHECK_WRITE(fwrite(&dataSize, sizeof(dataSize), 1, file)); - _CHECK_WRITE(fwrite(&horizontalResolution, sizeof(horizontalResolution), 1, file)); - _CHECK_WRITE(fwrite(&verticalResolution, sizeof(verticalResolution), 1, file)); - _CHECK_WRITE(fwrite(&paletteColorCount, sizeof(paletteColorCount), 1, file)); - _CHECK_WRITE(fwrite(&importantPaletteColorCount, sizeof(importantPaletteColorCount), 1, file)); + _DO_OR_DIE(fwrite(&magicNumber, sizeof(magicNumber), 1, file)); + _DO_OR_DIE(fwrite(&fileSize, sizeof(fileSize), 1, file)); + _DO_OR_DIE(fwrite(&reserved0, sizeof(reserved0), 1, file)); + _DO_OR_DIE(fwrite(&reserved1, sizeof(reserved1), 1, file)); + _DO_OR_DIE(fwrite(&dataOffset, sizeof(dataOffset), 1, file)); + _DO_OR_DIE(fwrite(&infoHeaderSize, sizeof(infoHeaderSize), 1, file)); + _DO_OR_DIE(fwrite(&width, sizeof(width), 1, file)); + _DO_OR_DIE(fwrite(&height, sizeof(height), 1, file)); + _DO_OR_DIE(fwrite(&colorPlanes, sizeof(colorPlanes), 1, file)); + _DO_OR_DIE(fwrite(&bitsPerPixel, sizeof(bitsPerPixel), 1, file)); + _DO_OR_DIE(fwrite(&compression, sizeof(compression), 1, file)); + _DO_OR_DIE(fwrite(&dataSize, sizeof(dataSize), 1, file)); + _DO_OR_DIE(fwrite(&horizontalResolution, sizeof(horizontalResolution), 1, file)); + _DO_OR_DIE(fwrite(&verticalResolution, sizeof(verticalResolution), 1, file)); + _DO_OR_DIE(fwrite(&paletteColorCount, sizeof(paletteColorCount), 1, file)); + _DO_OR_DIE(fwrite(&importantPaletteColorCount, sizeof(importantPaletteColorCount), 1, file)); size_t size = width * height; for (int i = 0; i < size; ++i) @@ -230,14 +258,174 @@ fail: fprintf(stderr, "Cannot write to %s: %s\n", filename, strerror(errno)); argb = PACK(argb, 2, r); argb = PACK(argb, 1, g); argb = PACK(argb, 0, b); - _CHECK_WRITE(fwrite(&argb, sizeof(argb), 1, file)); + _DO_OR_DIE(fwrite(&argb, sizeof(argb), 1, file)); } fclose(file); return 0; } -#undef _CHECK_WRITE + +raster_t* raster_import(const char* filename) +{ + int type = 0; + char* ext = strrchr(filename, '.'); + if (ext == NULL) { + goto fail; + } + ++ext; + + if (strcmp(ext, "bmp") == 0) { + return raster_import_bmp(filename); + } + if (strcmp(ext, "ppm") == 0) { + return raster_import_ppm(filename); + } + +fail: + fprintf(stderr, "Unknown file type: %s", filename); + return NULL; +} + +raster_t* raster_import_ppm(const char* filename) +{ + FILE* file = fopen(filename, "r"); + if (file == NULL) { + fprintf(stderr, "Cannot read from %s: %s\n", filename, strerror(errno)); + return NULL; + } + + int w, h; + if (fscanf(file, "P3 %d %d 255 ", &w, &h) != 2) { + fprintf(stderr, "Cannot read header from %s: %s\n", filename, strerror(errno)); + return NULL; + } + + raster_t* p = raster_alloc(w, h, COLOR_WHITE); + + for (int y = h - 1; y >= 0; --y) { + for (int x = 0; x < w; ++x) { + rgbachan_t r, g, b; + if (fscanf(file, "%hhu %hhu %hhu ", &r, &g, &b) != 3) { + fprintf(stderr, "Failed reading color values from %s: %s\n", filename, strerror(errno)); + return NULL; + } + rgba_t rgba = PACK(rgba, 3, r); + rgba = PACK(rgba, 2, g); + rgba = PACK(rgba, 1, b); + rgba = PACK(rgba, 0, 255); + p->pixels[y * w + x] = color_from_rgba(rgba); + } + } + + fclose(file); + return p; + +fail: + raster_destroy(p); + fclose(file); + fprintf(stderr, "Unexpected file format in %s: %s\n", filename, strerror(errno)); + return NULL; +} + +raster_t* raster_import_bmp(const char* filename) +{ + FILE* file = fopen(filename, "rb"); + if (file == NULL) { + fprintf(stderr, "Cannot read from %s: %s\n", filename, strerror(errno)); + return NULL; + } + + uint16_t magicNumber; + uint16_t reserved0;//0x4D41; + uint16_t reserved1;//0x5454; + uint32_t dataOffset; + uint32_t infoHeaderSize; + uint32_t width; + uint32_t height; + uint16_t colorPlanes; + uint16_t bitsPerPixel; + uint32_t compression; + uint32_t dataSize; + uint32_t horizontalResolution; + uint32_t verticalResolution; + uint32_t paletteColorCount; + uint32_t importantPaletteColorCount; + uint32_t fileSize; + + raster_t* p = NULL; + + _DO_OR_DIE(fread(&magicNumber, sizeof(magicNumber), 1, file)); + _DO_OR_DIE(fread(&fileSize, sizeof(fileSize), 1, file)); + _DO_OR_DIE(fread(&reserved0, sizeof(reserved0), 1, file)); + _DO_OR_DIE(fread(&reserved1, sizeof(reserved1), 1, file)); + _DO_OR_DIE(fread(&dataOffset, sizeof(dataOffset), 1, file)); + _DO_OR_DIE(fread(&infoHeaderSize, sizeof(infoHeaderSize), 1, file)); + _DO_OR_DIE(fread(&width, sizeof(width), 1, file)); + _DO_OR_DIE(fread(&height, sizeof(height), 1, file)); + _DO_OR_DIE(fread(&colorPlanes, sizeof(colorPlanes), 1, file)); + _DO_OR_DIE(fread(&bitsPerPixel, sizeof(bitsPerPixel), 1, file)); + _DO_OR_DIE(fread(&compression, sizeof(compression), 1, file)); + _DO_OR_DIE(fread(&dataSize, sizeof(dataSize), 1, file)); + _DO_OR_DIE(fread(&horizontalResolution, sizeof(horizontalResolution), 1, file)); + _DO_OR_DIE(fread(&verticalResolution, sizeof(verticalResolution), 1, file)); + _DO_OR_DIE(fread(&paletteColorCount, sizeof(paletteColorCount), 1, file)); + _DO_OR_DIE(fread(&importantPaletteColorCount, sizeof(importantPaletteColorCount), 1, file)); + + p = raster_alloc((int)width, (int)height, COLOR_WHITE); + + size_t size = width * height; + for (int i = 0; i < size; ++i) + { + uint32_t argb; + _DO_OR_DIE(fread(&argb, sizeof(argb), 1, file)); + rgba_t rgba = PACK(rgba, 3, UNPACK(argb, 2)); + rgba = PACK(rgba, 2, UNPACK(argb, 1)); + rgba = PACK(rgba, 1, UNPACK(argb, 0)); + rgba = PACK(rgba, 0, UNPACK(argb, 3)); + p->pixels[i] = color_from_rgba(rgba); + } + + fclose(file); + return p; + +fail: + if (p) { + raster_destroy(p); + } + fclose(file); + fprintf(stderr, "Unexpected file format in %s: %s\n", filename, strerror(errno)); + return NULL; +} + +#undef _DO_OR_DIE + + +void raster_draw_model(raster_t* p, const model_t* model) +{ +#if VERBOSITY >= 4 +#define PROGRESS_FMT "\033[80D\033[2K %s\t %9d / %d" + int tri; +#endif + + model_transformation(model, &p->model); + p->dirty = true; + raster_material(p, model_specular(model), model_shininess(model)); + p->current = model; + IF_RENDER_PROGRESS(tri = 0); + for (const list_t* ti = model_geometry(model); ti; ti = ti->link) { +#if VERBOSITY >= 4 + if (++tri % 100 == 0) { + printf(PROGRESS_FMT, model_name(model), tri, model_size(model)); + fflush(stdout); + } +#endif + raster_draw_tri(p, (tri_t*)ti->val); + } +#if VERBOSITY >= 4 + printf(PROGRESS_FMT"\n", model_name(model), tri, model_size(model)); +#endif +} /* @@ -286,38 +474,32 @@ bool _try_cull_backface(tri_t t) * Determine what color is associated with the given vertex. */ INLINE_MAYBE -color_t _get_vertex_color(raster_t* p, vert_t vert) +color_t _do_phong_lighting(raster_t* p, vert_t vert) { +#if TEXTURING + vert.c = color_mult(vert.c, model_tcolor(p->current, vert.t)); +#endif #if LIGHTING color_t color = COLOR_BLACK; + color.a = vert.c.a; for (list_t* i = p->lights; i; i = i->link) { light_t light = *(light_t*)i->val; vec_t mpos = vert.v; - vec_t lpos = light.position; + vec_t lpos = light.v; vec_t vpos = p->eye; vec_t n = vert.n; vec_t l = vec_normalize(vec_sub(lpos, mpos)); - vec_t r = vec_sub(vec_scale(n, S(2.0) * vec_dot(n, l)), l); + vec_t r = vec_normalize(vec_sub(vec_scale(n, S(2.0) * vec_dot(n, l)), l)); vec_t v = vec_normalize(vec_sub(vpos, mpos)); scal_t kd = scal_max(vec_dot(l, n), S(0.0)); - color_t Id = color_new( - light.color.r * vert.c.r * kd, - light.color.g * vert.c.g * kd, - light.color.b * vert.c.b * kd, - S(1.0) - ); - scal_t ks = scal_pow(scal_max(vec_dot(r, v), S(0.0)), S(64.0)); - color_t Is = color_new( - light.color.r * COLOR_WHITE.r * ks, - light.color.g * COLOR_WHITE.g * ks, - light.color.b * COLOR_WHITE.b * ks, - S(1.0) - ); + color_t Id = color_scale2(light.d, vert.c, kd); + scal_t ks = scal_pow(scal_max(vec_dot(r, v), S(0.0)), p->shininess); + color_t Is = color_scale2(light.s, p->specular, ks); color = color_add2(color, Id, Is); } - color_t Ia = p->ambient; + color_t Ia = color_mult(p->ambient, vert.c); return color_clamp(color_add(color, Ia)); #else return vert.c; @@ -336,7 +518,14 @@ void raster_draw_tri(raster_t* p, const tri_t* triangle) p->modelviewprojection = mat_mult(p->projection, p->modelviewprojection); p->dirty = false; } + t = tri_transform(t, p->modelviewprojection); + + // save w-values for texture mapping perspective correction + scal_t w1 = t.a.v.w; + scal_t w2 = t.b.v.w; + scal_t w3 = t.c.v.w; + t = tri_homodiv(t); if (!_try_cull_backface(t)) { @@ -356,17 +545,34 @@ void raster_draw_tri(raster_t* p, const tri_t* triangle) return; } - tri_t temp = tri_transform(*triangle, p->model); -#if LIGHTING && (!FIND_NORMALS || (!SMOOTH_COLOR && FIND_NORMALS == 2)) - temp.a.n = temp.b.n = temp.c.n = vec_normalize(tri_normal(temp)); +#if LIGHTING >= 1 + tri_t tl = tri_transform(*triangle, p->model); + tl.a.t.w = w1; + tl.b.t.w = w2; + tl.c.t.w = w3; #endif -#if !SMOOTH_COLOR - temp.a.c = tri_color(temp); -#endif - color_t color1 = _get_vertex_color(p, temp.a); -#if SMOOTH_COLOR - color_t color2 = _get_vertex_color(p, temp.b); - color_t color3 = _get_vertex_color(p, temp.c); + +#if LIGHTING == 1 + vert_t tv = vert_new(tri_midpoint(tl)); + tv.n = vec_normalize(tri_normal(tl)); + tv.c = tri_color(tl); + color_t color = _do_phong_lighting(p, tv); +#elif LIGHTING == 2 && SMOOTH_COLOR + color_t color1 = _do_phong_lighting(p, tl.a); + color_t color2 = _do_phong_lighting(p, tl.b); + color_t color3 = _do_phong_lighting(p, tl.c); +#elif LIGHTING == 2 && !SMOOTH_COLOR + color_t c = tri_color(t); + tl.a.c = tl.b.c = tl.c.c = c; + color_t color1 = _do_phong_lighting(p, tl.a); + color_t color2 = _do_phong_lighting(p, tl.b); + color_t color3 = _do_phong_lighting(p, tl.c); +#elif !LIGHTING && SMOOTH_COLOR + color_t color1 = t.a.c; + color_t color2 = t.b.c; + color_t color3 = t.c.c; +#else + color_t color = tri_color(t); #endif for (int y = bottom; y < top; ++y) { @@ -380,11 +586,27 @@ void raster_draw_tri(raster_t* p, const tri_t* triangle) if (S(-1.0) < v.z && v.z < *n) { #endif color_t* c = p->pixels + y * p->w + x; -#if SMOOTH_COLOR - *c = color_interp2(color1, color2, color3, b); + color_t newC; + +#if LIGHTING == 2 || (!LIGHTING && SMOOTH_COLOR) + newC = color_interp2(color1, color2, color3, b); +#elif LIGHTING == 3 && SMOOTH_COLOR + newC = _do_phong_lighting(p, tri_interp(tl, b)); +#elif LIGHTING == 3 && !SMOOTH_COLOR + vert_t d = vert_new(tri_point(t, b)); + d.c = tri_color(t); + d.n = tri_normal2(t, b); + newC = _do_phong_lighting(p, d); #else - *c = color1; + newC = color; #endif + +#if BLENDING + *c = color_blend(*c, newC); +#else + *c = newC; +#endif + #if DEPTH_TEST *n = v.z; }