#include #include #include #include #include #include #include #include #include #include #include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" int width; int height; GLFWwindow* window; GLuint shader_id; time_t shader_mtime; int nr_images = 0; time_t images_mtime; GLuint backbuffer; GLfloat params[8]; int scene; double ticks = 0; float last_tick; float tick_dur; int running = 0; FILE* ffmpeg; static snd_seq_t *midi_seq; static int midiin; float now() { struct timespec tv; clock_gettime(CLOCK_MONOTONIC, &tv); return (float) (tv.tv_sec * 1000000000 + tv.tv_nsec)/1000000000; } static void error_callback(int error, const char* description) { fputs(description, stderr); } static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (action == GLFW_PRESS) { if (key == GLFW_KEY_Q) glfwSetWindowShouldClose(window, GL_TRUE); else if (key == GLFW_KEY_SPACE) { if (running) { system("oscsend 0.0.0.0 8888 /renoise/transport/stop"); running = 0; } else { system("oscsend 0.0.0.0 8888 /renoise/transport/start"); running = 1; } } } } void resize_callback(GLFWwindow* window, int w, int h) { width = w; height = h; glUniform2f(glGetUniformLocation(shader_id, "resolution"),width,height); } time_t mtime(char *path) { struct stat file_stat; stat(path, &file_stat); return(file_stat.st_mtime); } const char * readShader() { char source[100000]; FILE *file = fopen("shader.frag", "r"); if (!file) { fprintf(stderr,"Cannot read 'shader.frag'\n"); exit(EXIT_FAILURE); } int res = fread(source,1,100000-1,file); source[res] = 0; fclose(file); const char *c_str = source; return c_str; } void checkShader(GLuint id,int success, char * action) { if (!success) { char infoLog[512]; glGetShaderInfoLog(id, 512, NULL, infoLog); fprintf(stderr,"Shader %s failed: %s\n",action,infoLog); exit(EXIT_FAILURE); } } GLuint compileShader(const char * source, GLenum type) { GLuint id = glCreateShader(type); glShaderSource(id, 1, &source, NULL); glCompileShader(id); int success; glGetShaderiv(id, GL_COMPILE_STATUS, &success); checkShader(id,success,"compilation"); return id; } GLuint linkShader(GLuint vertex, GLuint fragment) { GLuint id = glCreateProgram(); glAttachShader(id, vertex); glAttachShader(id, fragment); glLinkProgram(id); int success; glGetProgramiv(id, GL_LINK_STATUS, &success); checkShader(id,success,"linking"); glDetachShader(id, vertex); glDetachShader(id, fragment); glDeleteShader(vertex); glDeleteShader(fragment); return id; } void createShader() { static const char vertex_src[] = { "#version 450 core\n" "const vec2 quadVertices[4] = { vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0) };\n" "void main() { gl_Position = vec4(quadVertices[gl_VertexID], 0.0, 1.0); }\n" }; GLuint vertex = compileShader(vertex_src, GL_VERTEX_SHADER); GLuint fragment = compileShader(readShader(),GL_FRAGMENT_SHADER); shader_id = linkShader(vertex,fragment); shader_mtime = mtime("shader.frag"); glUseProgram(shader_id); glUniform2f(glGetUniformLocation(shader_id, "resolution"),width,height); // important!! } void readImage(char * path, int n) { int w,h,comp; stbi_set_flip_vertically_on_load(1); unsigned char* pixels = stbi_load(path, &w, &h, &comp, STBI_rgb_alpha); glUniform1i(glGetUniformLocation(shader_id, "images")+n,n); GLuint id; glActiveTexture(GL_TEXTURE0+n); glGenTextures(1, &id); fprintf(stderr,"Loading image #%i %s \n",n,path); glBindTexture(GL_TEXTURE_2D,id); 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_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); stbi_image_free(pixels); } void readImages() { FILE *file = fopen("images", "r"); char * line = NULL; size_t len = 0; ssize_t chars; int n = 0; while (((chars = getline(&line, &len, file)) != -1)) { if (line[chars - 1] == '\n') { line[chars - 1] = '\0'; --chars; } readImage(line,n); n++; } nr_images = n; fclose(file); images_mtime = mtime("images"); } void *readMidi() { snd_seq_open(&midi_seq, "default", SND_SEQ_OPEN_INPUT, 0); snd_seq_set_client_name(midi_seq, "SV"); midiin = snd_seq_create_simple_port(midi_seq, "sv:in", SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION); while(1) { snd_seq_event_t *ev = NULL; snd_seq_event_input(midi_seq, &ev); if(running && ev->type == SND_SEQ_EVENT_CLOCK) { float current_time = now(); tick_dur = current_time-last_tick; last_tick = current_time; ticks++; } else if(ev->type == SND_SEQ_EVENT_NOTEON) scene = ev->data.note.note; else if(ev->type == SND_SEQ_EVENT_CONTROLLER) { int p = ev->data.control.param; int v = ev->data.control.value; if (p < 8) params[p] = (float)v/127.0; } else if(ev->type == SND_SEQ_EVENT_SONGPOS) ticks = ev->data.control.value*24; else if(ev->type == SND_SEQ_EVENT_START) running = 1; else if(ev->type == SND_SEQ_EVENT_STOP) running = 0; else if(ev->type == SND_SEQ_EVENT_CONTINUE) running = 1; } } int main(int argc, char **argv) { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_DECORATED, GL_FALSE); const GLFWvidmode * mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); width = mode->width; height = mode->height; window = glfwCreateWindow(width,height, "sv", NULL, NULL); glfwSetWindowSizeCallback(window, resize_callback); glfwMakeContextCurrent(window); glfwSetKeyCallback(window, key_callback); glfwSetErrorCallback(error_callback); glewInit(); glfwGetWindowSize(window, &width, &height); glCreateTextures(GL_TEXTURE_2D,1,&backbuffer); glTextureStorage2D(backbuffer,1,GL_RGBA32F,width,height); glBindImageTexture(0,backbuffer, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F); createShader(); readImages(); unsigned int VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); pthread_t midiin_t; pthread_create(&midiin_t, NULL, readMidi, NULL); GLuint ticks_id = glGetUniformLocation(shader_id, "ticks"); GLuint scene_id = glGetUniformLocation(shader_id, "scene"); GLuint params_id = glGetUniformLocation(shader_id, "params"); GLuint backbuffer_id = glGetUniformLocation(shader_id, "backbuffer"); float next_frame = now(); while (!glfwWindowShouldClose(window)) { // glUniforms cannot be set from threads! if (mtime("shader.frag") > shader_mtime) { createShader(); for (int i = 0; i < nr_images; i++) glUniform1i(glGetUniformLocation(shader_id, "images")+i,i); ticks_id = glGetUniformLocation(shader_id, "ticks"); scene_id = glGetUniformLocation(shader_id, "scene"); params_id = glGetUniformLocation(shader_id, "params"); backbuffer_id = glGetUniformLocation(shader_id, "backbuffer"); } if (mtime("images") > images_mtime) readImages(); //float tick_frac = ticks + (now()-last_tick)/tick_dur; //glUniform1f(glGetUniformLocation(shader_id, "ticks"),tick_frac); glUniform1i(ticks_id,ticks); glUniform1i(scene_id, scene); glUniform1fv(params_id, 8, params); glUniform1i(backbuffer_id,0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glfwSwapBuffers(window); glfwPollEvents(); } system("oscsend 0.0.0.0 8888 /renoise/transport/stop"); pthread_cancel(midiin_t); glfwDestroyWindow(window); glfwTerminate(); exit(EXIT_SUCCESS); }