147 lines
3.8 KiB
C++
147 lines
3.8 KiB
C++
#include <GL/glew.h>
|
|
#include <GLFW/glfw3.h>
|
|
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
#include "stb_image.h"
|
|
|
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
|
#include "stb_image_write.h"
|
|
|
|
#include <fstream>
|
|
#include <vector>
|
|
#include <iostream>
|
|
|
|
std::string loadFile(const char* path)
|
|
{
|
|
std::ifstream f(path);
|
|
return std::string((std::istreambuf_iterator<char>(f)),
|
|
std::istreambuf_iterator<char>());
|
|
}
|
|
|
|
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);
|
|
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,c;
|
|
unsigned char* img1 = stbi_load("frame1.jpg",&w,&h,&c,4);
|
|
unsigned char* img2 = stbi_load("frame2.jpg",&w,&h,&c,4);
|
|
|
|
if(!img1 || !img2)
|
|
{
|
|
std::cout << "image load failed\n";
|
|
return 0;
|
|
}
|
|
|
|
// ---------------- TEXTURES ----------------
|
|
GLuint texA, texB;
|
|
glGenTextures(1,&texA);
|
|
glGenTextures(1,&texB);
|
|
|
|
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);
|
|
|
|
// ---------------- 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::cout << "FBO broken\n";
|
|
|
|
// ---------------- 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<unsigned char> 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);
|
|
|
|
std::cout << "done\n";
|
|
} |