// ----------------------------------------------------------------------------- // https://dataswamp.org/~incal/emacs-init/draw/draw.c // ----------------------------------------------------------------------------- #include "draw.h" #include "new.h" #include #include #include #include #include // ----------------------------------------------------------------------------- int plugin_is_GPL_compatible; // ----------------------------------------------------------------------------- int emacs_module_init (struct emacs_runtime* rnt) { /* check for incompatible Emacs binary */ if (rnt->size < (long int)sizeof(*rnt)) { return 1; } /* check for incompatible module API */ emacs_env* env = rnt->get_environment(rnt); if (env->size < (long int)sizeof(*env)) { return 2; } /* check for too old Emacs */ int __attribute__((unused)) emacs_ver; if ((long int)sizeof(struct emacs_env_31) <= env->size) { emacs_ver = 31; } else if ((long int)sizeof(struct emacs_env_30) <= env->size) { emacs_ver = 30; } else if ((long int)sizeof(struct emacs_env_29) <= env->size) { emacs_ver = 29; } else { return 3; } /* init module */ emacs_value sdl2_init_func = env->make_function(env, 1, 1, sdl2_init, "Init SDL2.", NULL); emacs_value sdl2_init_symb = env->intern(env, "sdl2_init"); emacs_value sdl2_init_args[] = {sdl2_init_symb, sdl2_init_func}; env->funcall(env, env->intern(env, "defalias"), 2, sdl2_init_args); return 0; } // ----------------------------------------------------------------------------- bool handle_event (Kbd* kbd) { SDL_Event e; SDL_PollEvent(&e); if (e.type == SDL_QUIT) { return false; } if (e.type == SDL_KEYDOWN) { kbd->input[e.key.keysym.scancode] = true; } if (e.type == SDL_KEYUP) { kbd->input[e.key.keysym.scancode] = false; } return true; } // ----------------------------------------------------------------------------- SDL_Surface* sur = NULL; SDL_mutex* mut; // ----------------------------------------------------------------------------- int delay (Uint64 to) { Uint64 now = SDL_GetTicks64(); if (now < to) { SDL_Delay(to - now); } return 0; } // ----------------------------------------------------------------------------- int thread_function(void* data __attribute__((unused))) { SDL_Surface* tsr = new_surface(640, 480); SDL_FillRect(tsr, NULL, SDL_MapRGB(tsr->format, 0, 0, 0)); int w = tsr->w; int h = tsr->h; Uint32* pxl = tsr->pixels; Uint32 col = 0; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { pxl[y*w + x] = col++; } } SDL_LockMutex(mut); SDL_BlitSurface(tsr, NULL, sur, NULL); SDL_UnlockMutex(mut); return 0; } // ----------------------------------------------------------------------------- emacs_value sdl2_init (emacs_env* env, ptrdiff_t nargs, emacs_value* args, void* data __attribute__((unused))) { /* init */ SDL_Init(SDL_INIT_EVERYTHING); Kbd kbd = { .input = {false} }; SDL_Window* win; /* renderer */ SDL_Renderer* rend; SDL_CreateWindowAndRenderer(640, 480, 0, &win, &rend); SDL_SetRenderDrawColor(rend, 0, 0, 0, 0); SDL_RenderClear(rend); SDL_RenderPresent(rend); /* text init */ TTF_Init(); int fnt_sze = 32; TTF_Font* txt_fnt = TTF_OpenFont("/usr/share/fonts/truetype/ocr-a/OCRA.ttf", fnt_sze); if (!txt_fnt) { printf("[font] error\n"); exit(1); } /* argument as string */ if (nargs != 1) { printf("[nargs] error\n"); exit(1); } char txt_str[128]; ptrdiff_t l = 0; emacs_value es = args[0]; env->copy_string_contents(env, es, NULL, &l); env->copy_string_contents(env, es, txt_str, &l); /* more text */ SDL_Color txt_col = {0x87, 0xaf, 0xd7, 0xff}; SDL_Surface* txt_sur = TTF_RenderText_Solid(txt_fnt, txt_str, txt_col); SDL_Texture* txt_tex = SDL_CreateTextureFromSurface(rend, txt_sur); SDL_Rect txt_rct; int offs = fnt_sze/2; txt_rct.x = offs; txt_rct.y = offs; txt_rct.w = txt_sur->w; txt_rct.h = txt_sur->h; /* thread */ bool mthr = true; SDL_Thread* thr = NULL; SDL_Surface* screen = NULL; if (mthr) { mut = new_mutex(); screen = new_screen(win); sur = new_surface(screen->w, screen->h); thr = new_thread("draw-thread", thread_function); } /* draw */ while (mthr) { Uint64 to = SDL_GetTicks64() + 16; if (!handle_event(&kbd) || kbd.input[SDL_SCANCODE_Q]) { SDL_UnlockMutex(mut); break; } SDL_LockMutex(mut); SDL_BlitSurface(sur, NULL, screen, NULL); SDL_UpdateWindowSurface(win); SDL_UnlockMutex(mut); delay(to); } /* wait for thread */ if (mthr) { SDL_WaitThread(thr, NULL); } /* draw text */ SDL_Texture* sur_tex = SDL_CreateTextureFromSurface(rend, sur); SDL_Rect sur_tex_rec; sur_tex_rec.x = 0; sur_tex_rec.y = 0; SDL_GetWindowSize(win, &(sur_tex_rec.w), &(sur_tex_rec.h)); SDL_RenderCopy(rend, sur_tex, NULL, &sur_tex_rec); SDL_RenderCopy(rend, txt_tex, NULL, &txt_rct); SDL_RenderPresent(rend); SDL_Delay(4 * 1000); /* quit text */ SDL_FreeSurface(txt_sur); SDL_DestroyTexture(sur_tex); SDL_DestroyTexture(txt_tex); SDL_DestroyRenderer(rend); TTF_CloseFont(txt_fnt); TTF_Quit(); /* quit multithread */ if (mthr) { SDL_FreeSurface(sur); SDL_FreeSurface(screen); SDL_DestroyMutex(mut); } /* quit SDL */ SDL_DestroyWindow(win); SDL_Quit(); /* return to Emacs */ return env->make_integer(env, 0); } // -----------------------------------------------------------------------------