﻿#include <stdio.h>
#include <stdlib.h>
#include <png.h>
#include <math.h>

#define WIDTH 800
#define HEIGHT 600

png_bytep* row_pointers;

void init_image() {
    row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * HEIGHT);
    for (int y = 0; y < HEIGHT; y++) {
        row_pointers[y] = (png_byte*)malloc(WIDTH * 3);
        for (int x = 0; x < WIDTH; x++) {
            row_pointers[y][x * 3] = 255;
            row_pointers[y][x * 3 + 1] = 255;
            row_pointers[y][x * 3 + 2] = 255;
        }
    }
}

void set_pixel(int x, int y, int r, int g, int b) {
    if (x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT) {
        row_pointers[y][x * 3] = r;
        row_pointers[y][x * 3 + 1] = g;
        row_pointers[y][x * 3 + 2] = b;
    }
}

void get_pixel(int x, int y, int* r, int* g, int* b) {
    if (x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT) {
        *r = row_pointers[y][x * 3];
        *g = row_pointers[y][x * 3 + 1];
        *b = row_pointers[y][x * 3 + 2];
    }
    else {
        *r = *g = *b = -1;
    }
}

void draw_line(int x0, int y0, int x1, int y1, int r, int g, int b) {
    int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
    int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
    int err = dx + dy, e2;

    while (1) {
        set_pixel(x0, y0, r, g, b);
        if (x0 == x1 && y0 == y1) break;
        e2 = 2 * err;
        if (e2 >= dy) { err += dy; x0 += sx; }
        if (e2 <= dx) { err += dx; y0 += sy; }
    }
}

void draw_circle(int xc, int yc, int radius, int r, int g, int b) {
    int x = 0, y = radius;
    int d = 3 - 2 * radius;
    while (y >= x) {
        set_pixel(xc + x, yc + y, r, g, b);
        set_pixel(xc - x, yc + y, r, g, b);
        set_pixel(xc + x, yc - y, r, g, b);
        set_pixel(xc - x, yc - y, r, g, b);
        set_pixel(xc + y, yc + x, r, g, b);
        set_pixel(xc - y, yc + x, r, g, b);
        set_pixel(xc + y, yc - x, r, g, b);
        set_pixel(xc - y, yc - x, r, g, b);
        x++;
        if (d > 0) {
            y--;
            d = d + 4 * (x - y) + 10;
        }
        else {
            d = d + 4 * x + 6;
        }
    }
}

typedef struct { int x, y; } Point;
void flood_fill(int start_x, int start_y, int fill_r, int fill_g, int fill_b) {
    int target_r, target_g, target_b;
    get_pixel(start_x, start_y, &target_r, &target_g, &target_b);

    if (target_r == fill_r && target_g == fill_g && target_b == fill_b) return;

    int max_stack_size = WIDTH * HEIGHT * 4;
    Point* stack = (Point*)malloc(max_stack_size * sizeof(Point));
    if (!stack) return;

    int top = -1;
    stack[++top] = (Point){ start_x, start_y };

    while (top >= 0) {
        Point p = stack[top--];
        int x = p.x, y = p.y;

        if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) continue;

        int cr, cg, cb;
        get_pixel(x, y, &cr, &cg, &cb);
        if (cr == target_r && cg == target_g && cb == target_b) {
            set_pixel(x, y, fill_r, fill_g, fill_b);

            if (top + 4 >= max_stack_size) continue;

            stack[++top] = (Point){ x + 1, y };
            stack[++top] = (Point){ x - 1, y };
            stack[++top] = (Point){ x, y + 1 };
            stack[++top] = (Point){ x, y - 1 };
        }
    }
    free(stack);
}

void write_png_file(char* filename) {
    FILE* fp = fopen(filename, "wb");
    if (!fp) {
        printf("Błąd: Nie można utworzyć pliku %s\n", filename);
        return;
    }

    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png) return;

    png_infop info = png_create_info_struct(png);
    if (!info) return;

    if (setjmp(png_jmpbuf(png))) return;

    png_init_io(png, fp);

    png_set_IHDR(
        png, info, WIDTH, HEIGHT,
        8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT
    );
    png_write_info(png, info);
    png_write_image(png, row_pointers);
    png_write_end(png, NULL);

    fclose(fp);
    png_destroy_write_struct(&png, &info);
}

void free_image() {
    for (int y = 0; y < HEIGHT; y++) {
        free(row_pointers[y]);
    }
    free(row_pointers);
}

int main() {
    init_image();

    draw_line(200, 200, 200, 400, 0, 0, 0);
    draw_line(200, 400, 280, 400, 0, 0, 0);
    draw_line(160, 320, 240, 280, 0, 0, 0);

    draw_line(450, 200, 350, 200, 0, 0, 0);
    draw_line(350, 200, 350, 280, 0, 0, 0);
    draw_line(350, 280, 450, 280, 0, 0, 0);
    draw_line(450, 280, 450, 360, 0, 0, 0);
    draw_line(450, 360, 350, 360, 0, 0, 0);
    draw_line(380, 180, 420, 150, 0, 0, 0);

    draw_circle(325, 275, 220, 0, 0, 0);

    flood_fill(10, 10, 173, 216, 230);
    flood_fill(325, 275, 255, 223, 186);

    write_png_file("output.png");
    free_image();

    printf("Sukces: Plik output.png został poprawnie wygenerowany!\n");
    return 0;
}