Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bresenham's Integer line algorithm #3

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 111 additions & 59 deletions olive.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,31 @@
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>

typedef int Errno;

#define return_defer(value) do { result = (value); goto defer; } while (0)
#define OLIVEC_SWAP(T, a, b) do { T t = a; a = b; b = t; } while (0)
#define return_defer(value) \
do \
{ \
result = (value); \
goto defer; \
} while (0)
#define OLIVEC_SWAP(T, a, b) \
do \
{ \
T t = a; \
a = b; \
b = t; \
} while (0)
#define OLIVEC_SIGN(T, x) ((T)((x) > 0) - (T)((x) < 0))
#define OLIVEC_ABS(T, x) (OLIVEC_SIGN(T, x)*(x))
#define OLIVEC_ABS(T, x) (OLIVEC_SIGN(T, x) * (x))

void olivec_fill(uint32_t *pixels, size_t width, size_t height, uint32_t color)
{
for (size_t i = 0; i < width*height; ++i) {
for (size_t i = 0; i < width * height; ++i)
{
pixels[i] = color;
}
}
Expand All @@ -26,25 +40,30 @@ Errno olivec_save_to_ppm_file(uint32_t *pixels, size_t width, size_t height, con

{
f = fopen(file_path, "wb");
if (f == NULL) return_defer(errno);
if (f == NULL)
return_defer(errno);

fprintf(f, "P6\n%zu %zu 255\n", width, height);
if (ferror(f)) return_defer(errno);
if (ferror(f))
return_defer(errno);

for (size_t i = 0; i < width*height; ++i) {
for (size_t i = 0; i < width * height; ++i)
{
uint32_t pixel = pixels[i];
uint8_t bytes[3] = {
(pixel>>(8*0))&0xFF,
(pixel>>(8*1))&0xFF,
(pixel>>(8*2))&0xFF,
(pixel >> (8 * 0)) & 0xFF,
(pixel >> (8 * 1)) & 0xFF,
(pixel >> (8 * 2)) & 0xFF,
};
fwrite(bytes, sizeof(bytes), 1, f);
if (ferror(f)) return_defer(errno);
if (ferror(f))
return_defer(errno);
}
}

defer:
if (f) fclose(f);
if (f)
fclose(f);
return result;
}

Expand All @@ -56,17 +75,23 @@ void olivec_fill_rect(uint32_t *pixels, size_t pixels_width, size_t pixels_heigh
int x1, int y1, int w, int h,
uint32_t color)
{
int x2 = x1 + OLIVEC_SIGN(int, w)*(OLIVEC_ABS(int, w) - 1);
if (x1 > x2) OLIVEC_SWAP(int, x1, x2);
int y2 = y1 + OLIVEC_SIGN(int, h)*(OLIVEC_ABS(int, h) - 1);
if (y1 > y2) OLIVEC_SWAP(int, y1, y2);

for (int y = y1; y <= y2; ++y) {
int x2 = x1 + OLIVEC_SIGN(int, w) * (OLIVEC_ABS(int, w) - 1);
if (x1 > x2)
OLIVEC_SWAP(int, x1, x2);
int y2 = y1 + OLIVEC_SIGN(int, h) * (OLIVEC_ABS(int, h) - 1);
if (y1 > y2)
OLIVEC_SWAP(int, y1, y2);

for (int y = y1; y <= y2; ++y)
{
// TODO: move boundary checks out of the loops in olivec_fill_rect
if (0 <= y && y < (int) pixels_height) {
for (int x = x1; x <= x2; ++x) {
if (0 <= x && x < (int) pixels_width) {
pixels[y*pixels_width + x] = color;
if (0 <= y && y < (int)pixels_height)
{
for (int x = x1; x <= x2; ++x)
{
if (0 <= x && x < (int)pixels_width)
{
pixels[y * pixels_width + x] = color;
}
}
}
Expand All @@ -81,66 +106,93 @@ void olivec_fill_circle(uint32_t *pixels, size_t pixels_width, size_t pixels_hei
int cx, int cy, int r,
uint32_t color)
{
if (r == 0) return;
if (r == 0)
return;

int x1 = cx - r;
int x2 = cx + r;
if (x1 > x2) OLIVEC_SWAP(int, x1, x2);
if (x1 > x2)
OLIVEC_SWAP(int, x1, x2);

int y1 = cy - r;
int y2 = cy + r;
if (y1 > y2) OLIVEC_SWAP(int, y1, y2);
if (y1 > y2)
OLIVEC_SWAP(int, y1, y2);

for (int y = y1; y <= y2; ++y) {
for (int y = y1; y <= y2; ++y)
{
// TODO: move boundary checks out of the loops in olivec_fill_circle
if (0 <= y && y < (int) pixels_height) {
for (int x = x1; x <= x2; ++x) {
if (0 <= x && x < (int) pixels_width) {
if (0 <= y && y < (int)pixels_height)
{
for (int x = x1; x <= x2; ++x)
{
if (0 <= x && x < (int)pixels_width)
{
int dx = x - cx;
int dy = y - cy;
if (dx*dx + dy*dy <= r*r) {
pixels[y*pixels_width + x] = color;
if (dx * dx + dy * dy <= r * r)
{
pixels[y * pixels_width + x] = color;
}
}
}
}
}
}

void olivec_draw_pixel(uint32_t *pixels, size_t pixels_width, size_t pixels_height, int x, int y, uint32_t color)
{
if (x < 0 || x >= (int)pixels_width || y < 0 || y >= (int)pixels_height)
return;

pixels[y * pixels_width + x] = color;
}

// TODO: lines with different thicness
void olivec_draw_line(uint32_t *pixels, size_t pixels_width, size_t pixels_height,
int x1, int y1, int x2, int y2,
uint32_t color)
{
// TODO: fix the olivec_draw_line stairs
bool steep = abs(y2 - y1) > abs(x2 - x1);

if (steep)
{
OLIVEC_SWAP(int, x1, y1);
OLIVEC_SWAP(int, x2, y2);
}

if (x1 > x2)
{
OLIVEC_SWAP(int, x1, x2);
OLIVEC_SWAP(int, y1, y2);
}

int deltay;
if (y1 > y2)
deltay = -1;
else
deltay = 1;

int dx = x2 - x1;
int dy = y2 - y1;

if (dx != 0) {
int c = y1 - dy*x1/dx;

if (x1 > x2) OLIVEC_SWAP(int, x1, x2);
for (int x = x1; x <= x2; ++x) {
if (0 <= x && x < (int) pixels_width) {
int sy1 = dy*x/dx + c;
int sy2 = dy*(x + 1)/dx + c;
if (sy1 > sy2) OLIVEC_SWAP(int, sy1, sy2);
for (int y = sy1; y <= sy2; ++y) {
if (0 <= y && y < (int) pixels_height) {
pixels[y*pixels_width + x] = color;
}
}
}
}
} else {
int x = x1;
if (0 <= x && x < (int) pixels_width) {
if (y1 > y2) OLIVEC_SWAP(int, y1, y2);
for (int y = y1; y <= y2; ++y) {
if (0 <= y && y < (int) pixels_height) {
pixels[y*pixels_width + x] = color;
}
}
int dy = abs(y2 - y1);
int y = y1;
int error = 0;

for (int x = x1; x < x2; x++)
{
if (x < 0 || x >= (int)pixels_width)
continue;

if (steep)
olivec_draw_pixel(pixels, pixels_width, pixels_height, y, x, color);
else
olivec_draw_pixel(pixels, pixels_width, pixels_height, x, y, color);

error += dy;
if (2 * error >= dx)
{
y = y + deltay;
error -= dx;
}
}
}
Expand Down