// ---- // glsl // ---- // -------------------- // Emacs dynamic module // -------------------- 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 nas 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; } // sdl_glsl_init nargs = 0; emacs_value sdl_glsl_init_func = env->make_function (env, nargs, nargs, sdl_glsl_init, "GLSL init.", NULL); emacs_value sdl_glsl_init_symb = env->intern (env, "sdl_glsl_init"); emacs_value sdl_glsl_init_args [] = { sdl_glsl_init_symb, sdl_glsl_init_func }; env->funcall (env, env->intern (env, "defalias"), 2, sdl_glsl_init_args); // sdl_glsl_quit nargs = 0; emacs_value sdl_glsl_quit_func = env->make_function (env, nargs, nargs, sdl_glsl_quit, "GLSL quit.", NULL); emacs_value sdl_glsl_quit_symb = env->intern (env, "sdl_glsl_quit"); emacs_value sdl_glsl_quit_args [] = { sdl_glsl_quit_symb, sdl_glsl_quit_func }; env->funcall (env, env->intern (env, "defalias"), 2, sdl_glsl_quit_args); // sdl_glsl_clear nargs = 0; emacs_value sdl_glsl_clear_func = env->make_function (env, nargs, nargs, sdl_glsl_clear, "GLSL clear.", NULL); emacs_value sdl_glsl_clear_symb = env->intern (env, "sdl_glsl_clear"); emacs_value sdl_glsl_clear_args [] = { sdl_glsl_clear_symb, sdl_glsl_clear_func }; env->funcall (env, env->intern (env, "defalias"), 2, sdl_glsl_clear_args); // sdl_glsl_swap nargs = 0; emacs_value sdl_glsl_swap_func = env->make_function (env, nargs, nargs, sdl_glsl_swap, "GLSL swap.", NULL); emacs_value sdl_glsl_swap_symb = env->intern (env, "sdl_glsl_swap"); emacs_value sdl_glsl_swap_args [] = { sdl_glsl_swap_symb, sdl_glsl_swap_func }; env->funcall (env, env->intern (env, "defalias"), 2, sdl_glsl_swap_args); // sdl_glsl_triangle nargs = 25; emacs_value sdl_glsl_triangle_func = env->make_function (env, nargs, nargs, sdl_glsl_triangle, "GLSL triangle.", NULL); emacs_value sdl_glsl_triangle_symb = env->intern (env, "sdl_glsl_triangle"); emacs_value sdl_glsl_triangle_args [] = { sdl_glsl_triangle_symb, sdl_glsl_triangle_func }; env->funcall (env, env->intern (env, "defalias"), 2, sdl_glsl_triangle_args); // sdl_glsl_update nargs = 3; emacs_value sdl_glsl_update_func = env->make_function (env, nargs, nargs, sdl_glsl_update, "GLSL update.", NULL); emacs_value sdl_glsl_update_symb = env->intern (env, "sdl_glsl_update"); emacs_value sdl_glsl_update_args [] = { sdl_glsl_update_symb, sdl_glsl_update_func }; env->funcall (env, env->intern (env, "defalias"), 2, sdl_glsl_update_args); // emacs (glsl draw) emacs_value sdl_glsl_init (emacs_env*, ptrdiff_t, emacs_value*, void*); emacs_value sdl_glsl_update (emacs_env*, ptrdiff_t, emacs_value*, void*); emacs_value sdl_glsl_clear (emacs_env*, ptrdiff_t, emacs_value*, void*); emacs_value sdl_glsl_triangle (emacs_env*, ptrdiff_t, emacs_value*, void*); emacs_value sdl_glsl_swap (emacs_env*, ptrdiff_t, emacs_value*, void*); emacs_value sdl_glsl_quit (emacs_env*, ptrdiff_t, emacs_value*, void*); // glsl GLuint glsl_compile_shader (GLenum, const char*); void glsl_init (); void glsl_clear (); void glsl_update (float*, float*, float*); vector normalize_vector (vector); vector cross_product (vector, vector); void glsl_triangle (vector, vector, vector, SDL_FColor, SDL_FColor, SDL_FColor, vector, float, SDL_FPoint, SDL_FPoint, SDL_FPoint); void glsl_swap (); void glsl_quit (); void glsl_init_tex (int n, const char* file_path); void glsl_quit_tex (); static SDL_GLContext ctx; static GLuint prg; static GLuint VAO; static GLuint VBO; emacs_value sdl_glsl_update (emacs_env* env, ptrdiff_t nargs, emacs_value* args, void* data nas) { SDL_assert (env); SDL_assert (nargs == 3); SDL_assert (args); const int size = 16; float P [size]; float V [size]; float M [size]; for (int i = 0; i < size; i++) { P [i] = env->extract_float (env, env->vec_get (env, args [0], i)); V [i] = env->extract_float (env, env->vec_get (env, args [1], i)); M [i] = env->extract_float (env, env->vec_get (env, args [2], i)); } glUniformMatrix4fv (glGetUniformLocation (prg, "P"), 1, GL_FALSE, P); glUniformMatrix4fv (glGetUniformLocation (prg, "V"), 1, GL_FALSE, V); glUniformMatrix4fv (glGetUniformLocation (prg, "M"), 1, GL_FALSE, M); return env->intern (env, "nil"); } const char* vert_shader_src = "#version 460 core \n" "layout (location = 0) in vec3 v_pos ; \n" "layout (location = 1) in vec3 v_col ; \n" "layout (location = 2) in vec3 v_nor ; \n" "layout (location = 3) in vec2 v_uv ; \n" " out vec4 f_pos ; \n" " out vec3 f_col ; \n" " out vec3 f_nor ; \n" " out vec2 f_uv ; \n" " uniform mat4 P ; \n" " uniform mat4 V ; \n" " uniform mat4 M ; \n" "void main () { \n" " f_pos = P * V * M * vec4 (v_pos, 1.0) ; \n" " f_col = v_col ; \n" " f_nor = v_nor ; \n" " f_uv = v_uv ; \n" " gl_Position = f_pos ; \n" "} \n"; const char* frag_shader_src = "#version 460 core \n" "in vec4 f_pos ; \n" "in vec3 f_col ; \n" "in vec3 f_nor ; \n" "in vec2 f_uv ; \n" "out vec4 o_col ; \n" "uniform sampler2D u_tex ; \n" "uniform float u_sec ; \n" "void main () { \n" " vec4 tex = texture (u_tex, f_uv) ; \n" " o_col.rgb = pow (tex.rgb, vec3 (0.88)) ; \n" " o_col += vec4 (f_col, 1.0) * 0.02 ; \n" " o_col.a = 0.88 ; \n" "} \n"; GLuint glsl_compile_shader (GLenum type, const char* src) { GLuint shader = glCreateShader (type); glShaderSource (shader, 1, &src, NULL); glCompileShader (shader); GLint ok; glGetShaderiv (shader, GL_COMPILE_STATUS, &ok); if (ok) { SDL_Log ("shader compile .... ok"); } else { char log [SHADER_INFO_LOG_SIZE]; glGetShaderInfoLog(shader, SHADER_INFO_LOG_SIZE, NULL, log); SDL_Log ("compile error ..... %s", log); glsl_quit (); } return shader; } emacs_value sdl_glsl_init (emacs_env* env, ptrdiff_t nargs, emacs_value* args nas, void* data nas) { SDL_assert (env); SDL_assert (nargs == 0); glsl_init (); return env->intern (env, "nil"); } emacs_value sdl_glsl_quit (emacs_env* env, ptrdiff_t nargs, emacs_value* args nas, void* data nas) { SDL_assert (env); SDL_assert (nargs == 0); glsl_quit (); return env->intern (env, "nil"); } emacs_value sdl_glsl_swap (emacs_env* env, ptrdiff_t nargs, emacs_value* args nas, void* data nas) { SDL_assert (env); SDL_assert (nargs == 0); glsl_swap (); return env->intern (env, "nil"); } emacs_value sdl_glsl_clear (emacs_env* env, ptrdiff_t nargs, emacs_value* args nas, void* data nas) { SDL_assert (env); SDL_assert (nargs == 0); glsl_clear (); return env->intern (env, "nil"); } emacs_value sdl_glsl_triangle (emacs_env* env, ptrdiff_t nargs, emacs_value* args nas, void* data nas) { SDL_assert (env); SDL_assert (nargs == 25); SDL_assert (args); // coords float x0 = env->extract_float (env, args [ 0]); float y0 = env->extract_float (env, args [ 1]); float z0 = env->extract_float (env, args [ 2]); float x1 = env->extract_float (env, args [ 3]); float y1 = env->extract_float (env, args [ 4]); float z1 = env->extract_float (env, args [ 5]); float x2 = env->extract_float (env, args [ 6]); float y2 = env->extract_float (env, args [ 7]); float z2 = env->extract_float (env, args [ 8]); // color float r0 = env->extract_float (env, args [ 9]); float g0 = env->extract_float (env, args [10]); float b0 = env->extract_float (env, args [11]); float a0 = 1.0f; float r1 = env->extract_float (env, args [12]); float g1 = env->extract_float (env, args [13]); float b1 = env->extract_float (env, args [14]); float a1 = 1.0f; float r2 = env->extract_float (env, args [15]); float g2 = env->extract_float (env, args [16]); float b2 = env->extract_float (env, args [17]); float a2 = 1.0f; // tex float tex = env->extract_float (env, args [18]); // uv float uv0x = env->extract_float (env, args [19]); float uv0y = env->extract_float (env, args [20]); float uv1x = env->extract_float (env, args [21]); float uv1y = env->extract_float (env, args [22]); float uv2x = env->extract_float (env, args [23]); float uv2y = env->extract_float (env, args [24]); // as vectors and colors and uvs vector v0 = { .x = x0, .y = y0, .z = z0 }; vector v1 = { .x = x1, .y = y1, .z = z1 }; vector v2 = { .x = x2, .y = y2, .z = z2 }; SDL_FColor c0 = { .r = r0, .g = g0, .b = b0, .a = a0 }; SDL_FColor c1 = { .r = r1, .g = g1, .b = b1, .a = a1 }; SDL_FColor c2 = { .r = r2, .g = g2, .b = b2, .a = a2 }; SDL_FPoint uv0 = { .x = uv0x, .y = uv0y }; SDL_FPoint uv1 = { .x = uv1x, .y = uv1y }; SDL_FPoint uv2 = { .x = uv2x, .y = uv2y }; // verify color SDL_assert (0.0f <= c0.r); SDL_assert (0.0f <= c0.g); SDL_assert (0.0f <= c0.b); SDL_assert (0.0f <= c0.a); SDL_assert (0.0f <= c1.r); SDL_assert (0.0f <= c1.g); SDL_assert (0.0f <= c1.b); SDL_assert (0.0f <= c1.a); SDL_assert (0.0f <= c2.r); SDL_assert (0.0f <= c2.g); SDL_assert (0.0f <= c2.b); SDL_assert (0.0f <= c2.a); // normal vector a = { .x = x2 - x0, .y = y2 - y0, .z = z2 - z0 }; vector b = { .x = x1 - x0, .y = y1 - y0, .z = z1 - z0 }; vector v = normalize_vector (cross_product (b, a)); // done glsl_triangle (v0, v1, v2, c0, c1, c2, v, tex, uv0, uv1, uv2); return env->intern (env, "nil"); } vector cross_product (vector a, vector b) { vector v = { .x = (a.y * b.z) - (a.z * b.y), .y = (a.z * b.x) - (a.x * b.z), .z = (a.x * b.y) - (a.y * b.x) }; return v; } vector normalize_vector (vector a) { float mag = SDL_sqrt (1.0f / (SDL_pow (a.x, 2) + SDL_pow (a.y, 2) + SDL_pow (a.z, 2))); vector v = { .x = a.x * mag, .y = a.y * mag, .z = a.z * mag }; return v; } void glsl_init () { // sdl3 SDL_Init (SDL_INIT_VIDEO); // window int w = 1920; int h = 1080; win = SDL_CreateWindow ("bad-el 6 GNU Emacs 31 SDL3 OpenGL GLSL 4.6", w, h, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_TRANSPARENT); ctx = SDL_GL_CreateContext (win); glewInit (); // version int major; int minor; glGetIntegerv (GL_MAJOR_VERSION, &major); glGetIntegerv (GL_MINOR_VERSION, &minor); SDL_Log ("OpenGL version .... %d.%d", major, minor); SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, major); SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, minor); SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); // shaders GLuint vs = glsl_compile_shader (GL_VERTEX_SHADER, vert_shader_src); GLuint fs = glsl_compile_shader (GL_FRAGMENT_SHADER, frag_shader_src); // program prg = glCreateProgram(); glAttachShader (prg, vs); glAttachShader (prg, fs); // link glLinkProgram (prg); GLint linked; glGetProgramiv (prg, GL_LINK_STATUS, &linked); if (linked) { SDL_Log ("linking ........... ok"); } else { char log [SHADER_INFO_LOG_SIZE]; glGetProgramInfoLog (prg, SHADER_INFO_LOG_SIZE, NULL, log); SDL_Log ("linking failure ... %s", log); glsl_quit (); } // done glDetachShader (prg, vs); glDetachShader (prg, fs); glDeleteShader (vs); glDeleteShader (fs); // almost glGenVertexArrays (1, &VAO); glGenBuffers (1, &VBO); // settings glClearColor (0.0f, 0.0f, 0.0f, 0.0f); glFrontFace (GL_CW); glCullFace (GL_FRONT); glEnable (GL_CULL_FACE); glEnable (GL_DEPTH_TEST); glEnable (GL_BLEND); // texture glsl_init_tex (0, "data/src.webp"); // almost glUseProgram (prg); glBindVertexArray (VAO); // done GLenum init_err = glGetError (); if (init_err == GL_NO_ERROR) { SDL_Log ("init .............. ok"); } else { SDL_Log ("init error ........ %d", init_err); } } void glsl_quit () { glsl_quit_tex (); glDeleteVertexArrays (1, &VAO); glDeleteBuffers (1, &VBO); glDeleteProgram (prg); SDL_GL_DestroyContext (ctx); SDL_DestroyWindow (win); SDL_Quit (); } void glsl_clear () { glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } void glsl_swap () { SDL_GL_SwapWindow (win); } void glsl_triangle (vector p0, vector p1, vector p2, SDL_FColor c0, SDL_FColor c1, SDL_FColor c2, vector nrml, float tex, SDL_FPoint uv0, SDL_FPoint uv1, SDL_FPoint uv2) { float vert [] = { p0.x, p0.y, p0.z, c0.r, c0.g, c0.b, nrml.x, nrml.y, nrml.z, uv0.x, uv0.y, p1.x, p1.y, p1.z, c1.r, c1.g, c1.b, nrml.x, nrml.y, nrml.z, uv1.x, uv1.y, p2.x, p2.y, p2.z, c2.r, c2.g, c2.b, nrml.x, nrml.y, nrml.z, uv2.x, uv2.y }; if (0.0f != tex) { glUniform1i (glGetUniformLocation (prg, "u_tex"), 0); } glUniform1f (glGetUniformLocation (prg, "u_sec"), SDL_GetTicks ()); glBindBuffer (GL_ARRAY_BUFFER, VBO); glBufferData (GL_ARRAY_BUFFER, sizeof (vert), vert, GL_STREAM_DRAW); glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, sizeof (vert) / 3, (void*) 0) ; glEnableVertexAttribArray (0); glVertexAttribPointer (1, 3, GL_FLOAT, GL_FALSE, sizeof (vert) / 3, (void*) (3 * sizeof (float))) ; glEnableVertexAttribArray (1); glVertexAttribPointer (2, 3, GL_FLOAT, GL_FALSE, sizeof (vert) / 3, (void*) (6 * sizeof (float))) ; glEnableVertexAttribArray (2); glVertexAttribPointer (3, 2, GL_FLOAT, GL_FALSE, sizeof (vert) / 3, (void*) (9 * sizeof (float))) ; glEnableVertexAttribArray (3); glDrawArrays (GL_TRIANGLES, 0, 3); } // ---- // tex // ---- #define IMG_SURS_NUM 256 static SDL_Surface* img_surs [IMG_SURS_NUM] = {NULL}; static GLuint img_tex = unset32; void glsl_quit_tex () { for (int i = 0; i < IMG_SURS_NUM; i++) { if (img_surs [i]) { SDL_DestroySurface (img_surs [i]); img_surs [i] = NULL; surfaces_destroyed++; } } } void glsl_init_tex (int n, const char* file_path) { SDL_assert ((0 <= n) && (n < IMG_SURS_NUM)); SDL_assert (file_path); img_surs [n] = IMG_Load (file_path); if (img_surs [n]) { bool verbose = (n == 0); if (verbose) { SDL_Log ("image file ........ ok"); } surfaces_created++; int w = img_surs [n] -> w; int h = img_surs [n] -> h; void* pxls = img_surs [n] -> pixels; glActiveTexture (GL_TEXTURE0); glBindTexture (GL_TEXTURE_2D, img_tex); glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, pxls); glGenerateMipmap (GL_TEXTURE_2D); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f); if (verbose) { SDL_Log ("mipmap ............ ok"); } } else { SDL_Log ("image ............. error: slot %d, file path %s", n, file_path); } }