diff --git a/.gitignore b/.gitignore index 2472996ec18de16c80b4f7ea72977c974ebdc293..b44090db6b17f4e2313ca1676d219c400ae6eafa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.o *.gch pgm_exe -.vscode \ No newline at end of file +.vscode +*.pgm \ No newline at end of file diff --git a/Makefile b/Makefile index 9c6e5e80f9f5c3808cf1ceaeff29363f81167879..8c30d47ec0db5d007698b7e2ea5845c9f49abc07 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ SANITIZERS = -g -fsanitize=address -fsanitize=leak -fsanitize=undefined LIBS = -lSDL2 -pgm_exe: pgm_main.o pgm.o matrix.o +pgm_exe: pgm_main.o pgm.o matrix.o gfx.o $(CC) $^ -o $@ $(LINKS) $(SANITIZERS) $(LIBS) @@ -19,6 +19,9 @@ pgm.o: pgm.c pgm.h matrix.o: matrix.c matrix.h $(CC) $^ -c $< +gfx.o: gfx.c gfx.h + $(CC) $^ -c $< + clean: rm -f *.o rm -f *.gch diff --git a/convolution.pgm b/convolution.pgm index a6f66718bbf33e5273df8afbbfac43e580a1dcb3..c550c050430ef8b35279d3926248ca710bda41fa 100644 Binary files a/convolution.pgm and b/convolution.pgm differ diff --git a/gfx.c b/gfx.c new file mode 100644 index 0000000000000000000000000000000000000000..aca1933358386e2b4c3e2c0dd05bcc20f06373c1 --- /dev/null +++ b/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/gfx.h b/gfx.h new file mode 100644 index 0000000000000000000000000000000000000000..72bbdc3906e7aac7eef073259807379c6a27d4a8 --- /dev/null +++ b/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/pgm.c b/pgm.c index 4373a15b06b364b4ca290524744e4d5ba95afa71..a41c016dc520d8e5e9386c4a8f2321dc2fc7ad3c 100644 --- a/pgm.c +++ b/pgm.c @@ -207,4 +207,23 @@ pgm_error pmg_conv(pgm *conv, const pgm *const orig, const matrix *const kernel) } } return success; +} + +pgm_error demo(const pgm *const img){ + int width = img->pixels.l, height = img->pixels.c; + struct gfx_context_t *ctxt = gfx_create("Example", width, height); + + + + while (gfx_keypressed() != 27/*ESC btn code*/) { + for (int i = 0; i < img->pixels.l; i++) { + for (int j = 0; j < img->pixels.c; j++) { + gfx_putpixel(ctxt, j, i, MAKE_COLOR(img->pixels.data[i][j], img->pixels.data[i][j], img->pixels.data[i][j])); + } + } + gfx_present(ctxt); + } + + gfx_destroy(ctxt); + return success; } \ No newline at end of file diff --git a/pgm.h b/pgm.h index 2494eb1ecfa74cea266699d93b43029e2c560de6..eadd88ac8655922b8379e136ae455128822a680a 100644 --- a/pgm.h +++ b/pgm.h @@ -5,6 +5,7 @@ #include <stdlib.h> #include <stdint.h> #include "matrix.h" +#include "gfx.h" typedef struct _pgm{ int32_t max; diff --git a/pgm_main.c b/pgm_main.c index ca1eb21d2d2a1fb7d95f2143ebbb8309ff7fd04e..6182af2c0c194564fbde353a1af6a596c84b0917 100644 --- a/pgm_main.c +++ b/pgm_main.c @@ -12,15 +12,14 @@ int main(){ pgm pgmWithZeros; pgm convolution; int conv[9] = { - 0,-1,0, - -1,4,-1, - 0,-1,0 + 1,2,1, + 2,4,2, + 1,2,1 }; matrix convKernel; matrix_init_from_array(&convKernel, 3, 3, conv, 9); - printf("%d", pgm_read_from_file(&a, "mandrill.pgm")); //printf("%d", pgm_write_to_file(&a, "newf.pgm")); printf("%d", pgm_negative(&neg, &a)); @@ -46,6 +45,7 @@ int main(){ printf("%d", pmg_conv(&convolution, &pgmWithZeros, &convKernel)); printf("%d", pgm_write_to_file(&convolution, "convolution.pgm")); + demo(&a); matrix_destroy(&a.pixels); matrix_destroy(&neg.pixels);