diff --git a/gfx/.gitignore b/gfx/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ba2906d0666cf726c7eaadd2cd3db615dedfdf3a --- /dev/null +++ b/gfx/.gitignore @@ -0,0 +1 @@ +main diff --git a/gfx/gfx.c b/gfx/gfx.c index 79004048bfce7a015cc4767f9d338daa27156c2f..40c7c26d68503dfddfe929a2f390e804750198ad 100644 --- a/gfx/gfx.c +++ b/gfx/gfx.c @@ -3,105 +3,254 @@ /// @date November 6, 2016 /// Helper routines to render pixels in fullscreen graphic mode. /// Uses the SDL2 library. +/// Update : Add full circle +/// @author Michaël El Kharroubi +/// @date 19 November 2021 +/// Update : Add better system to quit window +/// @author Michaël El Kharroubi +/// @date November 2024 -#include <assert.h> #include "gfx.h" +#include <assert.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_MAXIMIZED); - 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)); +struct gfx_context_t *gfx_create(char *title, uint32_t width, uint32_t height) { + if (SDL_Init(SDL_INIT_VIDEO) != 0) + goto error; + SDL_Window *window = + SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + 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; + 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; + 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; + SDL_ShowCursor(SDL_DISABLE); + gfx_clear(ctxt, COLOR_BLACK); + return ctxt; error: - return NULL; + 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; -} - -/// Get a pixel in the specified graphic context. -/// @param ctxt Graphic context where we want to get the pixel. -/// @param x X coordinate of the pixel. -/// @param y Y coordinate of the pixel. +/// @param column X coordinate of the pixel. +/// @param row Y coordinate of the pixel. /// @param color Color of the pixel. -/// @return color at position x, y. -uint32_t gfx_getpixel(struct gfx_context_t *ctxt, int x, int y) { - assert(x >= 0 && x < ctxt->width && y >= 0 && y < ctxt->height); - return ctxt->pixels[ctxt->width*y+x]; +void gfx_putpixel(struct gfx_context_t *ctxt, uint32_t column, uint32_t row, + uint32_t color) { + if (column < ctxt->width && row < ctxt->height) + ctxt->pixels[ctxt->width * row + column] = 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; + 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); + 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); + 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; + SDL_Event event; + if (SDL_PollEvent(&event)) { + if (event.type == SDL_KEYDOWN) + return event.key.keysym.sym; + } + return 0; +} + +/// Check for quit signals such as: alt-f4, ctrl+c, ctrl+d or ESC +// @return true if there is a quit signal +bool quit_signal() { + bool signal = false; + // process events + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: // signal when window "X" icon pressed + signal = true; + break; + case SDL_KEYDOWN: + if ((event.key.keysym.mod & KMOD_CTRL) != 0) { + SDL_Keycode k = event.key.keysym.sym; + signal = (k == SDLK_c) || (k == SDLK_d); // ctrl-c or ctrl-d pressed + } + break; + case SDL_KEYUP: + // escape pressed + signal = event.key.keysym.scancode == SDL_SCANCODE_ESCAPE; + break; + default: + break; + } + } + return signal; +} + +/// Wait for alt-f4, ctrl+c, ctrl+d or ESC +// Blocking call. +void wait_for_quit_signal() { + while (!quit_signal()) { + } } +/**/ +/**/ +/*/// @file gfx.c*/ +/*/// @author Florent Gluck*/ +/*/// @date November 6, 2016*/ +/*/// Helper routines to render pixels in fullscreen graphic mode.*/ +/*/// Uses the SDL2 library.*/ +/**/ +/*#include <assert.h>*/ +/*#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_MAXIMIZED);*/ +/* 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;*/ +/*}*/ +/**/ +/*/// Get a pixel in the specified graphic context.*/ +/*/// @param ctxt Graphic context where we want to get the pixel.*/ +/*/// @param x X coordinate of the pixel.*/ +/*/// @param y Y coordinate of the pixel.*/ +/*/// @param color Color of the pixel.*/ +/*/// @return color at position x, y.*/ +/*uint32_t gfx_getpixel(struct gfx_context_t *ctxt, int x, int y) {*/ +/* assert(x >= 0 && x < ctxt->width && y >= 0 && y < ctxt->height);*/ +/* return ctxt->pixels[ctxt->width*y+x];*/ +/*}*/ +/**/ +/*/// 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/gfx.h b/gfx/gfx.h index 8dabbf62946082913faa7368530d6a5bf109d648..8f34272ba404b7750391ce63219f04fd54604b13 100644 --- a/gfx/gfx.h +++ b/gfx/gfx.h @@ -1,42 +1,42 @@ #ifndef _GFX_H_ #define _GFX_H_ -#include <stdint.h> -#include <stdbool.h> #include <SDL2/SDL.h> +#include <stdbool.h> +#include <stdint.h> -#define MAKE_COLOR(r,g,b) ((uint32_t)b|((uint32_t)g<<8)|((uint32_t)r<<16)) +#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_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; + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Texture *texture; + uint32_t *pixels; + uint32_t width; + uint32_t height; }; -extern uint32_t gfx_getpixel(struct gfx_context_t *ctxt, int x, int y); -extern void gfx_putpixel(struct gfx_context_t *ctxt, int x, int y, uint32_t color); +extern void gfx_putpixel(struct gfx_context_t *ctxt, uint32_t column, + uint32_t row, 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 struct gfx_context_t *gfx_create(char *text, uint32_t width, + uint32_t height); extern void gfx_destroy(struct gfx_context_t *ctxt); extern void gfx_present(struct gfx_context_t *ctxt); extern SDL_Keycode gfx_keypressed(); +extern bool quit_signal(); +extern void wait_for_quit_signal(); #endif diff --git a/gfx/main.c b/gfx/main.c new file mode 100644 index 0000000000000000000000000000000000000000..59b871d07f14c464add90c3a7ad3d8b366e54ff5 --- /dev/null +++ b/gfx/main.c @@ -0,0 +1,58 @@ +#include "gfx.h" +#include <time.h> +#include <unistd.h> + +static void draw_rectangle(struct gfx_context_t *context, int x0, int x1, + int y0, int y1) { + for (int ix = x0; ix < x1; ++ix) { + gfx_putpixel(context, ix, y0, COLOR_WHITE); + } + for (int ix = x0; ix < x1; ++ix) { + gfx_putpixel(context, ix, y1 - 1, COLOR_WHITE); + } + for (int iy = y0; iy < y1; ++iy) { + gfx_putpixel(context, x0, iy, COLOR_WHITE); + } + for (int iy = y0; iy < y1; ++iy) { + gfx_putpixel(context, x1 - 1, iy, COLOR_WHITE); + } +} + +int main() { + int width = 240, height = 135; + struct gfx_context_t *ctxt = gfx_create("Serpent", width, height); + if (!ctxt) { + fprintf(stderr, "Graphics initialization failed!\n"); + return EXIT_FAILURE; + } + gfx_clear(ctxt, COLOR_BLACK); + draw_rectangle(ctxt, 10, 230, 10, 125); + + SDL_Keycode key = gfx_keypressed(); + + bool done = false; + while (!done) { + key = gfx_keypressed(); + + switch (key) { + case SDLK_a: + printf("a pressed\n"); + break; + case SDLK_w: + printf("w pressed\n"); + break; + case SDLK_d: + printf("d pressed\n"); + break; + case SDLK_s: + printf("s pressed\n"); + break; + default: + break; + } + gfx_present(ctxt); + done = quit_signal(); + } + gfx_destroy(ctxt); + return EXIT_SUCCESS; +}