#include #include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.hpp" #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.hpp" #include #include #include std::string loadFile(const char* path) { std::ifstream f(path); return std::string((std::istreambuf_iterator(f)), std::istreambuf_iterator()); } GLuint compile(GLenum t, const std::string& src) { GLuint s = glCreateShader(t); const char* c = src.c_str(); glShaderSource(s, 1, &c, NULL); glCompileShader(s); GLint ok = 0; glGetShaderiv(s, GL_COMPILE_STATUS, &ok); if (!ok) { char log[1024]; glGetShaderInfoLog(s, sizeof(log), NULL, log); std::cerr << "shader compile failed:\n" << log; } return s; } int main() { glfwInit(); glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); GLFWwindow* win = glfwCreateWindow(1,1,"",NULL,NULL); glfwMakeContextCurrent(win); glewInit(); // ---------------- LOAD IMAGES ---------------- int w,h; unsigned char* img1 = stbi_load("frame1.jpg",&w,&h,NULL,4); unsigned char* img2 = stbi_load("frame2.jpg",&w,&h,NULL,4); if(!img1 || !img2) { std::cerr << "image load failed\n"; return 1; } // ---------------- TEXTURES ---------------- GLuint tex[2]; glGenTextures(2, tex); GLuint texA = tex[0], texB = tex[1]; auto upload = [&](GLuint t, unsigned char* d) { glBindTexture(GL_TEXTURE_2D,t); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,d); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); }; upload(texA,img1); upload(texB,img2); // ---------------- SHADER ---------------- std::string frag = loadFile("motion.frag"); const char* vs = "#version 330 core\n" "layout(location=0) in vec2 pos;\n" "out vec2 uv;\n" "void main(){\n" "uv = pos*0.5+0.5;\n" "gl_Position = vec4(pos,0,1);\n" "}"; GLuint v = compile(GL_VERTEX_SHADER,vs); GLuint f = compile(GL_FRAGMENT_SHADER,frag); GLuint prog = glCreateProgram(); glAttachShader(prog,v); glAttachShader(prog,f); glLinkProgram(prog); GLint linked = 0; glGetProgramiv(prog, GL_LINK_STATUS, &linked); if (!linked) { char log[1024]; glGetProgramInfoLog(prog, sizeof(log), NULL, log); std::cerr << "program link failed:\n" << log; return 1; } // ---------------- QUAD (FIXED) ---------------- GLuint vao,vbo; float quad[] = { -1,-1, 1,-1, -1, 1, 1, 1 }; glGenVertexArrays(1,&vao); glBindVertexArray(vao); glGenBuffers(1,&vbo); glBindBuffer(GL_ARRAY_BUFFER,vbo); glBufferData(GL_ARRAY_BUFFER,sizeof(quad),quad,GL_STATIC_DRAW); glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,0,0); glEnableVertexAttribArray(0); // ---------------- FBO ---------------- GLuint fbo,outTex; glGenFramebuffers(1,&fbo); glGenTextures(1,&outTex); glBindTexture(GL_TEXTURE_2D,outTex); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL); glBindFramebuffer(GL_FRAMEBUFFER,fbo); glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,outTex,0); if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { std::cerr << "FBO broken\n"; return 1; } // ---------------- RENDER ---------------- glUseProgram(prog); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,texA); glUniform1i(glGetUniformLocation(prog,"texA"),0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,texB); glUniform1i(glGetUniformLocation(prog,"texB"),1); glViewport(0,0,w,h); glBindFramebuffer(GL_FRAMEBUFFER,fbo); glBindVertexArray(vao); glDrawArrays(GL_TRIANGLE_STRIP,0,4); // ---------------- READ BACK ---------------- std::vector out(w*h*4); glReadPixels(0,0,w,h,GL_RGBA,GL_UNSIGNED_BYTE,out.data()); stbi_write_jpg("frameO.jpg",w,h,4,out.data(),90); stbi_image_free(img1); stbi_image_free(img2); std::cout << "done\n"; }