aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakamichi Horikawa <takamichiho@gmail.com>2017-04-04 23:57:39 +0900
committerTakamichi Horikawa <takamichiho@gmail.com>2017-04-04 23:57:39 +0900
commitc6c96944ae1bb1d7363349ec21be9dca76ee9ec4 (patch)
tree287881e3661707b1a5185ef8dd1e24c866db0636
parent4c68a0d48bf2fa49c7a20e728ebf8c0dde073b5c (diff)
gtk: add Oscilloscope view OpenGL renderer
-rw-r--r--gtk/Makefile.am7
-rw-r--r--gtk/configure.ac13
-rw-r--r--gtk/oscilloview-gl.c170
-rw-r--r--gtk/oscilloview.c11
4 files changed, 193 insertions, 8 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 0247644..3524f15 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -42,7 +42,6 @@ endif
fmplayer_SOURCES=main.c \
toneview.c \
- oscilloview.c \
../tonedata/tonedata.c \
../common/fmplayer_file.c \
../common/fmplayer_file_gio.c \
@@ -50,3 +49,9 @@ fmplayer_SOURCES=main.c \
$(FMDRIVER_SRC) \
$(FMDSP_SRC)
+if ENABLE_OPENGL
+fmplayer_SOURCES+=oscilloview-gl.c
+fmplayer_LDADD+=-lGL
+else
+fmplayer_SOURCES+=oscilloview.c
+endif
diff --git a/gtk/configure.ac b/gtk/configure.ac
index f49bd74..79d02c1 100644
--- a/gtk/configure.ac
+++ b/gtk/configure.ac
@@ -22,5 +22,18 @@ AS_IF([test "x$emmintrin_found" = "xyes"], [
AC_DEFINE([ENABLE_SSE])
])
+AC_ARG_ENABLE([opengl], AS_HELP_STRING([--enable-opengl], [Enable OpenGL rendering for Oscilloscope view (default: enable if found)]))
+AS_IF([test "x$enable_opengl" != "xno"], [
+ AC_CHECK_LIB([GL], [glGetString], [opengl_found=yes])
+ AC_CHECK_HEADER([GL/glcorearb.h], , [opengl_found=])
+ AS_IF([test "x$enable_opengl" = "x" -a "x$opengl_found" = "xyes"], [
+ enable_opengl=yes
+ ])
+ AS_IF([test "x$enable_opengl" = "xyes" -a "x$opengl_found" != "xyes"], [
+ AC_MSG_ERROR([OpenGL header/library not found (-lGL, GL/glcorearb.h)], [1])
+ ])
+])
+AM_CONDITIONAL([ENABLE_OPENGL], [test "x$enable_opengl" = "xyes"])
+
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
diff --git a/gtk/oscilloview-gl.c b/gtk/oscilloview-gl.c
new file mode 100644
index 0000000..b67bdce
--- /dev/null
+++ b/gtk/oscilloview-gl.c
@@ -0,0 +1,170 @@
+#include <gtk/gtk.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glcorearb.h>
+#include <stdlib.h>
+#include <string.h>
+#include "oscilloview.h"
+
+struct oscilloview oscilloview_g = {
+ .flag = ATOMIC_FLAG_INIT
+};
+
+enum {
+ VIEW_SAMPLES = 1024,
+};
+
+static struct {
+ GtkWidget *win;
+ struct oscillodata oscillodata[LIBOPNA_OSCILLO_TRACK_COUNT];
+ GLuint program;
+ GLuint vs, fs;
+ GLuint vao;
+ GLuint vbo_linear;
+ GLuint vbo_data;
+ GLint uni_xpos;
+ GLint uni_ypos;
+} g;
+
+static void on_glarea_unrealize(GtkWidget *w, gpointer ptr) {
+ (void)w;
+ GtkGLArea *area = GTK_GL_AREA(w);
+ gtk_gl_area_make_current(area);
+ if (gtk_gl_area_get_error(area)) return;
+ glDeleteProgram(g.program);
+ glDeleteShader(g.vs);
+ glDeleteShader(g.fs);
+ glDeleteBuffers(1, &g.vbo_linear);
+ glDeleteBuffers(1, &g.vbo_data);
+ glDeleteVertexArrays(1, &g.vao);
+}
+
+static void on_destroy(GtkWidget *w, gpointer ptr) {
+ (void)w;
+ (void)ptr;
+ g.win = 0;
+}
+
+static const char v_sh[] =
+"#version 110\n"
+"attribute float coordx, coordy;\n"
+"uniform float xpos, ypos;\n"
+"void main(void) {\n"
+" gl_Position = vec4(vec2(coordx/3.0 + xpos, coordy*2.0/3.0 + ypos), 0.0, 1.0);\n"
+"}\n";
+
+static const char f_sh[] =
+"#version 110\n"
+"void main(void) {\n"
+" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
+"}\n";
+
+static GLuint create_shader(const char *shader, GLenum type) {
+ GLuint s = glCreateShader(type);
+ glShaderSource(s, 1, &shader, 0);
+ glCompileShader(s);
+ GLint ok;
+ glGetShaderiv(s, GL_COMPILE_STATUS, &ok);
+ if (!ok) {
+ GLint len;
+ glGetShaderiv(s, GL_INFO_LOG_LENGTH, &len);
+ if (len > 0) {
+ char *log = malloc(len);
+ if (log) {
+ glGetShaderInfoLog(s, len, 0, log);
+ printf("%s shader error: \n%s\n",
+ (type == GL_VERTEX_SHADER) ? "vertex" : "fragment",
+ log);
+ free(log);
+ }
+ }
+ glDeleteShader(s);
+ return 0;
+ }
+ return s;
+}
+
+static void on_realize(GtkWidget *w, gpointer ptr) {
+ (void)ptr;
+ GtkGLArea *area = GTK_GL_AREA(w);
+ gtk_gl_area_make_current(area);
+ if (gtk_gl_area_get_error(area)) return;
+ g.program = glCreateProgram();
+ g.vs = create_shader(v_sh, GL_VERTEX_SHADER);
+ g.fs = create_shader(f_sh, GL_FRAGMENT_SHADER);
+ glAttachShader(g.program, g.vs);
+ glAttachShader(g.program, g.fs);
+ glBindAttribLocation(g.program, 0, "coordx");
+ glBindAttribLocation(g.program, 1, "coordy");
+ glLinkProgram(g.program);
+ glUseProgram(g.program);
+ g.uni_xpos = glGetUniformLocation(g.program, "xpos");
+ g.uni_ypos = glGetUniformLocation(g.program, "ypos");
+ glGenVertexArrays(1, &g.vao);
+ glBindVertexArray(g.vao);
+ glGenBuffers(1, &g.vbo_linear);
+ glBindBuffer(GL_ARRAY_BUFFER, g.vbo_linear);
+ static GLfloat linear_pos[VIEW_SAMPLES];
+ for (int i = 0; i < VIEW_SAMPLES; i++) {
+ linear_pos[i] = 2.0f*((i-512) / (float)VIEW_SAMPLES);
+ }
+ glBufferData(GL_ARRAY_BUFFER, sizeof(linear_pos), linear_pos, GL_STATIC_DRAW);
+ glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, 0);
+ glGenBuffers(1, &g.vbo_data);
+ glBindBuffer(GL_ARRAY_BUFFER, g.vbo_data);
+ glBufferData(GL_ARRAY_BUFFER, 2*VIEW_SAMPLES, 0, GL_STREAM_DRAW);
+ glVertexAttribPointer(1, 1, GL_SHORT, GL_TRUE, 0, 0);
+}
+
+static gboolean on_render(GtkGLArea *area,
+ GdkGLContext *ctx,
+ gpointer ptr) {
+ (void)ptr;
+ if (!atomic_flag_test_and_set_explicit(
+ &oscilloview_g.flag, memory_order_acquire)) {
+ memcpy(g.oscillodata,
+ oscilloview_g.oscillodata,
+ sizeof(oscilloview_g.oscillodata));
+ atomic_flag_clear_explicit(&oscilloview_g.flag, memory_order_release);
+ }
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ for (int x = 0; x < 3; x++) {
+ for (int y = 0; y < 3; y++) {
+ int start = OSCILLO_SAMPLE_COUNT - VIEW_SAMPLES;
+ start -= (g.oscillodata[x*3+y].offset >> OSCILLO_OFFSET_SHIFT);
+ glBindBuffer(GL_ARRAY_BUFFER, g.vbo_data);
+ glBufferData(GL_ARRAY_BUFFER, 2*VIEW_SAMPLES, &g.oscillodata[x*3+y].buf[start], GL_STREAM_DRAW);
+ glUniform1f(g.uni_xpos, (x - 1) * (2.0f/3.0f));
+ glUniform1f(g.uni_ypos, (y - 1) * (-2.0f/3.0f));
+ glDrawArrays(GL_LINE_STRIP, 0, 1024);
+ }
+ }
+ glDisableVertexAttribArray(0);
+ glDisableVertexAttribArray(1);
+ return TRUE;
+}
+
+static gboolean tick_cb(GtkWidget *w, GdkFrameClock *clock, gpointer ptr) {
+ (void)clock;
+ (void)ptr;
+ gtk_widget_queue_draw(w);
+ return G_SOURCE_CONTINUE;
+}
+
+void show_oscilloview(void) {
+ if (!g.win) {
+ g.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(g.win), "Oscilloscope view");
+ g_signal_connect(g.win, "destroy", G_CALLBACK(on_destroy), 0);
+ GtkWidget *glarea = gtk_gl_area_new();
+ g_signal_connect(G_OBJECT(glarea), "unrealize", G_CALLBACK(on_glarea_unrealize), 0);
+ gtk_gl_area_set_required_version(GTK_GL_AREA(glarea), 3, 2);
+ g_signal_connect(glarea, "render", G_CALLBACK(on_render), 0);
+ g_signal_connect(glarea, "realize", G_CALLBACK(on_realize), 0);
+ gtk_container_add(GTK_CONTAINER(g.win), glarea);
+ gtk_widget_add_tick_callback(glarea, tick_cb, 0, 0);
+ }
+ gtk_widget_show_all(g.win);
+}
diff --git a/gtk/oscilloview.c b/gtk/oscilloview.c
index bf56140..e2893c6 100644
--- a/gtk/oscilloview.c
+++ b/gtk/oscilloview.c
@@ -10,8 +10,6 @@ struct oscilloview oscilloview_g = {
enum {
VIEW_SAMPLES = 1024,
VIEW_SKIP = 2,
- WIDTH = 600,
- HEIGHT = 300,
};
static struct {
@@ -75,11 +73,10 @@ void show_oscilloview(void) {
g.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(g.win), "Oscilloscope view");
g_signal_connect(g.win, "destroy", G_CALLBACK(on_destroy), 0);
+ GtkWidget *drawarea = gtk_drawing_area_new();
+ gtk_container_add(GTK_CONTAINER(g.win), drawarea);
+ g_signal_connect(drawarea, "draw", G_CALLBACK(draw_cb), 0);
+ gtk_widget_add_tick_callback(drawarea, tick_cb, 0, 0);
}
- GtkWidget *drawarea = gtk_drawing_area_new();
- gtk_container_add(GTK_CONTAINER(g.win), drawarea);
- //gtk_widget_set_size_request(drawarea, WIDTH*3, HEIGHT*3);
- g_signal_connect(drawarea, "draw", G_CALLBACK(draw_cb), 0);
- gtk_widget_add_tick_callback(drawarea, tick_cb, 0, 0);
gtk_widget_show_all(g.win);
}