diff --git a/experiment/newton/.gitignore b/experiment/newton/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ba31bf0a27bc5a896a8bd1351e44ba31e8b69ac7 --- /dev/null +++ b/experiment/newton/.gitignore @@ -0,0 +1,2 @@ +*.o +newton \ No newline at end of file diff --git a/experiment/newton/Makefile b/experiment/newton/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d43118c11726a0697cbb3bc4a8c9a6e399baed30 --- /dev/null +++ b/experiment/newton/Makefile @@ -0,0 +1,13 @@ +C_GCC=gcc +C_CLANG=clang +CFLAGS=-Wall -Wextra -std=gnu11 -g -fsanitize=leak -fsanitize=undefined -fsanitize=address +LIBS=-lSDL2 -lm + + +all: newton + +newton: newton.o gfx.o + $(C_GCC) $(CFLAGS) $^ -o $@ $(LIBS) + +clean: + rm -f *.o gfx_example newton diff --git a/experiment/newton/gfx.c b/experiment/newton/gfx.c new file mode 100644 index 0000000000000000000000000000000000000000..aca1933358386e2b4c3e2c0dd05bcc20f06373c1 --- /dev/null +++ b/experiment/newton/gfx.c @@ -0,0 +1,95 @@ +/// @file gfx.c +/// @author Florent Gluck +/// @date November 6, 2016 +/// Helper routines to render pixels in fullscreen graphic mode. +/// Uses the SDL2 library. + +#include "gfx.h" + +/// Create a fullscreen graphic window. +/// @param title Title of the window. +/// @param width Width of the window in pixels. +/// @param height Height of the window in pixels. +/// @return a pointer to the graphic context or NULL if it failed. +struct gfx_context_t* gfx_create(char *title, uint width, uint height) { + if (SDL_Init(SDL_INIT_VIDEO) != 0) goto error; + SDL_Window *window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_RESIZABLE); + SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0); + SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, width, height); + uint32_t *pixels = malloc(width*height*sizeof(uint32_t)); + struct gfx_context_t *ctxt = malloc(sizeof(struct gfx_context_t)); + + if (!window || !renderer || !texture || !pixels || !ctxt) goto error; + + ctxt->renderer = renderer; + ctxt->texture = texture; + ctxt->window = window; + ctxt->width = width; + ctxt->height = height; + ctxt->pixels = pixels; + + SDL_ShowCursor(SDL_DISABLE); + gfx_clear(ctxt, COLOR_BLACK); + return ctxt; + +error: + return NULL; +} + +/// Draw a pixel in the specified graphic context. +/// @param ctxt Graphic context where the pixel is to be drawn. +/// @param x X coordinate of the pixel. +/// @param y Y coordinate of the pixel. +/// @param color Color of the pixel. +void gfx_putpixel(struct gfx_context_t *ctxt, int x, int y, uint32_t color) { + if (x < ctxt->width && y < ctxt->height) + ctxt->pixels[ctxt->width*y+x] = color; +} + +/// Clear the specified graphic context. +/// @param ctxt Graphic context to clear. +/// @param color Color to use. +void gfx_clear(struct gfx_context_t *ctxt, uint32_t color) { + int n = ctxt->width*ctxt->height; + while (n) + ctxt->pixels[--n] = color; +} + +/// Display the graphic context. +/// @param ctxt Graphic context to clear. +void gfx_present(struct gfx_context_t *ctxt) { + SDL_UpdateTexture(ctxt->texture, NULL, ctxt->pixels, ctxt->width*sizeof(uint32_t)); + SDL_RenderCopy(ctxt->renderer, ctxt->texture, NULL, NULL); + SDL_RenderPresent(ctxt->renderer); +} + +/// Destroy a graphic window. +/// @param ctxt Graphic context of the window to close. +void gfx_destroy(struct gfx_context_t *ctxt) { + SDL_ShowCursor(SDL_ENABLE); + SDL_DestroyTexture(ctxt->texture); + SDL_DestroyRenderer(ctxt->renderer); + SDL_DestroyWindow(ctxt->window); + free(ctxt->pixels); + ctxt->texture = NULL; + ctxt->renderer = NULL; + ctxt->window = NULL; + ctxt->pixels = NULL; + SDL_Quit(); + free(ctxt); +} + +/// If a key was pressed, returns its key code (non blocking call). +/// List of key codes: https://wiki.libsdl.org/SDL_Keycode +/// @return the key that was pressed or 0 if none was pressed. +SDL_Keycode gfx_keypressed() { + SDL_Event event; + if (SDL_PollEvent(&event)) { + if (event.type == SDL_KEYDOWN) + return event.key.keysym.sym; + } + return 0; +} + diff --git a/experiment/newton/gfx.h b/experiment/newton/gfx.h new file mode 100644 index 0000000000000000000000000000000000000000..72bbdc3906e7aac7eef073259807379c6a27d4a8 --- /dev/null +++ b/experiment/newton/gfx.h @@ -0,0 +1,41 @@ +#ifndef _GFX_H_ +#define _GFX_H_ + +#include <stdint.h> +#include <stdbool.h> +#include <SDL2/SDL.h> + +#define MAKE_COLOR(r,g,b) ((uint32_t)b|((uint32_t)g<<8)|((uint32_t)r<<16)) + +#define COLOR_GET_B(color) (color & 0xff) +#define COLOR_GET_G(color) ((color >> 8) & 0xff) +#define COLOR_GET_R(color) ((color >> 16) & 0xff) + +#define COLOR_BLACK 0x00000000 +#define COLOR_RED 0x00FF0000 +#define COLOR_GREEN 0x0000FF00 +#define COLOR_BLUE 0x000000FF +#define COLOR_WHITE 0x00FFFFFF +#define COLOR_YELLOW 0x00FFFF00 + +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned char uchar; + +struct gfx_context_t { + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Texture *texture; + uint32_t *pixels; + int width; + int height; +}; + +extern void gfx_putpixel(struct gfx_context_t *ctxt, int x, int y, uint32_t color); +extern void gfx_clear(struct gfx_context_t *ctxt, uint32_t color); +extern struct gfx_context_t* gfx_create(char *text, uint width, uint height); +extern void gfx_destroy(struct gfx_context_t *ctxt); +extern void gfx_present(struct gfx_context_t *ctxt); +extern SDL_Keycode gfx_keypressed(); + +#endif diff --git a/experiment/newton/newton.c b/experiment/newton/newton.c new file mode 100644 index 0000000000000000000000000000000000000000..777b61f4f72c0a9df5686fde1c3f55cc22a69ac6 --- /dev/null +++ b/experiment/newton/newton.c @@ -0,0 +1,95 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <math.h> +#include <time.h> +#include "gfx.h" + +#define GRAV 9.8 +#define MASS 0.1 + +/// @param context graphical context to use. +static void render(struct gfx_context_t *context, double pos) +{ + int x = (int)(pos * 1000); + int y = context->height / 2; + uint32_t color = COLOR_WHITE; // 8-bit per color channel + for (int i = 0; i < 5; ++i) + { + for (int j = 0; j < 5; ++j) + { + gfx_putpixel(context, x + i, y + j, color); + } + } + gfx_present(context); +} + +double verlet(double p, double p_1, double a, double dt) +{ + double pos = 2.0 * p - p_1 + dt * dt * a; + return pos; +} + +int main(int argc, char **argv) +{ + double force = 0.0; + if (argc == 2) + { + force = atof(argv[1]); + } + else + { + printf("Error: missing force parameter.\n\ + Normal use is: ./newton <force>\n\ + Example: ./newton 1.0\n"); + return EXIT_FAILURE; + } + int width = 1900, height = 50; + struct gfx_context_t *ctxt = gfx_create("Newton's Law", width, height); + if (!ctxt) + { + fprintf(stderr, "Graphics initialization failed!\n"); + return EXIT_FAILURE; + } + + double p = 0.0; + double p_1 = 0.0; + double p_2 = 0.0; + double dt = 0.02; + + struct timespec time = {0, dt * 1000000000}; + + int num = sqrt(width / 1000.0 / 0.5 / (force / MASS)) / dt; + printf("%d\n", num); + + gfx_clear(ctxt, COLOR_BLACK); + + double avg_acc = 0.0; + for (int i = 0; i < num; ++i) + { + double vel = (p - p_1) / dt; + double vel_1 = (p_1 - p_2) / dt; + double acc = (vel - vel_1) / dt; + if (i > 0) + { + printf("t = %f, pos = %f, vel = %f, acc = %f\n", i * dt, p, vel, acc); + avg_acc += acc; + } + render(ctxt, p); + nanosleep(&time, NULL); + double p_tmp = p; + double noise = ((rand() % 1000) - 500) / 100000000.0; + p = verlet(p, p_1, force / MASS, dt) + noise; // add some noise of the order of + p_2 = p_1; + p_1 = p_tmp; + } + printf("Simulation ended: avg acceleration = %f\n", avg_acc / (num - 1)); + + while (gfx_keypressed() != SDLK_ESCAPE) + { + } + + gfx_destroy(ctxt); + + return EXIT_SUCCESS; +} \ No newline at end of file