├── CMakeLists.txt ├── EmacsModule.cpp ├── EmacsModule.hpp ├── GLHelper.hpp ├── Main.cpp ├── README.org ├── Window.cpp ├── Window.hpp ├── emacs-module.h ├── img └── mandel.png └── ob-glsl.el /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(ob-glsl-module) 2 | cmake_minimum_required(VERSION 3.11) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | find_package(SDL2 REQUIRED) 7 | find_library(SDL2_IMAGE_LIB SDL2_image) 8 | find_library(GLBINDING_LIB glbinding) 9 | 10 | file(GLOB SRCS "*.cpp") 11 | add_library(${PROJECT_NAME} SHARED ${SRCS}) 12 | set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") 13 | target_include_directories(${PROJECT_NAME} PUBLIC "/usr/local/include") 14 | target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIB} ${GLBINDING_LIB}) 15 | -------------------------------------------------------------------------------- /EmacsModule.cpp: -------------------------------------------------------------------------------- 1 | #include "EmacsModule.hpp" 2 | 3 | namespace detail { 4 | 5 | template<> 6 | std::string extractArg(emacs_env *env, emacs_value v) { 7 | ptrdiff_t len = 0; 8 | env->copy_string_contents(env, v, nullptr, &len); 9 | std::string s(len-1, ' '); 10 | env->copy_string_contents(env, v, s.data(), &len); 11 | return s; 12 | } 13 | 14 | template<> 15 | int extractArg(emacs_env *env, emacs_value v) { 16 | return env->extract_integer(env, v); 17 | } 18 | } 19 | 20 | static std::map symCache; 21 | 22 | emacs_value sym(emacs_env *env, const std::string& name) { 23 | auto i = symCache.find(name); 24 | if (i != symCache.end()) { 25 | return i->second; 26 | } 27 | auto localRef = env->intern(env, name.data()); 28 | auto globalRef = env->make_global_ref(env, localRef); 29 | if (!localRef || !globalRef) throw std::runtime_error("failed to intern symbol: " + name); 30 | symCache.emplace(name, globalRef); 31 | return globalRef; 32 | } 33 | 34 | emacs_value reportError(emacs_env *env, const std::exception& e) { 35 | emacs_value Qerr = env->intern(env, "native-exception"); 36 | std::string msg = e.what(); 37 | emacs_value Qmsg = env->make_string(env, msg.data(), msg.size()); 38 | emacs_value Qnil = env->intern(env, "nil"); 39 | emacs_value Qdata = env->funcall(env, env->intern(env, "list"), 1, &Qmsg); 40 | env->non_local_exit_signal(env, Qerr, Qdata); 41 | return Qnil; 42 | } 43 | 44 | void provide(emacs_env *env, const char *feature) { 45 | emacs_value Qfeat = env->intern(env, feature); 46 | emacs_value Qprovide = env->intern(env, "provide"); 47 | env->funcall(env, Qprovide, 1, &Qfeat); 48 | } 49 | 50 | int plugin_is_GPL_compatible; 51 | -------------------------------------------------------------------------------- /EmacsModule.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "emacs-module.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace detail { 10 | 11 | template 12 | T extractArg(emacs_env *env, emacs_value v); 13 | template<> std::string extractArg(emacs_env *env, emacs_value v); 14 | template<> int extractArg(emacs_env *env, emacs_value v); 15 | 16 | template 17 | auto extractArgsImpl(emacs_env *env, emacs_value* args, std::index_sequence) { 18 | return std::make_tuple(extractArg(env, args[I])...); 19 | } 20 | 21 | template 22 | auto extractArgs(emacs_env *env, ptrdiff_t nargs, emacs_value* args) { 23 | using indices = std::make_index_sequence; 24 | return extractArgsImpl...>(env, args, indices{}); 25 | } 26 | } 27 | 28 | emacs_value sym(emacs_env *env, const std::string& name); 29 | 30 | emacs_value reportError(emacs_env *env, const std::exception& e); 31 | 32 | void provide(emacs_env *env, const char *feature); 33 | 34 | template 35 | void bindFunction(emacs_env *env, emacs_value f(emacs_env*, ARGS...), const char* name) { 36 | auto numArgs = sizeof...(ARGS); 37 | auto trampoline = [] (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void *data) noexcept { 38 | auto func = reinterpret_cast(data); 39 | auto argsTuple = detail::extractArgs(env, nargs, args); 40 | try { 41 | return std::apply(func, std::tuple_cat(std::make_tuple(env), argsTuple)); 42 | } catch (std::exception& e) { 43 | return reportError(env, e); 44 | } 45 | }; 46 | emacs_value Sfun = env->make_function(env, numArgs, numArgs, trampoline, name, reinterpret_cast(f)); 47 | emacs_value Qfset = sym(env, "fset"); 48 | emacs_value Qsym = env->intern(env, name); 49 | emacs_value args[] = {Qsym, Sfun}; 50 | env->funcall(env, Qfset, 2, args); 51 | } 52 | -------------------------------------------------------------------------------- /GLHelper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace gl33core; 9 | 10 | class Shader { 11 | GLuint _handle = 0; 12 | public: 13 | Shader(GLenum type, const std::string& src) { 14 | _handle = glCreateShader(type); 15 | const char* srcList[] = {src.c_str()}; 16 | glShaderSource(_handle, 1, srcList, nullptr); 17 | glCompileShader(_handle); 18 | GLint compilationOk; 19 | glGetShaderiv(_handle, GL_COMPILE_STATUS, &compilationOk); 20 | if (!compilationOk) 21 | { 22 | GLint errLength; 23 | glGetShaderiv(_handle, GL_INFO_LOG_LENGTH, &errLength); 24 | std::string errLog(errLength, '\0'); 25 | glGetShaderInfoLog(_handle, errLength, &errLength, errLog.data()); 26 | throw std::runtime_error("shader compilation failed:" + errLog); 27 | } 28 | } 29 | Shader(Shader&& other) noexcept { 30 | _handle = other._handle; 31 | other._handle = 0; 32 | } 33 | virtual ~Shader() { 34 | if (_handle) { 35 | glDeleteShader(_handle); 36 | } 37 | } 38 | GLuint handle() const {return _handle;} 39 | }; 40 | 41 | class RenderProgram { 42 | GLuint _handle = 0; 43 | public: 44 | RenderProgram(const std::vector& shaders) 45 | { 46 | _handle = glCreateProgram(); 47 | for(const auto& shader: shaders) { 48 | glAttachShader(_handle, shader.handle()); 49 | } 50 | glLinkProgram(_handle); 51 | GLint isLinked = 0; 52 | glGetProgramiv(_handle, GL_LINK_STATUS, &isLinked); 53 | if(!isLinked) { 54 | auto errCode = glGetError(); 55 | GLint maxLength; 56 | glGetProgramiv(_handle, GL_INFO_LOG_LENGTH, &maxLength); 57 | std::vector infoLog(maxLength); 58 | glGetProgramInfoLog(_handle, maxLength, &maxLength, &infoLog[0]); 59 | throw std::runtime_error(std::string("failed to link program: ") + 60 | std::to_string(static_cast(errCode)) + 61 | reinterpret_cast(infoLog.data())); 62 | } 63 | } 64 | RenderProgram(RenderProgram&& other) noexcept { 65 | _handle = other._handle; 66 | other._handle = 0; 67 | } 68 | virtual ~RenderProgram() 69 | { 70 | if (_handle) 71 | glDeleteProgram(_handle); 72 | } 73 | void use() const 74 | { 75 | glUseProgram(_handle); 76 | } 77 | GLuint getUniformLocation(const char* name) const 78 | { 79 | return glGetUniformLocation(_handle, name); 80 | } 81 | }; 82 | 83 | class VertexArray { 84 | GLuint _handle = 0; 85 | public: 86 | VertexArray() { 87 | glGenVertexArrays(1, &_handle); 88 | } 89 | VertexArray(VertexArray&& other) noexcept { 90 | _handle = other._handle; 91 | other._handle = 0; 92 | } 93 | virtual ~VertexArray() { 94 | if (_handle) { 95 | glDeleteVertexArrays(1, &_handle); 96 | } 97 | } 98 | void bind() { 99 | glBindVertexArray(_handle); 100 | } 101 | }; 102 | 103 | class RenderBuffer { 104 | GLuint _handle = 0; 105 | friend class FrameBuffer; 106 | public: 107 | RenderBuffer() { 108 | glGenRenderbuffers(1, &_handle); 109 | } 110 | virtual ~RenderBuffer() { 111 | if (_handle) 112 | glDeleteRenderbuffers(1, &_handle); 113 | } 114 | RenderBuffer(RenderBuffer&& other) noexcept { 115 | _handle = other._handle; 116 | other._handle = 0; 117 | } 118 | void bind() { 119 | glBindRenderbuffer(GL_RENDERBUFFER, _handle); 120 | } 121 | }; 122 | 123 | class FrameBuffer { 124 | GLuint _handle = 0; 125 | public: 126 | FrameBuffer() { 127 | glGenFramebuffers(1, &_handle); 128 | } 129 | virtual ~FrameBuffer() { 130 | if (_handle) 131 | glDeleteFramebuffers(1, &_handle); 132 | } 133 | FrameBuffer(FrameBuffer&& other) noexcept { 134 | _handle = other._handle; 135 | other._handle = 0; 136 | } 137 | void bind() { 138 | glBindFramebuffer(GL_FRAMEBUFFER, _handle); 139 | } 140 | void renderBuffer(const RenderBuffer& rb) { 141 | glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb._handle); 142 | } 143 | bool check() { 144 | return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE; 145 | } 146 | }; 147 | -------------------------------------------------------------------------------- /Main.cpp: -------------------------------------------------------------------------------- 1 | #include "EmacsModule.hpp" 2 | #include "Window.hpp" 3 | #include "GLHelper.hpp" 4 | #include 5 | 6 | static const std::string vs = R"( 7 | #version 330 core 8 | const vec4 vertice[4] = vec4[4] ( 9 | vec4(-1.0, 1.0, 0.0, 1.0),vec4(-1.0, -1.0, 0.0, 1.0), 10 | vec4( 1.0, -1.0, 0.0, 1.0),vec4( 1.0, 1.0, 0.0, 1.0) 11 | ); 12 | void main() { 13 | gl_Position = vertice[gl_VertexID]; 14 | })"; 15 | 16 | static const std::string ps = R"( 17 | #version 330 core 18 | out vec4 fragColor; 19 | uniform vec2 iResolution; 20 | const float esc = 20.0; 21 | const int depth = 420; 22 | const float p = 30.0; 23 | vec3 mandel(vec2 z0) { 24 | float k = 0.0; 25 | vec2 z = vec2(0.0); 26 | for(int i = 0; i < depth; ++i) { 27 | z = vec2(z.x*z.x-z.y*z.y, z.x*z.y*2.0) + z0; 28 | if (length(z) > esc) 29 | break; 30 | k += 1.0; 31 | } 32 | float mu = k + 1.0 - log2(log(length(z))); 33 | return sin(mu*0.1 + vec3(0.0,0.5,1.0)); 34 | } 35 | void main() { 36 | float ar = iResolution.x / iResolution.y; 37 | vec2 uv = gl_FragCoord.xy / iResolution.yy - vec2(0.66 * ar, 0.5); 38 | float scale = 0.5; 39 | vec2 offset = vec2(-0.3, 0.0); 40 | uv += offset*scale; 41 | uv /= scale; 42 | fragColor = vec4(mandel(uv), 1.0); 43 | })"; 44 | 45 | emacs_value obGlslRun (emacs_env* env, 46 | const std::string& shaderCode, 47 | int width, 48 | int height, 49 | const std::string& outputPath) { 50 | FrameBuffer fb; 51 | RenderBuffer rb; 52 | rb.bind(); 53 | glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); 54 | fb.bind(); 55 | fb.renderBuffer(rb); 56 | if (!fb.check()) 57 | throw std::runtime_error("framebuffer is not complete!"); 58 | 59 | // prepare shader 60 | std::vector shaders; 61 | shaders.emplace_back(GL_VERTEX_SHADER, vs); 62 | shaders.emplace_back(GL_FRAGMENT_SHADER, shaderCode.empty() ? ps : shaderCode); 63 | RenderProgram prog(shaders); 64 | 65 | // draw 66 | VertexArray vao; 67 | glViewport(0, 0, width, height); 68 | glClearColor(1.0, 1.0, 0.0, 1.0); 69 | glClear(GL_COLOR_BUFFER_BIT); 70 | vao.bind(); 71 | prog.use(); 72 | auto res = prog.getUniformLocation("iResolution"); 73 | glUniform2f(res, width, height); 74 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 75 | 76 | // read back 77 | std::vector pixels(width * 4 * height); 78 | glReadBuffer(GL_COLOR_ATTACHMENT0); 79 | glReadPixels(0,0,width,height,GL_RGBA,GL_UNSIGNED_BYTE,pixels.data()); 80 | 81 | auto surface = SDL_CreateRGBSurfaceFrom(pixels.data(), width, height, 82 | 32/*depth*/, width * 4/*pitch*/, 83 | 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); 84 | IMG_SavePNG(surface, outputPath.data()); 85 | SDL_FreeSurface(surface); 86 | 87 | auto estr = env->make_string(env, outputPath.data(), outputPath.size()); 88 | return estr; 89 | }; 90 | 91 | int emacs_module_init (emacs_runtime *ert) noexcept { 92 | emacs_env* env = ert->get_environment (ert); 93 | try { 94 | init(); 95 | glbinding::Binding::initialize(nullptr); 96 | } catch (std::exception& e) { 97 | reportError(env, e); 98 | } 99 | 100 | bindFunction(env, obGlslRun, "ob-glsl-run"); 101 | provide(env, "ob-glsl-module"); 102 | return 0; 103 | } 104 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+TITLE: GLSL code blocks for Emacs Org-mode 2 | 3 | This org-mode extension adds the capability to run GLSL code blocks directly 4 | from inside Emacs and immediately displays the rendering results inline in your 5 | org-mode buffers. 6 | 7 | * Requirements 8 | - SDL2 (for creating OpenGL context) 9 | - SDL2_image (for saving PNG files) 10 | - glbinding (for OpenGL SDK) 11 | 12 | The rendering is done with OpenGL 3.3 so should work on any graphcs card. 13 | 14 | * Building 15 | 1. Generate project with CMake: 16 | #+begin_src sh 17 | cmake -G "Ninja" . 18 | #+end_src 19 | 20 | 2. Build the code: 21 | #+begin_src sh 22 | ninja 23 | #+end_src 24 | 25 | This will create the Emacs dynamic module ~ob-glsl-module.so~ (Linux) or 26 | ~ob-glsl-module.dll~ (Windows) or ~ob-glsl-module.dylib~ (MacOS). 27 | 28 | * Installing 29 | 1. Put both ~ob-glsl.el~ and the dynamic module under your elisp load path. 30 | 2. Add ~(glsl . t)~ to ~org-babel-load-languages~. You can either customize 31 | the variable or add it manually in lisp code. 32 | 33 | * Supported parameters 34 | - ~:file~ 35 | The output file path (required) 36 | - ~:width~ 37 | The render width in pixels 38 | - ~:height~ 39 | The render height in pixels 40 | 41 | You can omit either ~:width~ or ~:height~ and the omitted one will be 42 | calculated based on the other parameter. If you omit both, then the default 43 | output size is 400x300. 44 | 45 | * A simple pixel shader example 46 | #+BEGIN_SRC glsl :file img/mandel.png :width 600 :height 450 47 | vec3 mandel(vec2 z0) { 48 | float k = 0.0; 49 | vec2 z = vec2(0.0); 50 | for(int i = 0; i < 420; ++i) { 51 | z = vec2(z.x*z.x-z.y*z.y, z.x*z.y*2.0) + z0; 52 | if (length(z) > 20.0) break; 53 | k += 1.0; 54 | } 55 | float mu = k + 1.0 - log2(log(length(z))); 56 | return sin(mu*0.1 + vec3(0.0,0.5,1.0)); 57 | } 58 | void main() { 59 | float ar = iResolution.x / iResolution.y; 60 | vec2 uv = gl_FragCoord.xy / iResolution.yy - vec2(0.66 * ar, 0.5); 61 | // uv = uv * 2.0 + vec2(-0.3, 0.0); 62 | float p = 30.0; 63 | float t = mod(13.0, p); 64 | if (t > p/2.0) t = p - t; 65 | float scale = 0.5 + pow(2.0, t); 66 | vec2 offset = vec2(-1.36799, .01); 67 | uv += offset*scale; 68 | uv /= scale; 69 | fragColor = vec4(mandel(uv), 1.0); 70 | } 71 | #+END_SRC 72 | 73 | [[img/mandel.png]] 74 | -------------------------------------------------------------------------------- /Window.cpp: -------------------------------------------------------------------------------- 1 | #include "Window.hpp" 2 | #include 3 | #include 4 | 5 | static SDL_Window* win = nullptr; 6 | static SDL_GLContext ctx = nullptr; 7 | 8 | void init() { 9 | SDL_Init(SDL_INIT_VIDEO); 10 | 11 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 12 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); 13 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 14 | 15 | win = SDL_CreateWindow("hidden", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 16 | 100, 100, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN); 17 | if (!win) throw std::runtime_error("failed to create window"); 18 | ctx = SDL_GL_CreateContext(win); 19 | if (!ctx) throw std::runtime_error("failed to create gl context"); 20 | } 21 | -------------------------------------------------------------------------------- /Window.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void init(); 4 | -------------------------------------------------------------------------------- /emacs-module.h: -------------------------------------------------------------------------------- 1 | /* emacs-module.h - GNU Emacs module API. 2 | 3 | Copyright (C) 2015-2021 Free Software Foundation, Inc. 4 | 5 | This file is part of GNU Emacs. 6 | 7 | GNU Emacs is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or (at 10 | your option) any later version. 11 | 12 | GNU Emacs is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with GNU Emacs. If not, see . */ 19 | 20 | /* 21 | This file defines the Emacs module API. Please see the chapter 22 | `Dynamic Modules' in the GNU Emacs Lisp Reference Manual for 23 | information how to write modules and use this header file. 24 | */ 25 | 26 | #ifndef EMACS_MODULE_H 27 | #define EMACS_MODULE_H 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #ifndef __cplusplus 34 | #include 35 | #endif 36 | 37 | #define EMACS_MAJOR_VERSION 28 38 | 39 | #if defined __cplusplus && __cplusplus >= 201103L 40 | # define EMACS_NOEXCEPT noexcept 41 | #else 42 | # define EMACS_NOEXCEPT 43 | #endif 44 | 45 | #if defined __cplusplus && __cplusplus >= 201703L 46 | # define EMACS_NOEXCEPT_TYPEDEF noexcept 47 | #else 48 | # define EMACS_NOEXCEPT_TYPEDEF 49 | #endif 50 | 51 | #if 3 < __GNUC__ + (3 <= __GNUC_MINOR__) 52 | # define EMACS_ATTRIBUTE_NONNULL(...) \ 53 | __attribute__ ((__nonnull__ (__VA_ARGS__))) 54 | #elif (defined __has_attribute \ 55 | && (!defined __clang_minor__ \ 56 | || 3 < __clang_major__ + (5 <= __clang_minor__))) 57 | # if __has_attribute (__nonnull__) 58 | # define EMACS_ATTRIBUTE_NONNULL(...) \ 59 | __attribute__ ((__nonnull__ (__VA_ARGS__))) 60 | # endif 61 | #endif 62 | #ifndef EMACS_ATTRIBUTE_NONNULL 63 | # define EMACS_ATTRIBUTE_NONNULL(...) 64 | #endif 65 | 66 | #ifdef __cplusplus 67 | extern "C" { 68 | #endif 69 | 70 | /* Current environment. */ 71 | typedef struct emacs_env_28 emacs_env; 72 | 73 | /* Opaque pointer representing an Emacs Lisp value. 74 | BEWARE: Do not assume NULL is a valid value! */ 75 | typedef struct emacs_value_tag *emacs_value; 76 | 77 | enum { emacs_variadic_function = -2 }; 78 | 79 | /* Struct passed to a module init function (emacs_module_init). */ 80 | struct emacs_runtime 81 | { 82 | /* Structure size (for version checking). */ 83 | ptrdiff_t size; 84 | 85 | /* Private data; users should not touch this. */ 86 | struct emacs_runtime_private *private_members; 87 | 88 | /* Return an environment pointer. */ 89 | emacs_env *(*get_environment) (struct emacs_runtime *runtime) 90 | EMACS_ATTRIBUTE_NONNULL (1); 91 | }; 92 | 93 | /* Type aliases for function pointer types used in the module API. 94 | Note that we don't use these aliases directly in the API to be able 95 | to mark the function arguments as 'noexcept' before C++20. 96 | However, users can use them if they want. */ 97 | 98 | /* Function prototype for the module Lisp functions. These must not 99 | throw C++ exceptions. */ 100 | typedef emacs_value (*emacs_function) (emacs_env *env, ptrdiff_t nargs, 101 | emacs_value *args, 102 | void *data) 103 | EMACS_NOEXCEPT_TYPEDEF EMACS_ATTRIBUTE_NONNULL (1); 104 | 105 | /* Function prototype for module user-pointer and function finalizers. 106 | These must not throw C++ exceptions. */ 107 | typedef void (*emacs_finalizer) (void *data) EMACS_NOEXCEPT_TYPEDEF; 108 | 109 | /* Possible Emacs function call outcomes. */ 110 | enum emacs_funcall_exit 111 | { 112 | /* Function has returned normally. */ 113 | emacs_funcall_exit_return = 0, 114 | 115 | /* Function has signaled an error using `signal'. */ 116 | emacs_funcall_exit_signal = 1, 117 | 118 | /* Function has exit using `throw'. */ 119 | emacs_funcall_exit_throw = 2 120 | }; 121 | 122 | /* Possible return values for emacs_env.process_input. */ 123 | enum emacs_process_input_result 124 | { 125 | /* Module code may continue */ 126 | emacs_process_input_continue = 0, 127 | 128 | /* Module code should return control to Emacs as soon as possible. */ 129 | emacs_process_input_quit = 1 130 | }; 131 | 132 | /* Define emacs_limb_t so that it is likely to match GMP's mp_limb_t. 133 | This micro-optimization can help modules that use mpz_export and 134 | mpz_import, which operate more efficiently on mp_limb_t. It's OK 135 | (if perhaps a bit slower) if the two types do not match, and 136 | modules shouldn't rely on the two types matching. */ 137 | typedef size_t emacs_limb_t; 138 | #define EMACS_LIMB_MAX SIZE_MAX 139 | 140 | struct emacs_env_25 141 | { 142 | /* Structure size (for version checking). */ 143 | ptrdiff_t size; 144 | 145 | /* Private data; users should not touch this. */ 146 | struct emacs_env_private *private_members; 147 | 148 | /* Memory management. */ 149 | 150 | emacs_value (*make_global_ref) (emacs_env *env, emacs_value value) 151 | EMACS_ATTRIBUTE_NONNULL(1); 152 | 153 | void (*free_global_ref) (emacs_env *env, emacs_value global_value) 154 | EMACS_ATTRIBUTE_NONNULL(1); 155 | 156 | /* Non-local exit handling. */ 157 | 158 | enum emacs_funcall_exit (*non_local_exit_check) (emacs_env *env) 159 | EMACS_ATTRIBUTE_NONNULL(1); 160 | 161 | void (*non_local_exit_clear) (emacs_env *env) 162 | EMACS_ATTRIBUTE_NONNULL(1); 163 | 164 | enum emacs_funcall_exit (*non_local_exit_get) 165 | (emacs_env *env, emacs_value *symbol, emacs_value *data) 166 | EMACS_ATTRIBUTE_NONNULL(1, 2, 3); 167 | 168 | void (*non_local_exit_signal) (emacs_env *env, 169 | emacs_value symbol, emacs_value data) 170 | EMACS_ATTRIBUTE_NONNULL(1); 171 | 172 | void (*non_local_exit_throw) (emacs_env *env, 173 | emacs_value tag, emacs_value value) 174 | EMACS_ATTRIBUTE_NONNULL(1); 175 | 176 | /* Function registration. */ 177 | 178 | emacs_value (*make_function) (emacs_env *env, 179 | ptrdiff_t min_arity, 180 | ptrdiff_t max_arity, 181 | emacs_value (*func) (emacs_env *env, 182 | ptrdiff_t nargs, 183 | emacs_value* args, 184 | void *data) 185 | EMACS_NOEXCEPT 186 | EMACS_ATTRIBUTE_NONNULL(1), 187 | const char *docstring, 188 | void *data) 189 | EMACS_ATTRIBUTE_NONNULL(1, 4); 190 | 191 | emacs_value (*funcall) (emacs_env *env, 192 | emacs_value func, 193 | ptrdiff_t nargs, 194 | emacs_value* args) 195 | EMACS_ATTRIBUTE_NONNULL(1); 196 | 197 | emacs_value (*intern) (emacs_env *env, const char *name) 198 | EMACS_ATTRIBUTE_NONNULL(1, 2); 199 | 200 | /* Type conversion. */ 201 | 202 | emacs_value (*type_of) (emacs_env *env, emacs_value arg) 203 | EMACS_ATTRIBUTE_NONNULL(1); 204 | 205 | bool (*is_not_nil) (emacs_env *env, emacs_value arg) 206 | EMACS_ATTRIBUTE_NONNULL(1); 207 | 208 | bool (*eq) (emacs_env *env, emacs_value a, emacs_value b) 209 | EMACS_ATTRIBUTE_NONNULL(1); 210 | 211 | intmax_t (*extract_integer) (emacs_env *env, emacs_value arg) 212 | EMACS_ATTRIBUTE_NONNULL(1); 213 | 214 | emacs_value (*make_integer) (emacs_env *env, intmax_t n) 215 | EMACS_ATTRIBUTE_NONNULL(1); 216 | 217 | double (*extract_float) (emacs_env *env, emacs_value arg) 218 | EMACS_ATTRIBUTE_NONNULL(1); 219 | 220 | emacs_value (*make_float) (emacs_env *env, double d) 221 | EMACS_ATTRIBUTE_NONNULL(1); 222 | 223 | /* Copy the content of the Lisp string VALUE to BUFFER as an utf8 224 | null-terminated string. 225 | 226 | SIZE must point to the total size of the buffer. If BUFFER is 227 | NULL or if SIZE is not big enough, write the required buffer size 228 | to SIZE and return true. 229 | 230 | Note that SIZE must include the last null byte (e.g. "abc" needs 231 | a buffer of size 4). 232 | 233 | Return true if the string was successfully copied. */ 234 | 235 | bool (*copy_string_contents) (emacs_env *env, 236 | emacs_value value, 237 | char *buf, 238 | ptrdiff_t *len) 239 | EMACS_ATTRIBUTE_NONNULL(1, 4); 240 | 241 | /* Create a Lisp string from a utf8 encoded string. */ 242 | emacs_value (*make_string) (emacs_env *env, 243 | const char *str, ptrdiff_t len) 244 | EMACS_ATTRIBUTE_NONNULL(1, 2); 245 | 246 | /* Embedded pointer type. */ 247 | emacs_value (*make_user_ptr) (emacs_env *env, 248 | void (*fin) (void *) EMACS_NOEXCEPT, 249 | void *ptr) 250 | EMACS_ATTRIBUTE_NONNULL(1); 251 | 252 | void *(*get_user_ptr) (emacs_env *env, emacs_value arg) 253 | EMACS_ATTRIBUTE_NONNULL(1); 254 | void (*set_user_ptr) (emacs_env *env, emacs_value arg, void *ptr) 255 | EMACS_ATTRIBUTE_NONNULL(1); 256 | 257 | void (*(*get_user_finalizer) (emacs_env *env, emacs_value uptr)) 258 | (void *) EMACS_NOEXCEPT EMACS_ATTRIBUTE_NONNULL(1); 259 | void (*set_user_finalizer) (emacs_env *env, emacs_value arg, 260 | void (*fin) (void *) EMACS_NOEXCEPT) 261 | EMACS_ATTRIBUTE_NONNULL(1); 262 | 263 | /* Vector functions. */ 264 | emacs_value (*vec_get) (emacs_env *env, emacs_value vector, ptrdiff_t index) 265 | EMACS_ATTRIBUTE_NONNULL(1); 266 | 267 | void (*vec_set) (emacs_env *env, emacs_value vector, ptrdiff_t index, 268 | emacs_value value) 269 | EMACS_ATTRIBUTE_NONNULL(1); 270 | 271 | ptrdiff_t (*vec_size) (emacs_env *env, emacs_value vector) 272 | EMACS_ATTRIBUTE_NONNULL(1); 273 | }; 274 | 275 | struct emacs_env_26 276 | { 277 | /* Structure size (for version checking). */ 278 | ptrdiff_t size; 279 | 280 | /* Private data; users should not touch this. */ 281 | struct emacs_env_private *private_members; 282 | 283 | /* Memory management. */ 284 | 285 | emacs_value (*make_global_ref) (emacs_env *env, emacs_value value) 286 | EMACS_ATTRIBUTE_NONNULL(1); 287 | 288 | void (*free_global_ref) (emacs_env *env, emacs_value global_value) 289 | EMACS_ATTRIBUTE_NONNULL(1); 290 | 291 | /* Non-local exit handling. */ 292 | 293 | enum emacs_funcall_exit (*non_local_exit_check) (emacs_env *env) 294 | EMACS_ATTRIBUTE_NONNULL(1); 295 | 296 | void (*non_local_exit_clear) (emacs_env *env) 297 | EMACS_ATTRIBUTE_NONNULL(1); 298 | 299 | enum emacs_funcall_exit (*non_local_exit_get) 300 | (emacs_env *env, emacs_value *symbol, emacs_value *data) 301 | EMACS_ATTRIBUTE_NONNULL(1, 2, 3); 302 | 303 | void (*non_local_exit_signal) (emacs_env *env, 304 | emacs_value symbol, emacs_value data) 305 | EMACS_ATTRIBUTE_NONNULL(1); 306 | 307 | void (*non_local_exit_throw) (emacs_env *env, 308 | emacs_value tag, emacs_value value) 309 | EMACS_ATTRIBUTE_NONNULL(1); 310 | 311 | /* Function registration. */ 312 | 313 | emacs_value (*make_function) (emacs_env *env, 314 | ptrdiff_t min_arity, 315 | ptrdiff_t max_arity, 316 | emacs_value (*func) (emacs_env *env, 317 | ptrdiff_t nargs, 318 | emacs_value* args, 319 | void *data) 320 | EMACS_NOEXCEPT 321 | EMACS_ATTRIBUTE_NONNULL(1), 322 | const char *docstring, 323 | void *data) 324 | EMACS_ATTRIBUTE_NONNULL(1, 4); 325 | 326 | emacs_value (*funcall) (emacs_env *env, 327 | emacs_value func, 328 | ptrdiff_t nargs, 329 | emacs_value* args) 330 | EMACS_ATTRIBUTE_NONNULL(1); 331 | 332 | emacs_value (*intern) (emacs_env *env, const char *name) 333 | EMACS_ATTRIBUTE_NONNULL(1, 2); 334 | 335 | /* Type conversion. */ 336 | 337 | emacs_value (*type_of) (emacs_env *env, emacs_value arg) 338 | EMACS_ATTRIBUTE_NONNULL(1); 339 | 340 | bool (*is_not_nil) (emacs_env *env, emacs_value arg) 341 | EMACS_ATTRIBUTE_NONNULL(1); 342 | 343 | bool (*eq) (emacs_env *env, emacs_value a, emacs_value b) 344 | EMACS_ATTRIBUTE_NONNULL(1); 345 | 346 | intmax_t (*extract_integer) (emacs_env *env, emacs_value arg) 347 | EMACS_ATTRIBUTE_NONNULL(1); 348 | 349 | emacs_value (*make_integer) (emacs_env *env, intmax_t n) 350 | EMACS_ATTRIBUTE_NONNULL(1); 351 | 352 | double (*extract_float) (emacs_env *env, emacs_value arg) 353 | EMACS_ATTRIBUTE_NONNULL(1); 354 | 355 | emacs_value (*make_float) (emacs_env *env, double d) 356 | EMACS_ATTRIBUTE_NONNULL(1); 357 | 358 | /* Copy the content of the Lisp string VALUE to BUFFER as an utf8 359 | null-terminated string. 360 | 361 | SIZE must point to the total size of the buffer. If BUFFER is 362 | NULL or if SIZE is not big enough, write the required buffer size 363 | to SIZE and return true. 364 | 365 | Note that SIZE must include the last null byte (e.g. "abc" needs 366 | a buffer of size 4). 367 | 368 | Return true if the string was successfully copied. */ 369 | 370 | bool (*copy_string_contents) (emacs_env *env, 371 | emacs_value value, 372 | char *buf, 373 | ptrdiff_t *len) 374 | EMACS_ATTRIBUTE_NONNULL(1, 4); 375 | 376 | /* Create a Lisp string from a utf8 encoded string. */ 377 | emacs_value (*make_string) (emacs_env *env, 378 | const char *str, ptrdiff_t len) 379 | EMACS_ATTRIBUTE_NONNULL(1, 2); 380 | 381 | /* Embedded pointer type. */ 382 | emacs_value (*make_user_ptr) (emacs_env *env, 383 | void (*fin) (void *) EMACS_NOEXCEPT, 384 | void *ptr) 385 | EMACS_ATTRIBUTE_NONNULL(1); 386 | 387 | void *(*get_user_ptr) (emacs_env *env, emacs_value arg) 388 | EMACS_ATTRIBUTE_NONNULL(1); 389 | void (*set_user_ptr) (emacs_env *env, emacs_value arg, void *ptr) 390 | EMACS_ATTRIBUTE_NONNULL(1); 391 | 392 | void (*(*get_user_finalizer) (emacs_env *env, emacs_value uptr)) 393 | (void *) EMACS_NOEXCEPT EMACS_ATTRIBUTE_NONNULL(1); 394 | void (*set_user_finalizer) (emacs_env *env, emacs_value arg, 395 | void (*fin) (void *) EMACS_NOEXCEPT) 396 | EMACS_ATTRIBUTE_NONNULL(1); 397 | 398 | /* Vector functions. */ 399 | emacs_value (*vec_get) (emacs_env *env, emacs_value vector, ptrdiff_t index) 400 | EMACS_ATTRIBUTE_NONNULL(1); 401 | 402 | void (*vec_set) (emacs_env *env, emacs_value vector, ptrdiff_t index, 403 | emacs_value value) 404 | EMACS_ATTRIBUTE_NONNULL(1); 405 | 406 | ptrdiff_t (*vec_size) (emacs_env *env, emacs_value vector) 407 | EMACS_ATTRIBUTE_NONNULL(1); 408 | 409 | /* Returns whether a quit is pending. */ 410 | bool (*should_quit) (emacs_env *env) 411 | EMACS_ATTRIBUTE_NONNULL(1); 412 | }; 413 | 414 | struct emacs_env_27 415 | { 416 | /* Structure size (for version checking). */ 417 | ptrdiff_t size; 418 | 419 | /* Private data; users should not touch this. */ 420 | struct emacs_env_private *private_members; 421 | 422 | /* Memory management. */ 423 | 424 | emacs_value (*make_global_ref) (emacs_env *env, emacs_value value) 425 | EMACS_ATTRIBUTE_NONNULL(1); 426 | 427 | void (*free_global_ref) (emacs_env *env, emacs_value global_value) 428 | EMACS_ATTRIBUTE_NONNULL(1); 429 | 430 | /* Non-local exit handling. */ 431 | 432 | enum emacs_funcall_exit (*non_local_exit_check) (emacs_env *env) 433 | EMACS_ATTRIBUTE_NONNULL(1); 434 | 435 | void (*non_local_exit_clear) (emacs_env *env) 436 | EMACS_ATTRIBUTE_NONNULL(1); 437 | 438 | enum emacs_funcall_exit (*non_local_exit_get) 439 | (emacs_env *env, emacs_value *symbol, emacs_value *data) 440 | EMACS_ATTRIBUTE_NONNULL(1, 2, 3); 441 | 442 | void (*non_local_exit_signal) (emacs_env *env, 443 | emacs_value symbol, emacs_value data) 444 | EMACS_ATTRIBUTE_NONNULL(1); 445 | 446 | void (*non_local_exit_throw) (emacs_env *env, 447 | emacs_value tag, emacs_value value) 448 | EMACS_ATTRIBUTE_NONNULL(1); 449 | 450 | /* Function registration. */ 451 | 452 | emacs_value (*make_function) (emacs_env *env, 453 | ptrdiff_t min_arity, 454 | ptrdiff_t max_arity, 455 | emacs_value (*func) (emacs_env *env, 456 | ptrdiff_t nargs, 457 | emacs_value* args, 458 | void *data) 459 | EMACS_NOEXCEPT 460 | EMACS_ATTRIBUTE_NONNULL(1), 461 | const char *docstring, 462 | void *data) 463 | EMACS_ATTRIBUTE_NONNULL(1, 4); 464 | 465 | emacs_value (*funcall) (emacs_env *env, 466 | emacs_value func, 467 | ptrdiff_t nargs, 468 | emacs_value* args) 469 | EMACS_ATTRIBUTE_NONNULL(1); 470 | 471 | emacs_value (*intern) (emacs_env *env, const char *name) 472 | EMACS_ATTRIBUTE_NONNULL(1, 2); 473 | 474 | /* Type conversion. */ 475 | 476 | emacs_value (*type_of) (emacs_env *env, emacs_value arg) 477 | EMACS_ATTRIBUTE_NONNULL(1); 478 | 479 | bool (*is_not_nil) (emacs_env *env, emacs_value arg) 480 | EMACS_ATTRIBUTE_NONNULL(1); 481 | 482 | bool (*eq) (emacs_env *env, emacs_value a, emacs_value b) 483 | EMACS_ATTRIBUTE_NONNULL(1); 484 | 485 | intmax_t (*extract_integer) (emacs_env *env, emacs_value arg) 486 | EMACS_ATTRIBUTE_NONNULL(1); 487 | 488 | emacs_value (*make_integer) (emacs_env *env, intmax_t n) 489 | EMACS_ATTRIBUTE_NONNULL(1); 490 | 491 | double (*extract_float) (emacs_env *env, emacs_value arg) 492 | EMACS_ATTRIBUTE_NONNULL(1); 493 | 494 | emacs_value (*make_float) (emacs_env *env, double d) 495 | EMACS_ATTRIBUTE_NONNULL(1); 496 | 497 | /* Copy the content of the Lisp string VALUE to BUFFER as an utf8 498 | null-terminated string. 499 | 500 | SIZE must point to the total size of the buffer. If BUFFER is 501 | NULL or if SIZE is not big enough, write the required buffer size 502 | to SIZE and return true. 503 | 504 | Note that SIZE must include the last null byte (e.g. "abc" needs 505 | a buffer of size 4). 506 | 507 | Return true if the string was successfully copied. */ 508 | 509 | bool (*copy_string_contents) (emacs_env *env, 510 | emacs_value value, 511 | char *buf, 512 | ptrdiff_t *len) 513 | EMACS_ATTRIBUTE_NONNULL(1, 4); 514 | 515 | /* Create a Lisp string from a utf8 encoded string. */ 516 | emacs_value (*make_string) (emacs_env *env, 517 | const char *str, ptrdiff_t len) 518 | EMACS_ATTRIBUTE_NONNULL(1, 2); 519 | 520 | /* Embedded pointer type. */ 521 | emacs_value (*make_user_ptr) (emacs_env *env, 522 | void (*fin) (void *) EMACS_NOEXCEPT, 523 | void *ptr) 524 | EMACS_ATTRIBUTE_NONNULL(1); 525 | 526 | void *(*get_user_ptr) (emacs_env *env, emacs_value arg) 527 | EMACS_ATTRIBUTE_NONNULL(1); 528 | void (*set_user_ptr) (emacs_env *env, emacs_value arg, void *ptr) 529 | EMACS_ATTRIBUTE_NONNULL(1); 530 | 531 | void (*(*get_user_finalizer) (emacs_env *env, emacs_value uptr)) 532 | (void *) EMACS_NOEXCEPT EMACS_ATTRIBUTE_NONNULL(1); 533 | void (*set_user_finalizer) (emacs_env *env, emacs_value arg, 534 | void (*fin) (void *) EMACS_NOEXCEPT) 535 | EMACS_ATTRIBUTE_NONNULL(1); 536 | 537 | /* Vector functions. */ 538 | emacs_value (*vec_get) (emacs_env *env, emacs_value vector, ptrdiff_t index) 539 | EMACS_ATTRIBUTE_NONNULL(1); 540 | 541 | void (*vec_set) (emacs_env *env, emacs_value vector, ptrdiff_t index, 542 | emacs_value value) 543 | EMACS_ATTRIBUTE_NONNULL(1); 544 | 545 | ptrdiff_t (*vec_size) (emacs_env *env, emacs_value vector) 546 | EMACS_ATTRIBUTE_NONNULL(1); 547 | 548 | /* Returns whether a quit is pending. */ 549 | bool (*should_quit) (emacs_env *env) 550 | EMACS_ATTRIBUTE_NONNULL(1); 551 | 552 | /* Processes pending input events and returns whether the module 553 | function should quit. */ 554 | enum emacs_process_input_result (*process_input) (emacs_env *env) 555 | EMACS_ATTRIBUTE_NONNULL (1); 556 | 557 | struct timespec (*extract_time) (emacs_env *env, emacs_value arg) 558 | EMACS_ATTRIBUTE_NONNULL (1); 559 | 560 | emacs_value (*make_time) (emacs_env *env, struct timespec time) 561 | EMACS_ATTRIBUTE_NONNULL (1); 562 | 563 | bool (*extract_big_integer) (emacs_env *env, emacs_value arg, int *sign, 564 | ptrdiff_t *count, emacs_limb_t *magnitude) 565 | EMACS_ATTRIBUTE_NONNULL (1); 566 | 567 | emacs_value (*make_big_integer) (emacs_env *env, int sign, ptrdiff_t count, 568 | const emacs_limb_t *magnitude) 569 | EMACS_ATTRIBUTE_NONNULL (1); 570 | }; 571 | 572 | struct emacs_env_28 573 | { 574 | /* Structure size (for version checking). */ 575 | ptrdiff_t size; 576 | 577 | /* Private data; users should not touch this. */ 578 | struct emacs_env_private *private_members; 579 | 580 | /* Memory management. */ 581 | 582 | emacs_value (*make_global_ref) (emacs_env *env, emacs_value value) 583 | EMACS_ATTRIBUTE_NONNULL(1); 584 | 585 | void (*free_global_ref) (emacs_env *env, emacs_value global_value) 586 | EMACS_ATTRIBUTE_NONNULL(1); 587 | 588 | /* Non-local exit handling. */ 589 | 590 | enum emacs_funcall_exit (*non_local_exit_check) (emacs_env *env) 591 | EMACS_ATTRIBUTE_NONNULL(1); 592 | 593 | void (*non_local_exit_clear) (emacs_env *env) 594 | EMACS_ATTRIBUTE_NONNULL(1); 595 | 596 | enum emacs_funcall_exit (*non_local_exit_get) 597 | (emacs_env *env, emacs_value *symbol, emacs_value *data) 598 | EMACS_ATTRIBUTE_NONNULL(1, 2, 3); 599 | 600 | void (*non_local_exit_signal) (emacs_env *env, 601 | emacs_value symbol, emacs_value data) 602 | EMACS_ATTRIBUTE_NONNULL(1); 603 | 604 | void (*non_local_exit_throw) (emacs_env *env, 605 | emacs_value tag, emacs_value value) 606 | EMACS_ATTRIBUTE_NONNULL(1); 607 | 608 | /* Function registration. */ 609 | 610 | emacs_value (*make_function) (emacs_env *env, 611 | ptrdiff_t min_arity, 612 | ptrdiff_t max_arity, 613 | emacs_value (*func) (emacs_env *env, 614 | ptrdiff_t nargs, 615 | emacs_value* args, 616 | void *data) 617 | EMACS_NOEXCEPT 618 | EMACS_ATTRIBUTE_NONNULL(1), 619 | const char *docstring, 620 | void *data) 621 | EMACS_ATTRIBUTE_NONNULL(1, 4); 622 | 623 | emacs_value (*funcall) (emacs_env *env, 624 | emacs_value func, 625 | ptrdiff_t nargs, 626 | emacs_value* args) 627 | EMACS_ATTRIBUTE_NONNULL(1); 628 | 629 | emacs_value (*intern) (emacs_env *env, const char *name) 630 | EMACS_ATTRIBUTE_NONNULL(1, 2); 631 | 632 | /* Type conversion. */ 633 | 634 | emacs_value (*type_of) (emacs_env *env, emacs_value arg) 635 | EMACS_ATTRIBUTE_NONNULL(1); 636 | 637 | bool (*is_not_nil) (emacs_env *env, emacs_value arg) 638 | EMACS_ATTRIBUTE_NONNULL(1); 639 | 640 | bool (*eq) (emacs_env *env, emacs_value a, emacs_value b) 641 | EMACS_ATTRIBUTE_NONNULL(1); 642 | 643 | intmax_t (*extract_integer) (emacs_env *env, emacs_value arg) 644 | EMACS_ATTRIBUTE_NONNULL(1); 645 | 646 | emacs_value (*make_integer) (emacs_env *env, intmax_t n) 647 | EMACS_ATTRIBUTE_NONNULL(1); 648 | 649 | double (*extract_float) (emacs_env *env, emacs_value arg) 650 | EMACS_ATTRIBUTE_NONNULL(1); 651 | 652 | emacs_value (*make_float) (emacs_env *env, double d) 653 | EMACS_ATTRIBUTE_NONNULL(1); 654 | 655 | /* Copy the content of the Lisp string VALUE to BUFFER as an utf8 656 | null-terminated string. 657 | 658 | SIZE must point to the total size of the buffer. If BUFFER is 659 | NULL or if SIZE is not big enough, write the required buffer size 660 | to SIZE and return true. 661 | 662 | Note that SIZE must include the last null byte (e.g. "abc" needs 663 | a buffer of size 4). 664 | 665 | Return true if the string was successfully copied. */ 666 | 667 | bool (*copy_string_contents) (emacs_env *env, 668 | emacs_value value, 669 | char *buf, 670 | ptrdiff_t *len) 671 | EMACS_ATTRIBUTE_NONNULL(1, 4); 672 | 673 | /* Create a Lisp string from a utf8 encoded string. */ 674 | emacs_value (*make_string) (emacs_env *env, 675 | const char *str, ptrdiff_t len) 676 | EMACS_ATTRIBUTE_NONNULL(1, 2); 677 | 678 | /* Embedded pointer type. */ 679 | emacs_value (*make_user_ptr) (emacs_env *env, 680 | void (*fin) (void *) EMACS_NOEXCEPT, 681 | void *ptr) 682 | EMACS_ATTRIBUTE_NONNULL(1); 683 | 684 | void *(*get_user_ptr) (emacs_env *env, emacs_value arg) 685 | EMACS_ATTRIBUTE_NONNULL(1); 686 | void (*set_user_ptr) (emacs_env *env, emacs_value arg, void *ptr) 687 | EMACS_ATTRIBUTE_NONNULL(1); 688 | 689 | void (*(*get_user_finalizer) (emacs_env *env, emacs_value uptr)) 690 | (void *) EMACS_NOEXCEPT EMACS_ATTRIBUTE_NONNULL(1); 691 | void (*set_user_finalizer) (emacs_env *env, emacs_value arg, 692 | void (*fin) (void *) EMACS_NOEXCEPT) 693 | EMACS_ATTRIBUTE_NONNULL(1); 694 | 695 | /* Vector functions. */ 696 | emacs_value (*vec_get) (emacs_env *env, emacs_value vector, ptrdiff_t index) 697 | EMACS_ATTRIBUTE_NONNULL(1); 698 | 699 | void (*vec_set) (emacs_env *env, emacs_value vector, ptrdiff_t index, 700 | emacs_value value) 701 | EMACS_ATTRIBUTE_NONNULL(1); 702 | 703 | ptrdiff_t (*vec_size) (emacs_env *env, emacs_value vector) 704 | EMACS_ATTRIBUTE_NONNULL(1); 705 | 706 | /* Returns whether a quit is pending. */ 707 | bool (*should_quit) (emacs_env *env) 708 | EMACS_ATTRIBUTE_NONNULL(1); 709 | 710 | /* Processes pending input events and returns whether the module 711 | function should quit. */ 712 | enum emacs_process_input_result (*process_input) (emacs_env *env) 713 | EMACS_ATTRIBUTE_NONNULL (1); 714 | 715 | struct timespec (*extract_time) (emacs_env *env, emacs_value arg) 716 | EMACS_ATTRIBUTE_NONNULL (1); 717 | 718 | emacs_value (*make_time) (emacs_env *env, struct timespec time) 719 | EMACS_ATTRIBUTE_NONNULL (1); 720 | 721 | bool (*extract_big_integer) (emacs_env *env, emacs_value arg, int *sign, 722 | ptrdiff_t *count, emacs_limb_t *magnitude) 723 | EMACS_ATTRIBUTE_NONNULL (1); 724 | 725 | emacs_value (*make_big_integer) (emacs_env *env, int sign, ptrdiff_t count, 726 | const emacs_limb_t *magnitude) 727 | EMACS_ATTRIBUTE_NONNULL (1); 728 | 729 | /* Add module environment functions newly added in Emacs 28 here. 730 | Before Emacs 28 is released, remove this comment and start 731 | module-env-29.h on the master branch. */ 732 | 733 | void (*(*EMACS_ATTRIBUTE_NONNULL (1) 734 | get_function_finalizer) (emacs_env *env, 735 | emacs_value arg)) (void *) EMACS_NOEXCEPT; 736 | 737 | void (*set_function_finalizer) (emacs_env *env, emacs_value arg, 738 | void (*fin) (void *) EMACS_NOEXCEPT) 739 | EMACS_ATTRIBUTE_NONNULL (1); 740 | 741 | int (*open_channel) (emacs_env *env, emacs_value pipe_process) 742 | EMACS_ATTRIBUTE_NONNULL (1); 743 | 744 | void (*make_interactive) (emacs_env *env, emacs_value function, 745 | emacs_value spec) 746 | EMACS_ATTRIBUTE_NONNULL (1); 747 | 748 | /* Create a unibyte Lisp string from a string. */ 749 | emacs_value (*make_unibyte_string) (emacs_env *env, 750 | const char *str, ptrdiff_t len) 751 | EMACS_ATTRIBUTE_NONNULL(1, 2); 752 | }; 753 | 754 | /* Every module should define a function as follows. */ 755 | extern int emacs_module_init (struct emacs_runtime *runtime) 756 | EMACS_NOEXCEPT 757 | EMACS_ATTRIBUTE_NONNULL (1); 758 | 759 | #ifdef __cplusplus 760 | } 761 | #endif 762 | 763 | #endif /* EMACS_MODULE_H */ 764 | -------------------------------------------------------------------------------- /img/mandel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finalpatch/ob-glsl/65148e0596a17e342646e8d1bac465e0ca7f31d0/img/mandel.png -------------------------------------------------------------------------------- /ob-glsl.el: -------------------------------------------------------------------------------- 1 | (require 'ob) 2 | (require 'ob-glsl-module) 3 | 4 | (defvar org-babel-default-header-args:glsl 5 | '((:results . "file") (:exports . "results")) 6 | "Default arguments to use when evaluating a glsl source block.") 7 | 8 | (defun org-babel-expand-body:glsl (body params) 9 | "Expand BODY according to PARAMS, return the expanded body." 10 | (concat 11 | "#version 330 core\n" 12 | "out vec4 fragColor;\n" 13 | "uniform vec2 iResolution;\n" 14 | body)) 15 | 16 | (defun org-babel-execute:glsl (body params) 17 | "Execute a block of glsl code with org-babel. 18 | This function is called by `org-babel-execute-src-block'." 19 | (let ((out-file (org-babel-process-file-name 20 | (cdr (or (assq :file params) 21 | (error "You need to specify a :file parameter"))) 22 | t)) 23 | (glsl-code (org-babel-expand-body:glsl body params)) 24 | (render-width (cdr (assq :width params))) 25 | (render-height (cdr (assq :height params)))) 26 | (if (and (not render-width) render-height) 27 | (setq render-width (* 4 (/ render-height 3)))) 28 | (if (and (not render-height) render-width) 29 | (setq render-height (* 3 (/ render-width 4)))) 30 | (if (and (not render-width) (not render-height)) 31 | (setq render-width 400 render-height 300)) 32 | (ob-glsl-run glsl-code render-width render-height out-file) 33 | nil)) 34 | 35 | (defun org-babel-prep-session:shady (_session _params) 36 | "Return an error because glsl does not support sessions." 37 | (error "glsl does not support sessions")) 38 | 39 | (provide 'ob-glsl) 40 | --------------------------------------------------------------------------------