+
+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) {
+ uint16_t r, g, b;
+ /* mingw32 does not like %hhu conversion type */
+ if (fscanf(file, "%hu %hu %hu ", &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, (uint8_t)r);
+ rgba = PACK(rgba, 2, (uint8_t)g);
+ rgba = PACK(rgba, 1, (uint8_t)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
+}