/* * screen.c -- Abstracción sobre SDL para la entrada y salida gráfica. * Copyright (C) 2018 Juan Marín Noguera * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "error.h" #include "screen.h" #define TEXT_X 3 #define TEXT_Y 460 #define TEXT_FILE "56929.bmp" #define TEXT_H 8 #define TEXT_W 8 #define TEXT_PER_ROW 16 struct Picture { SDL_Surface *s; SDL_Surface *f; }; struct Screen { SDL_Window *window; SDL_Renderer *renderer; SDL_Surface *surface; }; Picture screen_text_bmp = NULL; static void screen_init() { if (!SDL_WasInit(SDL_INIT_VIDEO) && SDL_Init(SDL_INIT_VIDEO) < 0) error_sdl_exit(); } Screen screen_create(const char *caption, int w, int h) { Screen scr; if (w <= 0 || h <= 0) error_exit(ERR_OUT_OF_RANGE); scr = malloc(sizeof(struct Screen)); if (scr == NULL) error_libc_exit(); screen_init(); scr->window = SDL_CreateWindow( caption, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, 0); if (scr->window == NULL) error_sdl_exit(); scr->surface = SDL_GetWindowSurface(scr->window); if (scr->surface == NULL) error_sdl_exit(); scr->renderer = SDL_CreateSoftwareRenderer(scr->surface); if (scr->renderer == NULL) error_sdl_exit(); if (SDL_SetRenderDrawBlendMode(scr->renderer, SDL_BLENDMODE_BLEND) == -1) error_sdl_exit(); return scr; } void screen_free(Screen scr) { SDL_DestroyWindow(scr->window); SDL_DestroyRenderer(scr->renderer); } void screen_end() { if (screen_text_bmp != NULL) screen_free_picture(screen_text_bmp); SDL_Quit(); } int screen_width(Screen scr) { return scr->surface->w; } int screen_height(Screen scr) { return scr->surface->h; } void screen_wait(int ms) { SDL_Delay(ms); } void screen_update(Screen scr) { if (SDL_UpdateWindowSurface(scr->window) == -1) error_sdl_exit(); } int screen_get_keyboard_event(SDL_Scancode *sc) { SDL_Event event; while (SDL_PollEvent(&event)) switch (event.type) { case SDL_KEYDOWN: if (event.key.repeat) break; if (sc != NULL) *sc = event.key.keysym.scancode; return SCREEN_KEYDOWN; case SDL_KEYUP: if (event.key.repeat) break; if (sc != NULL) *sc = event.key.keysym.scancode; return SCREEN_KEYUP; case SDL_QUIT: exit(0); } return 0; } int screen_key_pressed(SDL_Scancode scancode) { int len; const uint8_t *state; SDL_PumpEvents(); state = SDL_GetKeyboardState(&len); if (len <= scancode || scancode < 0) error_exit(ERR_INVALID_SCANCODE); return state[scancode]; } void screen_fill(Screen scr, int r, int g, int b, int a) { if (SDL_SetRenderDrawColor(scr->renderer, r, g, b, a) == -1) error_sdl_exit(); if (SDL_RenderClear(scr->renderer) == -1) error_sdl_exit(); } void screen_place(Screen scr, Picture pict, int x, int y, int sx, int sy, int w, int h, int flipped) { SDL_Rect src, dst; int total_width = screen_width(scr), total_height = screen_height(scr); SDL_Surface *surface; if (flipped) { sx = pict->f->w - sx - w; surface = pict->f; } else { surface = pict->s; } if (x > total_width || y > total_height || x + w <= 0 || y + h <= 0) return; // Nothing to do here src.x = x < 0 ? sx - x : sx; src.y = y < 0 ? sy - y : sy; src.w = x < 0 ? w + x : x + w > total_width ? total_width - x : w; src.h = y < 0 ? h + y : y + h > total_height ? total_height - y: h; dst.x = x < 0 ? 0 : x; dst.y = y < 0 ? 0 : y; dst.w = src.w; dst.h = src.h; if (SDL_BlitSurface(surface, &src, scr->surface, &dst) == -1) error_sdl_exit(); } Picture screen_get_picture(const char *file) { SDL_Surface *raw, *converted, *flipped; SDL_PixelFormat *pxf; Picture pict = malloc(sizeof(struct Picture)); if (pict == NULL) error_libc_exit(); raw = SDL_LoadBMP(file); if (raw == NULL) error_sdl_exit(); pxf = SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888); if (pxf == NULL) error_sdl_exit(); converted = SDL_ConvertSurface(raw, pxf, 0); if (converted == NULL) error_sdl_exit(); SDL_FreeFormat(pxf); SDL_FreeSurface(raw); flipped = SDL_CreateRGBSurface(0, raw->w, raw->h, 32, pxf->Rmask, pxf->Gmask, pxf->Bmask, pxf->Amask); if (flipped == NULL) error_sdl_exit(); for (int y = 0; y < raw->h; y++) for (int x = 0; x < raw->w; x++) ((int*)flipped->pixels)[(y + 1) * raw->w - x - 1] = ((int*)converted->pixels)[y * raw->w + x]; pict->s = converted; pict->f = flipped; return pict; } void screen_free_picture(Picture pict) { SDL_FreeSurface(pict->f); SDL_FreeSurface(pict->s); free(pict); } void screen_print_char(Screen scr, int x, int y, char c) { int i; if (c >= '0' && c <= '9') i = c - '0'; else if (c >= 'a' && c <= 'z') i = c - 'a' + 10; else if (c >= 'A' && c <= 'Z') i = c - 'A' + 10; else if (c == '.') i = 36; // This is the copyright mark. else if (c == '-') i = 40; else if (c == '*') i = 41; else if (c == '!') i = 43; else return; screen_place(scr, screen_text_bmp, x, y, TEXT_X + (i % TEXT_PER_ROW) * TEXT_W, TEXT_Y + (i / TEXT_PER_ROW) * TEXT_H, TEXT_W, TEXT_H, 0); } void screen_text_print(Screen scr, int x, int y, int w, const char *str) { if (screen_text_bmp == NULL) screen_text_bmp = screen_get_picture(TEXT_FILE); for (int i = 0; str[i] != '\0'; i++) screen_print_char( scr, x + (w != 0 ? i % w : i) * TEXT_W, y + (w != 0 ? i / w : 0) * TEXT_H, str[i]); } void screen_text_centered(Screen scr, int x, int y, const char *str) { int len = strlen(str); screen_text_print(scr, x - len * TEXT_W / 2, y, 0, str); }