// ----------------------------------------------------------------------------- // https://dataswamp.org/~incal/emacs-init/draw/draw_thread.c // ----------------------------------------------------------------------------- // Note: This file has nothing to do with threads anymore! #include "draw_thread.h" #include "new.h" #include #include #include #include #include #include // ----------------------------------------------------------------------------- static SDL_Window* win = NULL; static SDL_Renderer* rnd = NULL; static TTF_Font* fnt = NULL; // ----------------------------------------------------------------------------- char* my_strdup(const char* s) { size_t len = strlen(s) + 1; char* cpy = malloc(len); if (cpy) { memcpy(cpy, s, len); } return cpy; } /* ----------------------------------------------------------------------------- */ emacs_value draw_init (emacs_env* env, ptrdiff_t nargs, emacs_value* args, void* data) { if (win || rnd || fnt) { draw_quit(env, nargs, args, data); if (win || rnd || fnt) { printf("[draw_init] error\n"); exit(EXIT_FAILURE); } } SDL_Init(SDL_INIT_EVERYTHING); TTF_Init(); win = new_window("SDL2 draw thread", 800, 600); rnd = new_renderer(win); fnt = new_font("/usr/share/fonts/truetype/ocr-a/OCRA.ttf", 28); return env->intern(env, "nil"); } // ----------------------------------------------------------------------------- emacs_value draw_quit (emacs_env* env, ptrdiff_t nargs __attribute__((unused)), emacs_value* args __attribute__((unused)), void* data __attribute__((unused))) { if (fnt) { TTF_CloseFont (fnt); } if (rnd) { SDL_DestroyRenderer (rnd); } if (win) { SDL_DestroyWindow (win); } fnt = NULL; rnd = NULL; win = NULL; TTF_Quit(); SDL_Quit(); return env->intern(env, "nil"); } // ----------------------------------------------------------------------------- void check_all () { if (!win) { printf("[win] error\n"); } if (!rnd) { printf("[rnd] error\n"); } if (!fnt) { printf("[fnt] error\n"); } if (!(win && rnd && fnt)) { exit(EXIT_FAILURE); } } void render_text (const char* txt) { check_all(); if (!txt) { printf("[text] error\n"); exit(EXIT_FAILURE); } SDL_SetRenderDrawColor(rnd, 64, 128, 255, 0); SDL_RenderClear(rnd); SDL_Color clr = { 64, 255, 255, 0 }; int max_h; int max_w; SDL_GetWindowSize(win, &max_w, &max_h); int line_h = TTF_FontHeight(fnt); int line_num = 0; int longest_w = 0; char* buff = my_strdup(txt); char* line = strtok(buff, "\n"); int w; while (line) { TTF_SizeText(fnt, line, &w, NULL); if (longest_w < w) { longest_w = w; } line_num++; line = strtok(NULL, "\n"); } free(buff); int pxls = 32; int frmt = SDL_PIXELFORMAT_RGBA32; int ph = line_h * line_num; int sw = (longest_w > max_w) ? max_w : longest_w; int sh = (ph > max_h) ? max_h : ph; SDL_Surface* main_sur = SDL_CreateRGBSurfaceWithFormat(0, sw, sh, pxls, frmt); if (!main_sur) { printf("[main-surface] error\n"); exit(EXIT_FAILURE); } int swl = (longest_w > max_w) ? max_w : sw; int shl = (line_h > max_h) ? max_h : line_h; SDL_Surface* line_sur = SDL_CreateRGBSurfaceWithFormat(0, swl, shl, pxls, frmt); if (!line_sur) { printf("[line-surface] error\n"); exit(EXIT_FAILURE); } SDL_Rect line_rect = { 0, 0, line_sur->w, line_sur->h }; Uint32 fill_clr = SDL_MapRGB(line_sur->format, 0, 0, 0); SDL_FillRect(line_sur, NULL, fill_clr); char* buff2 = my_strdup(txt); char* line2 = strtok(buff2, "\n"); while (line2) { SDL_FillRect(line_sur, NULL, fill_clr); line_sur = TTF_RenderText_Solid(fnt, line2, clr); SDL_BlitSurface(line_sur, NULL, main_sur, &line_rect); line_rect.y += line_sur->h; line2 = strtok(NULL, "\n"); } free(buff2); SDL_Texture* finl_tex = SDL_CreateTextureFromSurface(rnd, main_sur); if (!finl_tex) { printf("[texture] error\n"); exit(EXIT_FAILURE); } SDL_RenderCopy(rnd, finl_tex, NULL, NULL); SDL_RenderPresent(rnd); SDL_FreeSurface (main_sur); SDL_FreeSurface (line_sur); SDL_DestroyTexture (finl_tex); } // ----------------------------------------------------------------------------- emacs_value draw_draw (emacs_env* env, ptrdiff_t nargs, emacs_value* args, void* data) { if (!(win && rnd && fnt)) { draw_init(env, nargs, args, data); if (!(win && rnd && fnt)) { printf("[draw_draw] error\n"); exit(EXIT_FAILURE); } } emacs_value ef = env->intern(env, "buffer-substring-no-properties-in-window"); emacs_value es = env->funcall(env, ef, 0, NULL); char txt_str[1024]; ptrdiff_t l = 0; env->copy_string_contents(env, es, NULL, &l); env->copy_string_contents(env, es, txt_str, &l); render_text(txt_str); return env->intern(env, "nil"); } // -----------------------------------------------------------------------------