summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-11-03 19:48:26 -0400
committerpommicket <pommicket@gmail.com>2022-11-03 19:48:26 -0400
commit7a2b3ea8c13657ef697d0b4dc73ccada23f81039 (patch)
tree0b3702b9bce4536047525d2f472a937d6e06d039
parent4d995edfdde5953bc5669c54b1194be40a3641f2 (diff)
custom shader texture
-rw-r--r--config.c32
-rw-r--r--gl.c54
-rw-r--r--main.c10
-rw-r--r--ted.cfg4
-rw-r--r--ted.h17
-rw-r--r--util.c1
6 files changed, 111 insertions, 7 deletions
diff --git a/config.c b/config.c
index 3ac9b18..1265eaf 100644
--- a/config.c
+++ b/config.c
@@ -45,6 +45,7 @@ static void settings_copy(Settings *dest, const Settings *src) {
*dest = *src;
gl_rc_sab_incref(dest->bg_shader);
+ gl_rc_texture_incref(dest->bg_texture);
context_copy(&dest->context, &src->context);
for (u32 i = 0; i < LANG_COUNT; ++i) {
@@ -258,7 +259,7 @@ static OptionU8 const options_u8[] = {
{"tags-max-depth", &options_zero.tags_max_depth, 1, 100, false},
};
static OptionU16 const options_u16[] = {
- {"text-size", &options_zero.text_size, TEXT_SIZE_MIN, TEXT_SIZE_MAX, true},
+ {"text-size", &options_zero.text_size, TEXT_SIZE_MIN, TEXT_SIZE_MAX, false},
{"max-menu-width", &options_zero.max_menu_width, 10, U16_MAX, false},
{"error-display-time", &options_zero.error_display_time, 0, U16_MAX, false},
};
@@ -573,10 +574,11 @@ void main() { \n\
uniform float t_time;\n\
uniform float t_save_time;\n\
uniform vec2 t_aspect;\n\
+uniform sampler2D t_texture;\n\
#line 1\n\
%s", s->bg_shader_text);
- if (s->bg_shader) gl_rc_sab_decref(&s->bg_shader);
+ gl_rc_sab_decref(&s->bg_shader);
GLuint shader = gl_compile_and_link_shaders(ted->error, vshader, fshader);
if (shader) {
@@ -607,6 +609,26 @@ uniform vec2 t_aspect;\n\
}
}
+static void settings_load_bg_texture(Ted *ted, Settings *s) {
+ gl_rc_texture_decref(&s->bg_texture);
+
+ const char *path = s->bg_shader_image;
+ char expanded[TED_PATH_MAX];
+ expanded[0] = '\0';
+ if (path[0] == '~') {
+ strbuf_cpy(expanded, ted->home);
+ ++path;
+ }
+ strbuf_cat(expanded, path);
+
+ GLuint texture = gl_load_texture_from_image(expanded);
+ if (texture) {
+ s->bg_texture = gl_rc_texture_new(texture);
+ } else {
+ ted_seterr(ted, "Couldn't load image %s", path);
+ }
+}
+
// reads a single "line" of the config file, but it may include a multiline string,
// so it may read multiple lines.
static void config_parse_line(ConfigReader *cfg, Settings *settings, const ConfigPart *part, char **pline) {
@@ -832,9 +854,10 @@ static void config_parse_line(ConfigReader *cfg, Settings *settings, const Confi
}
}
- if (streq(key, "bg-shader")) {
+ if (streq(key, "bg-shader"))
settings_load_bg_shader(ted, settings);
- }
+ if (streq(key, "bg-texture"))
+ settings_load_bg_texture(ted, settings);
// this is probably a bad idea:
//if (!recognized)
@@ -952,6 +975,7 @@ void config_free(Ted *ted) {
for (u32 i = 0; i < LANG_COUNT; ++i)
free(settings->language_extensions[i]);
gl_rc_sab_decref(&settings->bg_shader);
+ gl_rc_texture_decref(&settings->bg_texture);
}
diff --git a/gl.c b/gl.c
index c16d252..1c41d54 100644
--- a/gl.c
+++ b/gl.c
@@ -5,6 +5,7 @@
do(DRAWARRAYS, DrawArrays)\
do(GENTEXTURES, GenTextures)\
do(DELETETEXTURES, DeleteTextures)\
+ do(GENERATEMIPMAP, GenerateMipmap)\
do(TEXIMAGE2D, TexImage2D)\
do(BINDTEXTURE, BindTexture)\
do(TEXPARAMETERI, TexParameteri)\
@@ -87,6 +88,29 @@ void gl_rc_sab_decref(GlRcSAB **ps) {
*ps = NULL;
}
+GlRcTexture *gl_rc_texture_new(GLuint texture) {
+ GlRcTexture *t = calloc(1, sizeof *t);
+ t->ref_count = 1;
+ t->texture = texture;
+ return t;
+}
+
+void gl_rc_texture_incref(GlRcTexture *t) {
+ if (!t) return;
+ ++t->ref_count;
+}
+
+void gl_rc_texture_decref(GlRcTexture **pt) {
+ GlRcTexture *t = *pt;
+ if (!t) return;
+ if (--t->ref_count == 0) {
+ debug_println("Delete texture %u", t->texture);
+ glDeleteTextures(1, &t->texture);
+ free(t);
+ }
+ *pt = NULL;
+}
+
// set by main()
static int gl_version_major;
static int gl_version_minor;
@@ -305,3 +329,33 @@ static void gl_geometry_draw(void) {
arr_clear(gl_geometry_triangles);
}
+
+static GLuint gl_load_texture_from_image(const char *path) {
+ GLuint texture = 0;
+ int w=0, h=0, n=0;
+ unsigned char *data = stbi_load(path, &w, &h, &n, 4);
+ if (data && w > 0 && h > 0) {
+ size_t bytes_per_row = (size_t)w * 4;
+ unsigned char *tempbuf = calloc(1, bytes_per_row);
+ // flip image vertically
+ for (int y = 0; y < h/2; ++y) {
+ int y2 = h-1-y;
+ unsigned char *row1 = &data[y*w*4];
+ unsigned char *row2 = &data[y2*w*4];
+ memcpy(tempbuf, row1, bytes_per_row);
+ memcpy(row1, row2, bytes_per_row);
+ memcpy(row2, tempbuf, bytes_per_row);
+ }
+ free(tempbuf);
+
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ free(data);
+ }
+ return texture;
+}
diff --git a/main.c b/main.c
index 8fc0ca3..dbc49d5 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,5 @@
/*
FUTURE FEATURES:
-- custom shaders texture
- config variables
- plugins?
*/
@@ -811,6 +810,15 @@ int main(int argc, char **argv) {
glUniform1f(glGetUniformLocation(shader, "t_time"), (float)fmod(t - start_time, 3600));
glUniform2f(glGetUniformLocation(shader, "t_aspect"), (float)window_width / (float)window_height, 1);
glUniform1f(glGetUniformLocation(shader, "t_save_time"), (float)(t - ted->last_save_time));
+ if (s->bg_texture) {
+ GLuint texture = s->bg_texture->texture;
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glUniform1i(glGetUniformLocation(shader, "t_texture"), 0);
+ } else {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
glBindBuffer(GL_ARRAY_BUFFER, buffer);
if (!array) {
GLuint v_pos = (GLuint)glGetAttribLocation(shader, "v_pos");
diff --git a/ted.cfg b/ted.cfg
index 0c142b1..4b815f6 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -42,6 +42,7 @@ regenerate-tags-if-not-found = yes
# t_aspect - (window_width / window_height, 1)
# t_time - current time in seconds, modulo 3600
# t_save_time - time since last save, in seconds.
+# t_texture - a texture, made with your choice of image
# if you want your shader supported no matter what, only use stuff from GLSL version 110.
# on non-ancient computers, you should be able to use GLSL version 130.
# bg-shader = "void main() {
@@ -51,6 +52,9 @@ regenerate-tags-if-not-found = yes
# vec4 color = vec4(r, g, 1.0 - t_save_time, 0.2);
# gl_FragColor = clamp(color, 0.0, 1.0);
# }"
+# here's an example using a texture:
+# bg-texture = "/path/to/my/cool/picture.jpg" (or .png, .gif, .bmp)
+# bg-shader = "void main() { gl_FragColor = texture2D(t_texture, t_pos) * vec4(1.0,1.0,1.0,0.2); }"
[keyboard]
# motion and selection
diff --git a/ted.h b/ted.h
index bbd2d48..3db5a3c 100644
--- a/ted.h
+++ b/ted.h
@@ -143,9 +143,21 @@ typedef struct {
char *path; // these settings apply to all paths which start with this string, or all paths if path=NULL
} SettingsContext;
-// shader-array-buffer combo.
// need to use refcounting for this because of Settings.
-// (we copy parent settings to children)
+// => we copy parent settings to children
+// e.g.
+// [core]
+// bg-texture = "blablabla.png"
+// [Javascript.core]
+// some random shit
+// the main Settings' bg_texture will get copied to javascript's Settings,
+// so we need to be extra careful about when we delete textures.
+typedef struct {
+ u32 ref_count;
+ u32 texture;
+} GlRcTexture;
+
+// shader-array-buffer combo.
typedef struct {
u32 ref_count;
u32 shader;
@@ -177,6 +189,7 @@ typedef struct {
u8 scrolloff;
u8 tags_max_depth;
GlRcSAB *bg_shader;
+ GlRcTexture *bg_texture;
char bg_shader_text[4096];
char bg_shader_image[TED_PATH_MAX];
char build_default_command[256];
diff --git a/util.c b/util.c
index 57b54da..cee9cc3 100644
--- a/util.c
+++ b/util.c
@@ -150,6 +150,7 @@ static void str_cpy(char *dst, size_t dst_sz, char const *src) {
}
#define strbuf_cpy(dst, src) str_cpy(dst, sizeof dst, src)
+#define strbuf_cat(dst, src) str_cat(dst, sizeof dst, src)
// advances str to the start of the next UTF8 character
static void utf8_next_char_const(char const **str) {