// The OS/K Team licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #include #ifndef _LARGE_SCREEN # define CONSOLE_WIDTH 80 # define CONSOLE_HEIGHT 25 # define CONSOLE_FONT_SIZE 16 #else # define CONSOLE_WIDTH 160 # define CONSOLE_HEIGHT 50 # define CONSOLE_FONT_SIZE 32 #endif #define SCREEN_WIDTH (9 * CONSOLE_WIDTH) #define SCREEN_HEIGHT (16 * CONSOLE_HEIGHT) SDL_Window *scr_win = NULL; SDL_Renderer *scr_rend = NULL; TTF_Font *scr_font = NULL; SDL_Color scr_text_color = { 255, 255, 255, 0 }; char scr_lines[CONSOLE_HEIGHT][CONSOLE_WIDTH+1] = { 0 }; SDL_Texture *scr_texts[CONSOLE_HEIGHT] = { 0 }; SDL_Rect *scr_rects[CONSOLE_HEIGHT] = { 0 }; //----------------------------------------------------------------------------// void console_init(ctx_t *ctx) { if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0) { logerr("Couldn't initialize SDL: %s", SDL_GetError()); die(-1); } SDL_CreateWindowAndRenderer(SCREEN_WIDTH, SCREEN_HEIGHT, 0, &scr_win, &scr_rend); SDL_SetRenderDrawColor(scr_rend, 20, 20, 20, 0); if (scr_win == NULL || scr_rend == NULL) { logerr("Couldn't create SDL screen window/renderer: %s", SDL_GetError()); die(-1); } TTF_Init(); scr_font = TTF_OpenFont ("fs/console_font.ttf", CONSOLE_FONT_SIZE); if (scr_font == NULL) { logerr("Couldn't open the FreeMono font\n"); die(-1); } size_t y; for (y = 0; y < CONSOLE_HEIGHT; y++) { memset(scr_lines[y], ' ', CONSOLE_WIDTH); scr_lines[y][CONSOLE_WIDTH] = 0; } SDL_RenderClear(scr_rend); SDL_RenderPresent(scr_rend); } //----------------------------------------------------------------------------// void console_exit(ctx_t *ctx) { size_t y; for (y = 0; y < CONSOLE_HEIGHT; y++) if (scr_texts[y] != NULL) { if (scr_rects[y]) free(scr_rects[y]); SDL_DestroyTexture(scr_texts[y]); } if (scr_rend) SDL_DestroyRenderer(scr_rend); if (scr_win) SDL_DestroyWindow(scr_win); TTF_Quit(); SDL_Quit(); } //----------------------------------------------------------------------------// void console_render(ctx_t *ctx) { size_t y; SDL_RenderClear(scr_rend); for (y = 0; y < CONSOLE_HEIGHT; y++) if (scr_texts[y] != NULL && scr_rects[y] != NULL) SDL_RenderCopy(scr_rend, scr_texts[y], NULL, scr_rects[y]); SDL_RenderPresent(scr_rend); } //----------------------------------------------------------------------------// void console_update(ctx_t *ctx) { SDL_Event evt; if (__builtin_expect(SDL_PollEvent(&evt) == 1, 0)) { switch (evt.type) { case SDL_QUIT: die(0); break; case SDL_KEYDOWN: console_handle_input(ctx, evt.key.keysym.sym); break; } } } //----------------------------------------------------------------------------// void console_putat(ctx_t *ctx, char ch, int x, int y) { SDL_Surface *surf; //trace("putat: %c %d %d\n", ch, x, y); if (y >= CONSOLE_HEIGHT || x >= CONSOLE_WIDTH) { logerr("console_putat: position out of range (%d,%d)", x, y); return; } scr_lines[y][x] = ch; surf = TTF_RenderText_Solid(scr_font, scr_lines[y], scr_text_color); if (!surf) { logerr("console_putat: couldn't render TTF font: " "(%d,%d) '%c'\nError: '%s'\n", x, y, ch, SDL_GetError()); die(-1); } if (scr_texts[y]) { if (scr_rects[y]) { free(scr_rects[y]); scr_rects[y] = NULL; } SDL_DestroyTexture(scr_texts[y]); } scr_texts[y] = SDL_CreateTextureFromSurface(scr_rend, surf); scr_rects[y] = malloc(sizeof(SDL_Rect)); if (scr_texts[y] == NULL) { logerr("console_putat: couldn't create texture from surface: " "(%d,%d) '%c'\nError: '%s'\n", x, y, ch, SDL_GetError()); SDL_FreeSurface(surf); die(-1); } if (scr_rects[y] == NULL) { logerr("console_putat: not enough memory\n"); SDL_FreeSurface(surf); SDL_DestroyTexture(scr_texts[y]); die(-1); } scr_rects[y]->x = 0; scr_rects[y]->y = y * surf->h; scr_rects[y]->w = surf->w; scr_rects[y]->h = surf->h; SDL_FreeSurface(surf); console_render(ctx); } int csn_x = 0; int csn_y = 0; void console_putc(ctx_t *ctx, char ch) { size_t y; switch (ch) { case '\n': csn_x = CONSOLE_WIDTH; break; case '\r': csn_x = 0; return; case '\b': if (csn_x == 0) return; csn_x--; console_putat(ctx, ' ', csn_x, csn_y); break; default: console_putat(ctx, ch, csn_x, csn_y); csn_x++; break; } if (csn_x == CONSOLE_WIDTH) { csn_x = 0; csn_y++; } if (csn_y == CONSOLE_HEIGHT) { csn_y--; memmove(scr_lines, &scr_lines[1], (CONSOLE_HEIGHT - 1) * CONSOLE_WIDTH); memset(&scr_lines[CONSOLE_HEIGHT-1], ' ', CONSOLE_WIDTH); scr_lines[CONSOLE_HEIGHT-1][CONSOLE_WIDTH] = 0; if (scr_texts[0] != NULL) { SDL_DestroyTexture(scr_texts[0]); scr_texts[0] = NULL; } memmove(scr_texts, &scr_texts[1], (CONSOLE_HEIGHT - 1) * sizeof(SDL_Texture *)); scr_texts[CONSOLE_HEIGHT-1] = NULL; if (scr_rects[0] != NULL) { free(scr_rects[0]); scr_rects[0] = NULL; } memmove(scr_rects, &scr_rects[1], (CONSOLE_HEIGHT - 1) * sizeof(SDL_Rect *)); scr_rects[CONSOLE_HEIGHT-1] = NULL; for (y = 0; y < CONSOLE_HEIGHT-1; y++) if (scr_rects[y] != NULL) { scr_rects[y]->y -= 16; // surf->h } console_render(ctx); } } //----------------------------------------------------------------------------//