diff --git a/draw.c b/draw.c new file mode 100644 index 0000000000000000000000000000000000000000..d4be34be4912fb5950b9103a3b1cc9bec9c6981c --- /dev/null +++ b/draw.c @@ -0,0 +1,102 @@ +/** + * @file draw.c + * @author Tanguy Cavagna (tanguy.cavagna@etu.hesge.ch) + * @brief Drawing library + * @version 0.1 + * @date 2021-07-12 + * + * @copyright Copyright (c) 2021 + * + */ + +#include "draw.h" +#include "math.h" + +/** + * @brief Bresenham's line algorithme. + * Full understanding of the algorithme, but some parts of the + * implementation still blury. + * @see https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#All_cases + * + * @param ctxt Context to draw on + * @param p0 Start point + * @param p1 End point + * @param color Stroke color + */ +void gfx_draw_line(struct gfx_context_t *ctxt, coordinates_t p0, coordinates_t p1, uint32_t color) { + int x0 = p0.column, y0 = p0.row; + int x1 = p1.column, y1 = p1.row; + + // Single pixel line + if (x0 == x1 && y0 == y1) { + gfx_putpixel(ctxt, x0, y0, color); + return; + } + + int dx = abs(x1 - x0); + int sx = x0 < x1 ? 1 : -1; // Increase if x goes left to right and decrease if right to left + int dy = -abs(y1 - y0); + int sy = y0 < y1 ? 1 : -1; // Increase if y goes up to down and decrease if down to up + + int err = dx + dy; // Error value between x and y + int e2; + + while (true) { + gfx_putpixel(ctxt, x0, y0, color); + + if (x0 == x1 && y0 == y1) break; + + e2 = 2 * err; + + if (e2 >= dy) { // e_xy + e_x > 0 + err += dy; + x0 += sx; + } + if (e2 <= dx) { // e_xy + e_y < 0 + err += dx; + y0 += sy; + } + } +} + +/** + * @brief Andres's circle algorithm + * @see https://fr.wikipedia.org/wiki/Algorithme_de_tracé_de_cercle_d%27Andres#Algorithme + * + * @param ctxt Context to draw on + * @param c Center + * @param r Radius + * @param color Stroke color + */ +void gfx_draw_circle(struct gfx_context_t *ctxt, coordinates_t c, int r, uint32_t color) { + int xc = c.column; + int yc = c.row; + int x = 0; + int y = r; + int d = r - 1; + + while (x < y) { + // Draw octants pixel + gfx_putpixel(ctxt, xc + x, yc + y, color); + gfx_putpixel(ctxt, xc + y, yc + x, color); + gfx_putpixel(ctxt, xc - x, yc + y, color); + gfx_putpixel(ctxt, xc - y, yc + x, color); + gfx_putpixel(ctxt, xc + x, yc - y, color); + gfx_putpixel(ctxt, xc + y, yc - x, color); + gfx_putpixel(ctxt, xc - x, yc - y, color); + gfx_putpixel(ctxt, xc - y, yc - x, color); + + // Rotate + if (d >= 2 * x) { + d -= (2 * x) - 1; + x += 1; + } else if (d < 2 * (r - y)) { + d += (2 * y) - 1; + y -= 1; + } else { + d += 2 * (y - x - 1); + y -= 1; + x += 1; + } + } +} \ No newline at end of file diff --git a/draw.h b/draw.h new file mode 100644 index 0000000000000000000000000000000000000000..36be2b8b7f7f442db0b54ddee68a0decdc1bea2a --- /dev/null +++ b/draw.h @@ -0,0 +1,40 @@ +/** + * @file draw.h + * @author Tanguy Cavagna (tanguy.cavagna@etu.hesge.ch) + * @brief Header of the draw file + * @version 0.1 + * @date 2021-07-12 + * + * @copyright Copyright (c) 2021 + * + */ + +#ifndef _DRAW_H_ +#define _DRAW_H_ + +#include <stdlib.h> +#include <stdio.h> +#include "utils.h" +#include "gfx/gfx.h" + +/** + * @brief Draw a line using the Bresenham's line algorithm + * + * @param ctxt Context to draw on + * @param p0 Start + * @param p1 End + * @param color Stroke color + */ +void gfx_draw_line(struct gfx_context_t *ctxt, coordinates_t p0, coordinates_t p1, uint32_t color); + +/** + * @brief Draw a circle using _______ + * + * @param ctxt Context to draw on + * @param c Center + * @param r Raidus + * @param color Stroke color + */ +void gfx_draw_circle(struct gfx_context_t *ctxt, coordinates_t c, int r, uint32_t color); + +#endif // _DRAW_H_ diff --git a/gfx.c b/gfx/gfx.c similarity index 100% rename from gfx.c rename to gfx/gfx.c diff --git a/gfx.h b/gfx/gfx.h similarity index 100% rename from gfx.h rename to gfx/gfx.h diff --git a/main.c b/main.c index 84b3c264444738a2d1896c2719169464ff0daa88..f786b12d6dc7c98088d1753a31c86c926328d424 100644 --- a/main.c +++ b/main.c @@ -1,7 +1,8 @@ #include <stdlib.h> #include <time.h> #include <math.h> -#include "gfx.h" +#include "gfx/gfx.h" +#include "draw.h" int main(void) { const int WINDOW_SIZE_X = 500; diff --git a/makefile b/makefile index a8b315dcbcc841c8088e9695fae559400d35ea48..d5000d71566c1206c2ee74098c9ff581569a33c0 100644 --- a/makefile +++ b/makefile @@ -1,39 +1,44 @@ +# see https://yuukidach.github.io/2019/08/05/makefile-learning/ # Variable setup CC = gcc -CFLAGS = -Wall -Wextra -std=c11 -g -fsanitize=leak -fsanitize=address +CFLAGS = -Wall -Wextra -std=gnu11 -g -fsanitize=address -fsanitize=leak LDFLAGS = -lm -LIBS = -lSDL2 -lm +LIBS = -lSDL2 TARGET = main BIN = bin +SUBDIR = vector RUN = ./$(BIN)/$(TARGET) # Get source and object -SOURCE = $(wildcard *.c) -OBJECT = $(patsubst %,$(BIN)/%, $(notdir $(SOURCE:.c=.o))) - -# Convert the source in object, but before all, run `$(BIN)` aka mkdir -$(BIN)/%.o: %.c | $(BIN) - $(CC) $(CFLAGS) -c $< -o $@ +SRCS = $(wildcard *.c */*.c) +OBJS = $(addprefix $(BIN)/, $(SRCS:.c=.o)) +PHONY := $(TARGET) # Create the target -$(BIN)/$(TARGET): $(OBJECT) - $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) +$(TARGET): $(OBJS) + $(CC) $(CFLAGS) -o $(BIN)/$@ $(OBJS) $(LIBS) $(LDFLAGS) $(RUN) -$(BIN): - mkdir -p $(BIN) +# Convert the source in object, but before all, run `$(BIN)` aka mkdir +$(BIN)/%.o: %.c + mkdir -p $(@D) + $(CC) $(CFLAGS) -o $@ -c $< $(LDFLAGS) +PHONY += help # Echo the source and object values help: - @echo "src: $(SOURCE)" - @echo "obj: $(OBJECT)" + @echo "src: $(SRCS)" + @echo "inc: $(INCS)" + @echo "obj: $(OBJS)" +PHONY += run # Run the program run: $(RUN) -.PHONY: clean # Specify that the clean target is not a file +PHONY += clean clean: rm -rf bin - \ No newline at end of file + +.PHONY: $(PHONY) diff --git a/vector/vector.c b/vector/vector.c new file mode 100644 index 0000000000000000000000000000000000000000..3c3b7ddeb261ecda75cb4f062f9934e6a75d8575 --- /dev/null +++ b/vector/vector.c @@ -0,0 +1,102 @@ +/*! \file Library for vector operations + All the operations are made with a Cartesian vector. If you want a Polar vector, call to_polar(). +*/ + +// To be able to use mathematical constant defined in math.h +#ifndef __USE_MISC +#define __USE_MISC +#endif + +#include <math.h> +#include <stdio.h> +#include "vector.h" + +/*! \fn vector add_vector(vector v1, vector v2) + \brief Add two vector and return the final vector + \param v1 First vector to add + \param v2 Second vector to add +*/ +vector add_vector(vector v1, vector v2) { + vector resultVector; + + double finalX = v1.x + v2.x; + double finalY = v1.y + v2.y; + + resultVector.x = finalX; + resultVector.y = finalY; + + return resultVector; +} + +/*! \fn vector sub_vector(vector v1, vector v2) + \brief Substract two vector and return the final vector + \param v1 First vector + \param v2 Vector we want to substract to the first +*/ +vector sub_vector(vector v1, vector v2) { + // First we reverse the direction of the vector we want to substract + v2.x *= -1; + v2.y *= -1; + + // Then add them as usual + return add_vector(v1, v2); +} + +/*! \fn vector mult_by_scalar(vector v1, int scalar) + \brief Multiply a vector by a scalar + \param v1 Vector to multiply + \param scalar Scalar to use for the multiplication +*/ +vector mult_by_scalar(vector v1, int scalar) { + vector resultVector = {v1.x * scalar, v1.y * scalar}; + + return resultVector; +} + +/*! \fn double norm(vector v1) + \brief Get the norm of a given vector + \param v1 Vector to multiply +*/ +double norm(vector v1) { + double vectorNorm; + + vectorNorm = sqrt(pow(v1.x, 2) + pow(v1.y, 2)); + + return vectorNorm; +} + +/*! \fn double dot_multiply(vector v1, vector v2) + \brief Multiply two vector with the dot product formula + \param v1 First vector to multiply + \param v2 Second vector to multiply +*/ +double dot_multiply(vector v1, vector v2) { + return (v1.x * v2.x) + (v1.y * v2.y); +} + +/*! \fn polarVector to_polar(vector v1) + \brief Convert a Cartesian vector to a Polar vector + \param v1 Cartesian vector +*/ +polarVector to_polar(vector v1) { + polarVector p_vector; + + p_vector.f = norm(v1); + p_vector.a = atan(v1.y / v1.x) * (180.0 / M_PI); // The atan return a radian angle. Use `* 180 / M_PI` to convert it in degree + + return p_vector; +} + +/*! \fn vector to_cartesian(polarVector v1) + \brief Convert a Polar vector to a Cartesian vector + \param v1 Polar vector +*/ +vector to_cartesian(polarVector v1) { + vector c_vector; + + // The cos work with radian angle. Convert degree to radiant inside the cos function to have the correct force + c_vector.x = v1.f * cos(v1.a * (M_PI / 180.0)); + c_vector.y = v1.f * sin(v1.a * (M_PI / 180.0)); + + return c_vector; +} diff --git a/vector/vector.h b/vector/vector.h new file mode 100644 index 0000000000000000000000000000000000000000..4d40c6d12209a1051413d8bfcc0dce77603bb6ee --- /dev/null +++ b/vector/vector.h @@ -0,0 +1,34 @@ +/*! \file Abstract of the vector-lib file + Contains the skeleton of the vector-lib file. All the functions and structs are defined here. +*/ + +#ifndef VECTOR_H_ /* Header guard. Prevent the error of double inclusion inside a program. See : https://fr.wikipedia.org/wiki/Include_guard */ +#define VECTOR_H_ + +/** + * @brief Cartesian vector + */ +typedef struct { + double x; + double y; +} vector; + +/** + * @brief Polar vector used for representation only + */ +typedef struct { + double f; /* Force of the vector */ + double a; /* Angle of the vector */ +} polarVector; + +vector add_vector(vector v1, vector v2); /* Add a vector to another and return the result as a vector */ +vector sub_vector(vector v1, vector v2); /* Substract a vector to another vector and return the result as a vector */ +vector mult_by_scalar(vector v1, int scalar); /* Multiply a vector by a scalar */ +double dot_multiply(vector v1, vector v2); /* Multiply two vectors with the dot product formula */ +double norm(vector v1); /* Get the norm of a given vector */ +polarVector to_polar(vector v1); /* Convert a Cartesian vector to a Polar vector */ +vector to_cartesian(polarVector v1); /* Convert a Polar vector to a Cartesian vector */ + +/* For the moment, the cross product hasn't be inplemented because it only work with vectors on 3 dimentionals plan. */ + +#endif /* VECTOR_H_ */