#include "ppm.h" #include #include #include #include #include ppm_image *ppm_create(uint64_t height, uint64_t width) { return ppm_create_with_background_color(height, width, PPM_BLACK); } ppm_image *ppm_create_with_background_color(uint64_t height, uint64_t width, ppm_rgb background_color) { ppm_image *image = (ppm_image *)malloc(sizeof(ppm_image)); image->height = height; image->width = width; ppm_rgb *data = (ppm_rgb *)malloc(sizeof(ppm_rgb) * width * height); for (uint64_t y = 0; y < height; y++) { for (uint64_t x = 0; x < width; x++) { uint64_t position = (y * width) + x; data[position] = background_color; } } image->data = data; return image; } int ppm_destroy(ppm_image *image) { free(image->data); free(image); return EXIT_SUCCESS; } int ppm_is_in_bounds(ppm_image *image, uint64_t x, uint64_t y) { if (x <= 0) return EXIT_FAILURE; if (x > image->width) return EXIT_FAILURE; if (y <= 0) return EXIT_FAILURE; if (y > image->height) return EXIT_FAILURE; return EXIT_SUCCESS; } int ppm_to_ppm3_file(ppm_image *image, const char *file_path) { FILE *file = fopen(file_path, "w"); fprintf(file, "P3\n"); fprintf(file, "%" PRIu64 " %" PRIu64 "\n", image->height, image->width); fprintf(file, "255\n"); for (uint64_t y = 0; y < image->height; y++) { for (uint64_t x = 0; x < image->width; x++) { uint64_t position = (y * image->width) + x; ppm_rgb rgb = image->data[position]; fprintf(file, "%" PRIu8 " %" PRIu8 " %" PRIu8, rgb.r, rgb.g, rgb.b); if (x != image->width - 1) { fprintf(file, " "); } } if (y != image->height - 1) { fprintf(file, "\n"); } } fclose(file); return EXIT_SUCCESS; } int ppm_to_ppm6_file(ppm_image *image, const char *file_path) { FILE *file = fopen(file_path, "w"); fprintf(file, "P6\n"); fprintf(file, "%" PRIu64 " %" PRIu64 "\n", image->height, image->width); fprintf(file, "255\n"); for (uint64_t y = 0; y < image->height; y++) { for (uint64_t x = 0; x < image->width; x++) { uint64_t position = (y * image->width) + x; ppm_rgb rgb = image->data[position]; fprintf(file, "%c%c%c", rgb.r, rgb.g, rgb.b); } } fclose(file); return EXIT_SUCCESS; } int ppm_draw_point(ppm_image *image, uint64_t x, uint64_t y, ppm_rgb color) { if (ppm_is_in_bounds(image, x, y) == EXIT_FAILURE) return EXIT_FAILURE; uint64_t position = ((y - 1) * image->width) + x - 1; image->data[position] = color; return EXIT_SUCCESS; } int ppm_draw_circle(ppm_image *image, int x, int y, uint64_t radius, ppm_rgb color) { for (int local_y = 0; local_y <= radius * 2; local_y++) { for (int local_x = 0; local_x <= radius * 2; local_x++) { int local_centered_x = local_x - radius; int local_centered_y = local_y - radius; uint64_t length = sqrt((local_centered_x * local_centered_x) + (local_centered_y * local_centered_y)); if (length > radius) continue; uint64_t global_x = local_x + x - radius; uint64_t global_y = local_y + y - radius; ppm_draw_point(image, global_x, global_y, color); } } return EXIT_SUCCESS; } int ppm_draw_rectangle(ppm_image *image, int x, int y, uint64_t height, uint64_t width, ppm_rgb color) { for (int local_y = 0; local_y <= height; local_y++) { for (int local_x = 0; local_x <= width; local_x++) { uint64_t global_x = local_x + x; uint64_t global_y = local_y + y; ppm_draw_point(image, global_x, global_y, color); } } return EXIT_SUCCESS; } /** * Draw a line using Bresenham's line algorithm. */ int ppm_draw_line(ppm_image *image, int x1, int y1, int x2, int y2, ppm_rgb color) { int dx = x2 - x1; int dy = y2 - y1; int d = 2 * dy - dx; int y = y1; for (int x = x1; x < x2; x++) { ppm_draw_point(image, x, y, color); if (d > 0) { y++; d -= 2 * dx; } d += 2 * dy; } return EXIT_SUCCESS; } int ppm_clear(ppm_image *image) { ppm_clear_with_background_color(image, PPM_BLACK); return EXIT_SUCCESS; } int ppm_clear_with_background_color(ppm_image *image, ppm_rgb background_color) { for (uint64_t y = 0; y < image->height; y++) { for (uint64_t x = 0; x < image->width; x++) { uint64_t position = (y * image->width) + x; image->data[position] = background_color; } } return EXIT_SUCCESS; }