C++ Glsl 3.3+;使用多个纹理输入和输出(材质球中的布料计算)

C++ Glsl 3.3+;使用多个纹理输入和输出(材质球中的布料计算),c++,opengl,glsl,C++,Opengl,Glsl,我们正在尝试移植在cpu上计算的工作布料模拟,以便使用gpu上的着色器进行计算。基本概念如下:2个着色器过程,一个用于计算布料中每个点的位置,另一个用于绘制布料,并计算布料法线。我们使用2个FBO,每个FBO有3个纹理用于位置、上一个位置和法线 在第一个着色器过程中,我们希望使用第一个FBO的纹理作为输入,并将位置和上一个位置写入第二个FBO的纹理。 在过程1和过程2之间,我们提取位置数据,并使用它为绘图步骤创建三角形的顶点数组,而不是奇点。 在过程2中,我们使用新的顶点数组绘制布料,并使用几何

我们正在尝试移植在cpu上计算的工作布料模拟,以便使用gpu上的着色器进行计算。基本概念如下:2个着色器过程,一个用于计算布料中每个点的位置,另一个用于绘制布料,并计算布料法线。我们使用2个FBO,每个FBO有3个纹理用于位置、上一个位置和法线

在第一个着色器过程中,我们希望使用第一个FBO的纹理作为输入,并将位置和上一个位置写入第二个FBO的纹理。 在过程1和过程2之间,我们提取位置数据,并使用它为绘图步骤创建三角形的顶点数组,而不是奇点。 在过程2中,我们使用新的顶点数组绘制布料,并使用几何体着色器重新计算法线,将其发送到片段着色器,最后将其从第二个FBO输出到法线纹理。然后FBO交换下一个循环的位置

这就是我们希望发生的事情。现在发生的是,在计算步骤中,写入纹理的内容似乎与着色器中的内容完全无关,我们怀疑在绘制循环期间链接纹理时出错。任何指点都将不胜感激

我们得到的每个点的输出是0.664063 0.742188 0.839844 1.000000

片段着色器:

#version 330
uniform sampler2D pos;
uniform sampler2D prev_pos;
uniform sampler2D normal;
uniform float damping;
uniform float mass;
uniform vec3 gravity;
uniform vec3 wind;
uniform float ts;
uniform vec2 texsize;
uniform vec2 patch_size;
uniform vec2 step;
uniform vec2 neighbours[12]; 
in vec2 frag_texcoord;

out vec4 outpos;
out vec4 outprev;

void main(void)
{
    float movable_l = floor(frag_texcoord.x+(1.0-3*step.x))+floor(frag_texcoord.y+(1.0-step.y));
    float movable_r = (1-floor(frag_texcoord.x+3*step.x))+(1-floor(frag_texcoord.y+step.y));
    float movable = movable_r*movable_l;
    vec3 curr_pos = texture(pos,frag_texcoord.yx).xyz;

    if(movable >0){
        vec3 p_pos = texture(prev_pos,frag_texcoord).xyz;
        vec2 neighbourtexcoord;
        vec3  neighbourpos;
        for(int n=0;n<12;n++){
            neighbourtexcoord = neighbours[n]*step;
            neighbourtexcoord += frag_texcoord;
            if(neighbourtexcoord.x<0.0 || neighbourtexcoord.x>(1.0-step.x)){
                continue;
            }
            if(neighbourtexcoord.y<0.0 || neighbourtexcoord.y>(1.0-step.y)){
                continue;
            }
            neighbourpos = texture(pos,neighbourtexcoord).xyz;
            vec3 d = curr_pos-neighbourpos;
            float dist = distance(curr_pos,neighbourpos);
            float idist = length(neighbours[n])*step.x;
            curr_pos += d*(1-(idist/dist));
        }
        vec3 windF = texture(normal,frag_texcoord).xyz*wind;
        vec3 acc = windF+gravity;
        float damp = 1-damping;
        vec3 vel = curr_pos-p_pos;
        curr_pos += acc*ts+vel;
    }
    outpos = vec4(curr_pos,1.0);
    outprev = vec4(texture(pos,frag_texcoord).xyz,0.0);
}
主程序:

#include <math.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include "SOIL.h"
#include <stdio.h>
#include <cassert>
#include <string.h>
#include <stddef.h>
#ifdef __APPLE__
    #include <OpenGL/gl.h>
    #include "MicroGlut.h"
// uses framework Cocoa
#else
//  #include <GL/glut.h>
#endif
#include "GL_utilities.h"
#include "VectorUtils2.h"
#include "Cloth.h"

//#include "LoadTGA.h"


#define TIME_STEPSIZE2 0.5*0.5 

#define CHECK_GL_ERRORS assert(glGetError()==GL_NO_ERROR);

#ifndef M_PI
#define M_PI 3.14159265
#endif

static long count = 0;
static long limit = -1;
static float startTime;

static GLfloat view_rotx = 90.0, view_roty = 0.0, view_rotz = 70.0;
static GLuint gear1, gear2, gear3; // Was display lists, now are VAOs
static GLfloat angle = 0.0;

//The value that controls the wind speed
float windForceZ = 0.0;

int gear1Triangles=0, gear2Triangles=0, gear3Triangles=0;

GLuint program, verletShader,clothVao, clothVbo, clothNbo, clothTbo, quadVao, quadVbo; // Shader

GLint colorPos;
float projectionMatrix[16];

static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
static GLuint quad[]={  -1.0f, -1.0f, 0.0f,
                        1.0f, -1.0f, 0.0f,
                        -1.0f,  1.0f, 0.0f,
                        -1.0f,  1.0f, 0.0f,
                        1.0f, -1.0f, 0.0f,
                        1.0f,  1.0f, 0.0f};

#define W 512
#define H 512

//------------a structure for FBO information-------------------------------------
typedef struct
{
    GLuint attachID[3];
    GLuint fb;
    GLuint rb;
    GLuint depth;
    int width, height;
} FBOstruct;

FBOstruct *fbo1, *fbo2;
GLenum color_attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};

float *gVert;
float *gNorm;
float *data;
static int numVertices;
static float currentNormalsX, currentNormalsY, currentNormalsZ;

GLuint texture_img;
GLint location_Texture, location_texCoord;
#define vDensity 8
#define hDensity 8
#define cloth_width 20
#define cloth_height 20
Cloth cloth1(cloth_height,cloth_width,vDensity,hDensity);

int size = (vDensity-1)*(hDensity-1)*9*2;

Point3D gravity, tmp1, wind;

void init_glsl_stuff(){

      verletShader = loadShaders("verlet.vert", "verlet.frag");
      CHECK_GL_ERRORS
      glUseProgram(verletShader);
      float neighbourarray[24] = {1,0,0,1,1,1,-1,1,-1,0,1-1,2,0,0,2,-2,0,0-2};
      glUniform1i(glGetUniformLocation(verletShader,"pos"),0);
      glUniform1i(glGetUniformLocation(verletShader,"prev_pos"),1);
      glUniform1i(glGetUniformLocation(verletShader,"normal"),2);
      glUniform1f(glGetUniformLocation(verletShader,"damping"), 0.01); 
      glUniform1f(glGetUniformLocation(verletShader,"mass"), 1.0);
      glUniform3f(glGetUniformLocation(verletShader,"gravity"), 0.0,0.9,0.0);
       glUniform3f(glGetUniformLocation(verletShader,"wind"), 0.0,0.0,0.0);
      glUniform1f(glGetUniformLocation(verletShader,"ts"), 0.5*0.5);
      CHECK_GL_ERRORS
      glUniform2f(glGetUniformLocation(verletShader,"texsize"), (float)hDensity,(float)vDensity);
      CHECK_GL_ERRORS
      // eventuellt lägga till k värden för fjädrar
      glUniform2f(glGetUniformLocation(verletShader,"patch_size"), (float)cloth_width/((float)hDensity-1.0),(float)cloth_height/((float)vDensity-1.0));
      CHECK_GL_ERRORS
      glUniform2f(glGetUniformLocation(verletShader,"step"),1.0/((float)vDensity-1.0), 1.0/((float)hDensity-1.0));
       CHECK_GL_ERRORS
      glUniform2fv(glGetUniformLocation(verletShader,"neighbours"),12,neighbourarray);
       glBindFragDataLocation(verletShader, 0, "outpos");
       glBindFragDataLocation(verletShader, 1, "outprev");
       glLinkProgram(verletShader);
       printProgramInfoLog(verletShader);

      glUseProgram(0);


}


void addTexture(int width, int height,int int_method,GLuint mempos,float *data,int attachment_pos){


        glBindTexture(GL_TEXTURE_2D,mempos);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        if (int_method == 0)
        {
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        }
        else
        {
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        }


        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, data);
        glFramebufferTexture2D(GL_FRAMEBUFFER, attachment_pos, GL_TEXTURE_2D, mempos, 0);
}

//------------------------------------------------------------
//-----------------------FBO Init-----------------------------
//------------------------------------------------------------
void CHECK_FRAMEBUFFER_STATUS()
{
    GLenum status;
    status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE)
        fprintf(stderr, "Framebuffer not complete\n");
}
FBOstruct *initFBO(int width, int height, int int_method, float *positions, float *normals)
{

    FBOstruct *fbo = new FBOstruct();



    fbo->width = width;
    fbo->height = height;

    // create objects
    glGenFramebuffers(1, &fbo->fb); // frame buffer id
    glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
    glGenTextures(3, fbo->attachID);
    addTexture(width,height,int_method,fbo->attachID[0],positions,color_attachments[0]);
    addTexture(width,height,int_method,fbo->attachID[1],positions,color_attachments[1]);
    addTexture(width,height,int_method,fbo->attachID[2],normals,color_attachments[2]);
    fprintf(stderr, "Framebuffer object %d\n", fbo->fb);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    return fbo;
}

//------------------------------------------------------------
//---------------------Draw on GPU----------------------------
//------------------------------------------------------------
void drawClothGPU(){

    glViewport(0, 0, H, W);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo1->fb);

    glDrawBuffers(3, color_attachments);    

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, fbo2->attachID[0]);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, fbo2->attachID[1]);

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, fbo2->attachID[2]);

    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(verletShader);

    glBindVertexArray(quadVao); 
    glBindBuffer(GL_ARRAY_BUFFER,quadVbo);
    glDrawArrays(GL_TRIANGLES, 0, 18);

    glBindBuffer(GL_ARRAY_BUFFER,0);


    glBindVertexArray(clothVao);
    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo2->fb);
    glBindTexture(GL_TEXTURE_2D, fbo2->attachID[0]);
    glReadBuffer(GL_COLOR_ATTACHMENT0);         
        int s = hDensity*vDensity*4;
    data = new float[s];
    glReadPixels(0, 0, hDensity, vDensity, GL_RGBA, GL_FLOAT, data);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);



    gVert = new float[size];
    glUseProgram(program);
    glBindBuffer(GL_ARRAY_BUFFER, clothVbo);
    int count = 0;
    for(int x = 0; x<vDensity-1; x++){
        for(int y=0; y<hDensity-1; y++){
            //(x+1,y)
            printf("value : %f",data[4*(x + 1 + hDensity*y)]);
            gVert[count] = data[4*(x + 1 + hDensity*y)];
            gVert[count + 1] = data[4*(x + 1 + hDensity*y) + 1];
            gVert[count + 2] = data[4*(x + 1 + hDensity*y) + 2];
            //(x,y)
            gVert[count + 3] = data[4*(x + hDensity*y)];
            gVert[count + 4] = data[4*(x + hDensity*y) + 1];
            gVert[count + 5] = data[4*(x + hDensity*y) + 2];
            //(x,y+1)
            gVert[count + 6] = data[4*(x + hDensity*(y+1))];
            gVert[count + 7] = data[4*(x + hDensity*(y+1)) + 1];
            gVert[count + 8] = data[4*(x + hDensity*(y+1)) + 2];
            //(x+1,y+1)
            gVert[count + 9] = data[4*(x + 1 + hDensity*(y+1))];
            gVert[count + 10] = data[4*(x + 1 + hDensity*(y+1)) + 1];
            gVert[count + 11] = data[4*(x + 1 + hDensity*(y+1)) + 2];
            //(x+1,y)
            gVert[count + 12] = data[4*(x + 1 + hDensity*y)];
            gVert[count + 13] = data[4*(x + 1 + hDensity*y) + 1];
            gVert[count + 14] = data[4*(x + 1 + hDensity*y) + 2];
            //(x,y+1)
            gVert[count + 15] = data[4*(x + hDensity*(y+1))];
            gVert[count + 16] = data[4*(x + hDensity*(y+1)) + 1];
            gVert[count + 17] = data[4*(x + hDensity*(y+1)) + 2];

            count+=18;
        }
    }

    int num_vertices = (count)/3;
    int num_coordinates = count;

    GLfloat* pData = (GLfloat*)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
    memcpy(pData, &gVert[0], num_coordinates*sizeof(GLfloat));
    glUnmapBuffer(GL_ARRAY_BUFFER);

    glDrawArrays(GL_TRIANGLES, 0, num_vertices);
    delete [] gVert;
    delete [] data;
    FBOstruct *tmp = fbo1;
    fbo1 = fbo2;
    fbo2 = tmp;
}



static void draw(void)
{




    //CPU
    //drawClothCPU(m);

    //GPU
    drawClothGPU();



    glBindTexture(GL_TEXTURE_2D, 0);

    glutSwapBuffers();
    count++;
    if (count == limit)
        exit(0);
    theTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
    if (theTime >= startTime + 1.0)
    {
        //printf("%d fps\n", count);
        startTime = theTime;
        count = 0;
    }
}

static void
init(void)
{

    glDisable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
    init_glsl_stuff();  //first shader stuff
    program = loadShaders("gears.vert", "gears.frag");
    glUseProgram(program);
    glUniform4fv(glGetUniformLocation(program, "pos"), 1, pos);
    glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"), 1, GL_TRUE, projectionMatrix);
    colorPos = glGetUniformLocation(program, "color");
    gVert = new float[size];
    gNorm = new float[size];
    float *pts = new float[vDensity*hDensity*4];
    float *norm = new float[vDensity*hDensity*4];
    int num = cloth1.drawShaded(gVert, gNorm);
    cloth1.getPoints(pts,norm);
    fbo1 = initFBO(hDensity, vDensity, 0,pts,norm);
    fbo2 = initFBO(hDensity, vDensity, 0,pts,norm);

    glGenVertexArrays(1, &clothVao);
    glBindVertexArray(clothVao);
    glGenBuffers(1, &clothVbo);
    glGenBuffers(1, &clothNbo);
    glGenBuffers(1, &clothTbo);

    glBindBuffer(GL_ARRAY_BUFFER, clothVbo);
    glBufferData(GL_ARRAY_BUFFER, num*9*sizeof(GLfloat), gVert, GL_STATIC_DRAW);

    glVertexAttribPointer(glGetAttribLocation(program, "in_Position"), 3, GL_FLOAT, GL_FALSE, 0, 0); 
    glEnableVertexAttribArray(glGetAttribLocation(program, "in_Position"));


    //VAO for quad
    glGenVertexArrays(1, &quadVao);
    glBindVertexArray(quadVao);

    //VBO for quad
    glGenBuffers(1, &quadVbo);
    glBindBuffer(GL_ARRAY_BUFFER, quadVbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);


    glBindVertexArray(0);

    delete [] gVert;
    delete [] gNorm;


    //texture
    texture_img = loadTexture("C:/Users/Bohb/Downloads/boa.jpg");

    location_Texture = glGetUniformLocation( program, "colorMap" );
    if(location_Texture == -1)
        fprintf( stderr, "Binding warning: Failed to locate uniform variable 'colorMap'.\n");

    frustum(-1.0, 1.0, -1.0, 1.0, 5.0, 60.0, projectionMatrix);

    startTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
    glBindVertexArray(clothVao);
}
#包括
#包括
#包括
#包括
#包括“土壤h”
#包括
#包括
#包括
#包括
#苹果__
#包括
#包括“MicroGlut.h”
//使用框架Cocoa
#否则
//#包括
#恩迪夫
#包括“GL_utilities.h”
#包括“VectorUtils2.h”
#包括“Cloth.h”
//#包括“LoadTGA.h”
#定义时间步长2 0.5*0.5
#定义CHECK\u GL\u ERRORS assert(glGetError()==GL\u NO\u ERROR);
#伊夫德夫·穆皮
#定义M_PI 3.14159265
#恩迪夫
静态长计数=0;
静态长限=-1;
静态浮动起始时间;
静态GLfloat视图旋转X=90.0,视图旋转Y=0.0,视图旋转Z=70.0;
静态胶合齿轮1、齿轮2、齿轮3;//以前是显示列表,现在是VAO
静态浮动角度=0.0;
//控制风速的值
浮动风力z=0.0;
int gear1Triangles=0,gear2Triangles=0,gear3Triangles=0;
GLuint程序,verletShader,clothVao,clothVbo,clothNbo,clothTbo,quadVao,quadVbo;//着色器
闪烁色;
浮动投影矩阵[16];
静态GLfloat pos[4]={5.0,5.0,10.0,0.0};
静态胶接四元[]={-1.0f,-1.0f,0.0f,
1.0f,-1.0f,0.0f,
-1.0f,1.0f,0.0f,
-1.0f,1.0f,0.0f,
1.0f,-1.0f,0.0f,
1.0f,1.0f,0.0f};
#定义w512
#定义h512
//------------一种FBO信息结构-------------------------------------
类型定义结构
{
胶合附着体[3];
GLuint fb;
胶合rb;
胶合深度;
int宽度、高度;
}FBOstruct;
FBOstruct*fbo1,*fbo2;
GLenum color_attachments[]={GL_color_ATTACHMENT0,GL_color_ATTACHMENT1,GL_color_ATTACHMENT2};
浮动*gVert;
浮动*gNorm;
浮动*数据;
静态整数;
静态浮点currentNormalsX、currentNormalsY、currentNormalsZ;
胶合纹理;
闪烁位置\纹理,位置\纹理坐标;
#定义密度8
#定义密度8
#定义布料宽度20
#定义布料高度20
布匹1(布匹高度、布匹宽度、密度、密度);
整数大小=(vDensity-1)*(hDensity-1)*9*2;
点3D重力,tmp1,风;
void init_glsl_stuff(){
verletShader=加载着色器(“verlet.vert”、“verlet.frag”);
检查GLU错误
glUseProgram(verletShader);
浮动邻域[24]={1,0,0,1,1,1,-1,1,-1,0,1-1,2,0,0,2,-2,0,0-2};
glUniform1i(glGetUniformLocation(verletShader,“pos”),0;
glUniform1i(glGetUniformLocation(verletShader,“prev_pos”),1);
glUniform1i(glGetUniformLocation(verletShader,“正常”),2;
glUniform1f(glGetUniformLocation(verletShader,“阻尼”),0.01;
glUniform1f(glGetUniformLocation(verletShader,“质量”),1.0;
glUniform3f(glGetUniformLocation(verletShader,“重力”),0.0,0.9,0.0;
glUniform3f(glGetUniformLocation(verletShader,“风”),0.0,0.0,0.0;
glUniform1f(glGetUniformLocation(verletShader,“ts”),0.5*0.5;
检查GLU错误
glUniform2f(glGetUniformLocation(verletShader,“texsize”),(float)hDensity,(float)vDensity);
检查GLU错误
//最终,我会一直坚持到最后
glUniform2f(glGetUniformLocation(verletShader,“面片大小”),(浮动)布料宽度/((浮动)hDensity-1.0),(浮动)布料高度/((浮动)vDensity-1.0));
检查GLU错误
glUniform2f(glGetUniformLocation(verletShader,“step”)、1.0/((浮点)vDensity-1.0)、1.0/((浮点)hDensity-1.0);
检查GLU错误
glUniform2fv(glGetUniformLocation(verletShader,“邻居”),12,邻居阵列;
glBindFragDataLocation(verletShader,0,“输出”);
glBindFragDataLocation(verletShader,1,“outprev”);
glLinkProgram(verletShader);
printProgramInfoLog(verletShader);
glUseProgram(0);
}
void addTexture(int-width、int-height、int-int\u方法、GLuint-mempos、float*数据、int-attachment\u-pos){
glBindTexture(GL_TEXTURE_2D,mempos);
glTexParameteri(GL_纹理2D、GL_纹理包裹S、GL_重复);
glTexParameteri(GL_纹理2D、GL_纹理包裹、GL_重复);
if(int_方法==0)
{
glTexParameteri(GL_纹理2D,GL_纹理MAG_过滤器,GL_最近);
glTexParameteri(GL\u纹理\u 2D,GL\u纹理\u最小\u过滤器,GL\u最近);
}
其他的
{
glTexParameteri(GL_纹理2D、GL_纹理MAG_过滤器、GL_线性);
glTexParameteri(GL_纹理2D、GL_纹理最小过滤器、GL_线性);
}
GLTEXAGE2D(GL_纹理_2D,0,GL_RGBA16F,宽度,高度,0,GL_RGBA,GL_浮点,数据);
glFramebufferTexture2D(GL_帧缓冲区、附件位置、GL_纹理位置2D、mempos、0);
}
//---------------------------------------------------
#include <math.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include "SOIL.h"
#include <stdio.h>
#include <cassert>
#include <string.h>
#include <stddef.h>
#ifdef __APPLE__
    #include <OpenGL/gl.h>
    #include "MicroGlut.h"
// uses framework Cocoa
#else
//  #include <GL/glut.h>
#endif
#include "GL_utilities.h"
#include "VectorUtils2.h"
#include "Cloth.h"

//#include "LoadTGA.h"


#define TIME_STEPSIZE2 0.5*0.5 

#define CHECK_GL_ERRORS assert(glGetError()==GL_NO_ERROR);

#ifndef M_PI
#define M_PI 3.14159265
#endif

static long count = 0;
static long limit = -1;
static float startTime;

static GLfloat view_rotx = 90.0, view_roty = 0.0, view_rotz = 70.0;
static GLuint gear1, gear2, gear3; // Was display lists, now are VAOs
static GLfloat angle = 0.0;

//The value that controls the wind speed
float windForceZ = 0.0;

int gear1Triangles=0, gear2Triangles=0, gear3Triangles=0;

GLuint program, verletShader,clothVao, clothVbo, clothNbo, clothTbo, quadVao, quadVbo; // Shader

GLint colorPos;
float projectionMatrix[16];

static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
static GLuint quad[]={  -1.0f, -1.0f, 0.0f,
                        1.0f, -1.0f, 0.0f,
                        -1.0f,  1.0f, 0.0f,
                        -1.0f,  1.0f, 0.0f,
                        1.0f, -1.0f, 0.0f,
                        1.0f,  1.0f, 0.0f};

#define W 512
#define H 512

//------------a structure for FBO information-------------------------------------
typedef struct
{
    GLuint attachID[3];
    GLuint fb;
    GLuint rb;
    GLuint depth;
    int width, height;
} FBOstruct;

FBOstruct *fbo1, *fbo2;
GLenum color_attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};

float *gVert;
float *gNorm;
float *data;
static int numVertices;
static float currentNormalsX, currentNormalsY, currentNormalsZ;

GLuint texture_img;
GLint location_Texture, location_texCoord;
#define vDensity 8
#define hDensity 8
#define cloth_width 20
#define cloth_height 20
Cloth cloth1(cloth_height,cloth_width,vDensity,hDensity);

int size = (vDensity-1)*(hDensity-1)*9*2;

Point3D gravity, tmp1, wind;

void init_glsl_stuff(){

      verletShader = loadShaders("verlet.vert", "verlet.frag");
      CHECK_GL_ERRORS
      glUseProgram(verletShader);
      float neighbourarray[24] = {1,0,0,1,1,1,-1,1,-1,0,1-1,2,0,0,2,-2,0,0-2};
      glUniform1i(glGetUniformLocation(verletShader,"pos"),0);
      glUniform1i(glGetUniformLocation(verletShader,"prev_pos"),1);
      glUniform1i(glGetUniformLocation(verletShader,"normal"),2);
      glUniform1f(glGetUniformLocation(verletShader,"damping"), 0.01); 
      glUniform1f(glGetUniformLocation(verletShader,"mass"), 1.0);
      glUniform3f(glGetUniformLocation(verletShader,"gravity"), 0.0,0.9,0.0);
       glUniform3f(glGetUniformLocation(verletShader,"wind"), 0.0,0.0,0.0);
      glUniform1f(glGetUniformLocation(verletShader,"ts"), 0.5*0.5);
      CHECK_GL_ERRORS
      glUniform2f(glGetUniformLocation(verletShader,"texsize"), (float)hDensity,(float)vDensity);
      CHECK_GL_ERRORS
      // eventuellt lägga till k värden för fjädrar
      glUniform2f(glGetUniformLocation(verletShader,"patch_size"), (float)cloth_width/((float)hDensity-1.0),(float)cloth_height/((float)vDensity-1.0));
      CHECK_GL_ERRORS
      glUniform2f(glGetUniformLocation(verletShader,"step"),1.0/((float)vDensity-1.0), 1.0/((float)hDensity-1.0));
       CHECK_GL_ERRORS
      glUniform2fv(glGetUniformLocation(verletShader,"neighbours"),12,neighbourarray);
       glBindFragDataLocation(verletShader, 0, "outpos");
       glBindFragDataLocation(verletShader, 1, "outprev");
       glLinkProgram(verletShader);
       printProgramInfoLog(verletShader);

      glUseProgram(0);


}


void addTexture(int width, int height,int int_method,GLuint mempos,float *data,int attachment_pos){


        glBindTexture(GL_TEXTURE_2D,mempos);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        if (int_method == 0)
        {
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        }
        else
        {
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        }


        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, data);
        glFramebufferTexture2D(GL_FRAMEBUFFER, attachment_pos, GL_TEXTURE_2D, mempos, 0);
}

//------------------------------------------------------------
//-----------------------FBO Init-----------------------------
//------------------------------------------------------------
void CHECK_FRAMEBUFFER_STATUS()
{
    GLenum status;
    status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE)
        fprintf(stderr, "Framebuffer not complete\n");
}
FBOstruct *initFBO(int width, int height, int int_method, float *positions, float *normals)
{

    FBOstruct *fbo = new FBOstruct();



    fbo->width = width;
    fbo->height = height;

    // create objects
    glGenFramebuffers(1, &fbo->fb); // frame buffer id
    glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
    glGenTextures(3, fbo->attachID);
    addTexture(width,height,int_method,fbo->attachID[0],positions,color_attachments[0]);
    addTexture(width,height,int_method,fbo->attachID[1],positions,color_attachments[1]);
    addTexture(width,height,int_method,fbo->attachID[2],normals,color_attachments[2]);
    fprintf(stderr, "Framebuffer object %d\n", fbo->fb);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    return fbo;
}

//------------------------------------------------------------
//---------------------Draw on GPU----------------------------
//------------------------------------------------------------
void drawClothGPU(){

    glViewport(0, 0, H, W);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo1->fb);

    glDrawBuffers(3, color_attachments);    

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, fbo2->attachID[0]);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, fbo2->attachID[1]);

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, fbo2->attachID[2]);

    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(verletShader);

    glBindVertexArray(quadVao); 
    glBindBuffer(GL_ARRAY_BUFFER,quadVbo);
    glDrawArrays(GL_TRIANGLES, 0, 18);

    glBindBuffer(GL_ARRAY_BUFFER,0);


    glBindVertexArray(clothVao);
    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo2->fb);
    glBindTexture(GL_TEXTURE_2D, fbo2->attachID[0]);
    glReadBuffer(GL_COLOR_ATTACHMENT0);         
        int s = hDensity*vDensity*4;
    data = new float[s];
    glReadPixels(0, 0, hDensity, vDensity, GL_RGBA, GL_FLOAT, data);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);



    gVert = new float[size];
    glUseProgram(program);
    glBindBuffer(GL_ARRAY_BUFFER, clothVbo);
    int count = 0;
    for(int x = 0; x<vDensity-1; x++){
        for(int y=0; y<hDensity-1; y++){
            //(x+1,y)
            printf("value : %f",data[4*(x + 1 + hDensity*y)]);
            gVert[count] = data[4*(x + 1 + hDensity*y)];
            gVert[count + 1] = data[4*(x + 1 + hDensity*y) + 1];
            gVert[count + 2] = data[4*(x + 1 + hDensity*y) + 2];
            //(x,y)
            gVert[count + 3] = data[4*(x + hDensity*y)];
            gVert[count + 4] = data[4*(x + hDensity*y) + 1];
            gVert[count + 5] = data[4*(x + hDensity*y) + 2];
            //(x,y+1)
            gVert[count + 6] = data[4*(x + hDensity*(y+1))];
            gVert[count + 7] = data[4*(x + hDensity*(y+1)) + 1];
            gVert[count + 8] = data[4*(x + hDensity*(y+1)) + 2];
            //(x+1,y+1)
            gVert[count + 9] = data[4*(x + 1 + hDensity*(y+1))];
            gVert[count + 10] = data[4*(x + 1 + hDensity*(y+1)) + 1];
            gVert[count + 11] = data[4*(x + 1 + hDensity*(y+1)) + 2];
            //(x+1,y)
            gVert[count + 12] = data[4*(x + 1 + hDensity*y)];
            gVert[count + 13] = data[4*(x + 1 + hDensity*y) + 1];
            gVert[count + 14] = data[4*(x + 1 + hDensity*y) + 2];
            //(x,y+1)
            gVert[count + 15] = data[4*(x + hDensity*(y+1))];
            gVert[count + 16] = data[4*(x + hDensity*(y+1)) + 1];
            gVert[count + 17] = data[4*(x + hDensity*(y+1)) + 2];

            count+=18;
        }
    }

    int num_vertices = (count)/3;
    int num_coordinates = count;

    GLfloat* pData = (GLfloat*)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
    memcpy(pData, &gVert[0], num_coordinates*sizeof(GLfloat));
    glUnmapBuffer(GL_ARRAY_BUFFER);

    glDrawArrays(GL_TRIANGLES, 0, num_vertices);
    delete [] gVert;
    delete [] data;
    FBOstruct *tmp = fbo1;
    fbo1 = fbo2;
    fbo2 = tmp;
}



static void draw(void)
{




    //CPU
    //drawClothCPU(m);

    //GPU
    drawClothGPU();



    glBindTexture(GL_TEXTURE_2D, 0);

    glutSwapBuffers();
    count++;
    if (count == limit)
        exit(0);
    theTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
    if (theTime >= startTime + 1.0)
    {
        //printf("%d fps\n", count);
        startTime = theTime;
        count = 0;
    }
}

static void
init(void)
{

    glDisable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
    init_glsl_stuff();  //first shader stuff
    program = loadShaders("gears.vert", "gears.frag");
    glUseProgram(program);
    glUniform4fv(glGetUniformLocation(program, "pos"), 1, pos);
    glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"), 1, GL_TRUE, projectionMatrix);
    colorPos = glGetUniformLocation(program, "color");
    gVert = new float[size];
    gNorm = new float[size];
    float *pts = new float[vDensity*hDensity*4];
    float *norm = new float[vDensity*hDensity*4];
    int num = cloth1.drawShaded(gVert, gNorm);
    cloth1.getPoints(pts,norm);
    fbo1 = initFBO(hDensity, vDensity, 0,pts,norm);
    fbo2 = initFBO(hDensity, vDensity, 0,pts,norm);

    glGenVertexArrays(1, &clothVao);
    glBindVertexArray(clothVao);
    glGenBuffers(1, &clothVbo);
    glGenBuffers(1, &clothNbo);
    glGenBuffers(1, &clothTbo);

    glBindBuffer(GL_ARRAY_BUFFER, clothVbo);
    glBufferData(GL_ARRAY_BUFFER, num*9*sizeof(GLfloat), gVert, GL_STATIC_DRAW);

    glVertexAttribPointer(glGetAttribLocation(program, "in_Position"), 3, GL_FLOAT, GL_FALSE, 0, 0); 
    glEnableVertexAttribArray(glGetAttribLocation(program, "in_Position"));


    //VAO for quad
    glGenVertexArrays(1, &quadVao);
    glBindVertexArray(quadVao);

    //VBO for quad
    glGenBuffers(1, &quadVbo);
    glBindBuffer(GL_ARRAY_BUFFER, quadVbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);


    glBindVertexArray(0);

    delete [] gVert;
    delete [] gNorm;


    //texture
    texture_img = loadTexture("C:/Users/Bohb/Downloads/boa.jpg");

    location_Texture = glGetUniformLocation( program, "colorMap" );
    if(location_Texture == -1)
        fprintf( stderr, "Binding warning: Failed to locate uniform variable 'colorMap'.\n");

    frustum(-1.0, 1.0, -1.0, 1.0, 5.0, 60.0, projectionMatrix);

    startTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
    glBindVertexArray(clothVao);
}