예제 #1
0
int main( int argc, char* argv[] )
{
    // Initialise window
    pangolin::View& container = SetupPangoGLWithCuda(1024, 768);
    size_t cu_mem_start, cu_mem_end, cu_mem_total;
    cudaMemGetInfo( &cu_mem_start, &cu_mem_total );
    glClearColor(1,1,1,0);

    // Open video device
    hal::Camera video = OpenRpgCamera(argc,argv);

    // Capture first image
    pb::ImageArray images;

    // N cameras, each w*h in dimension, greyscale
    const size_t N = video.NumChannels();
    if( N != 2 ) {
        std::cerr << "Two images are required to run this program!" << std::endl;
        exit(1);
    }
    const size_t nw = video.Width();
    const size_t nh = video.Height();

    // Capture first image
    video.Capture(images);

    // Downsample this image to process less pixels
    const int max_levels = 6;
    const int level = roo::GetLevelFromMaxPixels( nw, nh, 640*480 );
//    const int level = 4;
    assert(level <= max_levels);

    // Find centered image crop which aligns to 16 pixels at given level
    const NppiRect roi = roo::GetCenteredAlignedRegion(nw,nh,16 << level,16 << level);

    // Load Camera intrinsics from file
    GetPot clArgs( argc, argv );
    const std::string filename = clArgs.follow("","-cmod");
    if( filename.empty() ) {
        std::cerr << "Camera models file is required!" << std::endl;
        exit(1);
    }
    const calibu::CameraRig rig = calibu::ReadXmlRig(filename);

    if( rig.cameras.size() != 2 ) {
        std::cerr << "Two camera models are required to run this program!" << std::endl;
        exit(1);
    }

    Eigen::Matrix3f CamModel0 = rig.cameras[0].camera.K().cast<float>();
    Eigen::Matrix3f CamModel1 = rig.cameras[1].camera.K().cast<float>();

    roo::ImageIntrinsics camMod[] = {
        {CamModel0(0,0),CamModel0(1,1),CamModel0(0,2),CamModel0(1,2)},
        {CamModel1(0,0),CamModel1(1,1),CamModel1(0,2),CamModel1(1,2)}
    };

    for(int i=0; i<2; ++i ) {
        // Adjust to match camera image dimensions
        const double scale = nw / rig.cameras[i].camera.Width();
        roo::ImageIntrinsics camModel = camMod[i].Scale( scale );

        // Adjust to match cropped aligned image
        camModel = camModel.CropToROI( roi );

        camMod[i] = camModel;
    }

    const unsigned int w = roi.width;
    const unsigned int h = roi.height;
    const unsigned int lw = w >> level;
    const unsigned int lh = h >> level;

    const Eigen::Matrix3d& K0 = camMod[0].Matrix();
    const Eigen::Matrix3d& Kl = camMod[0][level].Matrix();

    std::cout << "K Matrix: " << std::endl << K0 << std::endl;
    std::cout << "K Matrix - Level: " << std::endl << Kl << std::endl;

    std::cout << "Video stream dimensions: " << nw << "x" << nh << std::endl;
    std::cout << "Chosen Level: " << level << std::endl;
    std::cout << "Processing dimensions: " << lw << "x" << lh << std::endl;
    std::cout << "Offset: " << roi.x << "x" << roi.y << std::endl;

    // print selected camera model
    std::cout << "Camera Model used: " << std::endl << camMod[0][level].Matrix() << std::endl;

    Eigen::Matrix3d RDFvision;RDFvision<< 1,0,0,  0,1,0,  0,0,1;
    Eigen::Matrix3d RDFrobot; RDFrobot << 0,1,0,  0,0, 1,  1,0,0;
    Eigen::Matrix4d T_vis_ro = Eigen::Matrix4d::Identity();
    T_vis_ro.block<3,3>(0,0) = RDFvision.transpose() * RDFrobot;
    Eigen::Matrix4d T_ro_vis = Eigen::Matrix4d::Identity();
    T_ro_vis.block<3,3>(0,0) = RDFrobot.transpose() * RDFvision;

    const Sophus::SE3d T_rl_orig = T_rlFromCamModelRDF(rig.cameras[0], rig.cameras[1], RDFvision);

    // TODO(jmf): For now, assume cameras are rectified. Later allow unrectified cameras.
    /*
    double k1 = 0;
    double k2 = 0;

    if(cam[0].Type() == MVL_CAMERA_WARPED)
    {
        k1 = cam[0].GetModel()->warped.kappa1;
        k2 = cam[0].GetModel()->warped.kappa2;
    }
    */

    const bool rectify = false;
    if(!rectify) {
        std::cout << "Using pre-rectified images" << std::endl;
    }

    // Check we received at least two images
    if(images.Size() < 2) {
        std::cerr << "Failed to capture first stereo pair from camera" << std::endl;
        return -1;
    }

    // Define Camera Render Object (for view / scene browsing)
    pangolin::OpenGlRenderState s_cam(
        pangolin::ProjectionMatrixRDF_TopLeft(w,h,K0(0,0),K0(1,1),K0(0,2),K0(1,2),0.1,10000),
        pangolin::IdentityMatrix(pangolin::GlModelViewStack)
    );

    pangolin::GlBufferCudaPtr vbo(pangolin::GlArrayBuffer, lw*lh,GL_FLOAT, 4, cudaGraphicsMapFlagsWriteDiscard, GL_STREAM_DRAW );
    pangolin::GlBufferCudaPtr cbo(pangolin::GlArrayBuffer, lw*lh,GL_UNSIGNED_BYTE, 4, cudaGraphicsMapFlagsWriteDiscard, GL_STREAM_DRAW );
    pangolin::GlBuffer ibo = pangolin::MakeTriangleStripIboForVbo(lw,lh);

    // Allocate Camera Images on device for processing
    roo::Image<unsigned char, roo::TargetHost, roo::DontManage> hCamImg[] = {{0,nw,nh},{0,nw,nh}};
    roo::Image<float2, roo::TargetDevice, roo::Manage> dLookup[] = {{w,h},{w,h}};

    roo::Image<unsigned char, roo::TargetDevice, roo::Manage> upload(w,h);
    roo::Pyramid<unsigned char, max_levels, roo::TargetDevice, roo::Manage> img_pyr[] = {{w,h},{w,h}};

    roo::Image<float, roo::TargetDevice, roo::Manage> img[] = {{lw,lh},{lw,lh}};
    roo::Volume<float, roo::TargetDevice, roo::Manage> vol[] = {{lw,lh,MAXD},{lw,lh,MAXD}};
    roo::Image<float, roo::TargetDevice, roo::Manage>  disp[] = {{lw,lh},{lw,lh}};
    roo::Image<float, roo::TargetDevice, roo::Manage> meanI(lw,lh);
    roo::Image<float, roo::TargetDevice, roo::Manage> varI(lw,lh);
    roo::Image<float, roo::TargetDevice, roo::Manage> temp[] = {{lw,lh},{lw,lh},{lw,lh},{lw,lh},{lw,lh}};

    roo::Image<float,roo::TargetDevice, roo::Manage>& imgd = disp[0];
    roo::Image<float,roo::TargetDevice, roo::Manage> depthmap(lw,lh);
    roo::Image<float,roo::TargetDevice, roo::Manage> imga(lw,lh);
    roo::Image<float2,roo::TargetDevice, roo::Manage> imgq(lw,lh);
    roo::Image<float,roo::TargetDevice, roo::Manage> imgw(lw,lh);

    roo::Image<float4, roo::TargetDevice, roo::Manage>  d3d(lw,lh);
    roo::Image<unsigned char, roo::TargetDevice,roo::Manage> Scratch(lw*sizeof(roo::LeastSquaresSystem<float,6>),lh);

    typedef ulong4 census_t;
    roo::Image<census_t, roo::TargetDevice, roo::Manage> census[] = {{lw,lh},{lw,lh}};

    // Stereo transformation (post-rectification)
    Sophus::SE3d T_rl = T_rl_orig;

    const double baseline = T_rl.translation().norm();
    std::cout << "Baseline: " << baseline << std::endl;

    cudaMemGetInfo( &cu_mem_end, &cu_mem_total );
    std::cout << "CuTotal: " << cu_mem_total/(1024*1024) << ", Available: " << cu_mem_end/(1024*1024) << ", Used: " << (cu_mem_start-cu_mem_end)/(1024*1024) << std::endl;

    pangolin::Var<bool> step("ui.step", false, false);
    pangolin::Var<bool> run("ui.run", false, true);
    pangolin::Var<bool> lockToCam("ui.Lock to cam", false, true);
    pangolin::Var<int> show_slice("ui.show slice",MAXD/2, 0, MAXD-1);

    pangolin::Var<int> maxdisp("ui.maxdisp",MAXD, 0, MAXD);
    pangolin::Var<bool> subpix("ui.subpix", true, true);

    pangolin::Var<bool> use_census("ui.use census", true, true);
    pangolin::Var<int> avg_rad("ui.avg_rad",0, 0, 100);

    pangolin::Var<bool> do_dtam("ui.do dtam", false, true);
    pangolin::Var<bool> dtam_reset("ui.reset", false, false);

    pangolin::Var<float> g_alpha("ui.g alpha", 14, 0,4);
    pangolin::Var<float> g_beta("ui.g beta", 2.5, 0,2);


    pangolin::Var<float> theta("ui.theta", 100, 0,100);
    pangolin::Var<float> lambda("ui.lambda", 20, 0,20);
    pangolin::Var<float> sigma_q("ui.sigma q", 0.7, 0, 1);
    pangolin::Var<float> sigma_d("ui.sigma d", 0.7, 0, 1);
    pangolin::Var<float> huber_alpha("ui.huber alpha", 0.002, 0, 0.01);
    pangolin::Var<float> beta("ui.beta", 0.00001, 0, 0.01);

    pangolin::Var<float> alpha("ui.alpha", 0.9, 0,1);
    pangolin::Var<float> r1("ui.r1", 100, 0,0.01);
    pangolin::Var<float> r2("ui.r2", 100, 0,0.01);

    pangolin::Var<bool> filter("ui.filter", false, true);
    pangolin::Var<float> eps("ui.eps",0.01*0.01, 0, 0.01);
    pangolin::Var<int> rad("ui.radius",9, 1, 20);

    pangolin::Var<bool> leftrightcheck("ui.left-right check", false, true);
    pangolin::Var<float> maxdispdiff("ui.maxdispdiff",1, 0, 5);

    pangolin::Var<int> domedits("ui.median its",1, 1, 10);
    pangolin::Var<bool> domed9x9("ui.median 9x9", false, true);
    pangolin::Var<bool> domed7x7("ui.median 7x7", false, true);
    pangolin::Var<bool> domed5x5("ui.median 5x5", false, true);
    pangolin::Var<int> medi("ui.medi",12, 0, 24);

    pangolin::Var<float> filtgradthresh("ui.filt grad thresh", 0, 0, 20);

    pangolin::Var<bool> save_depthmaps("ui.save_depthmaps", false, true);

    int jump_frames = 0;

    pangolin::RegisterKeyPressCallback(' ', [&run](){run = !run;} );
    pangolin::RegisterKeyPressCallback('l', [&lockToCam](){lockToCam = !lockToCam;} );
    pangolin::RegisterKeyPressCallback(pangolin::PANGO_SPECIAL + GLUT_KEY_RIGHT, [&step](){step=true;} );
    pangolin::RegisterKeyPressCallback(']', [&jump_frames](){jump_frames=100;} );
    pangolin::RegisterKeyPressCallback('}', [&jump_frames](){jump_frames=1000;} );

    pangolin::Handler2dImageSelect handler2d(lw,lh,level);
//    ActivateDrawPyramid<unsigned char,max_levels> adleft(img_pyr[0],GL_LUMINANCE8, false, true);
//    ActivateDrawPyramid<unsigned char,max_levels> adright(img_pyr[1],GL_LUMINANCE8, false, true);
    pangolin::ActivateDrawImage<float> adleft(img[0],GL_LUMINANCE32F_ARB, false, true);
    pangolin::ActivateDrawImage<float> adright(img[1],GL_LUMINANCE32F_ARB, false, true);
    pangolin::ActivateDrawImage<float> adisp(disp[0],GL_LUMINANCE32F_ARB, false, true);
    pangolin::ActivateDrawImage<float> adw(imgw,GL_LUMINANCE32F_ARB, false, true);
//    ActivateDrawImage<float> adCrossSection(dCrossSection,GL_RGBA_FLOAT32_APPLE, false, true);
    pangolin::ActivateDrawImage<float> adVol(vol[0].ImageXY(show_slice),GL_LUMINANCE32F_ARB, false, true);

    SceneGraph::GLSceneGraph graph;
    SceneGraph::GLVbo glvbo(&vbo,&ibo,&cbo);
    graph.AddChild(&glvbo);

    SetupContainer(container, 6, (float)w/h);
    container[0].SetDrawFunction(boost::ref(adleft)).SetHandler(&handler2d);
    container[1].SetDrawFunction(boost::ref(adright)).SetHandler(&handler2d);
    container[2].SetDrawFunction(boost::ref(adisp)).SetHandler(&handler2d);
    container[3].SetDrawFunction(boost::ref(adVol)).SetHandler(&handler2d);
    container[4].SetDrawFunction(SceneGraph::ActivateDrawFunctor(graph, s_cam))
                .SetHandler( new pangolin::Handler3D(s_cam, pangolin::AxisNone) );
    container[5].SetDrawFunction(boost::ref(adw)).SetHandler(&handler2d);

    for(unsigned long frame=0; !pangolin::ShouldQuit();)
    {
        bool go = frame==0 || jump_frames > 0 || run || Pushed(step);

        for(; jump_frames > 0; jump_frames--) {
            video.Capture(images);
        }

        if(go) {
            if(frame>0) {
                if( video.Capture(images) == false) {
                    exit(1);
                }
            }

            frame++;

            /////////////////////////////////////////////////////////////
            // Upload images to device (Warp / Decimate if necessery)
            for(int i=0; i<2; ++i ) {
                hCamImg[i].ptr = images[i].data();

                if(rectify) {
                    upload.CopyFrom(hCamImg[i].SubImage(roi));
                    Warp(img_pyr[i][0], upload, dLookup[i]);
                }else{
                    img_pyr[i][0].CopyFrom(hCamImg[i].SubImage(roi));
                }

                roo::BoxReduce<unsigned char, max_levels, unsigned int>(img_pyr[i]);
            }
        }

        go |= avg_rad.GuiChanged() | use_census.GuiChanged();
        if( go ) {
            for(int i=0; i<2; ++i ) {
                roo::ElementwiseScaleBias<float,unsigned char,float>(img[i], img_pyr[i][level],1.0f/255.0f);
                if(avg_rad > 0 ) {
                    roo::BoxFilter<float,float,float>(temp[0],img[i],Scratch,avg_rad);
                    roo::ElementwiseAdd<float,float,float,float>(img[i], img[i], temp[0], 1, -1, 0.5);
                }
                if(use_census) {
                    Census(census[i], img[i]);
                }
            }
        }

        if( go | g_alpha.GuiChanged() || g_beta.GuiChanged() ) {
            ExponentialEdgeWeight(imgw, img[0], g_alpha, g_beta);
        }

        go |= filter.GuiChanged() | leftrightcheck.GuiChanged() | rad.GuiChanged() | eps.GuiChanged() | alpha.GuiChanged() | r1.GuiChanged() | r2.GuiChanged();
        if(go) {
            if(use_census) {
                roo::CensusStereoVolume<float, census_t>(vol[0], census[0], census[1], maxdisp, -1);
                if(leftrightcheck) roo::CensusStereoVolume<float, census_t>(vol[1], census[1], census[0], maxdisp, +1);
            }else{
                CostVolumeFromStereoTruncatedAbsAndGrad(vol[0], img[0], img[1], -1, alpha, r1, r2);
                if(leftrightcheck) CostVolumeFromStereoTruncatedAbsAndGrad(vol[1], img[1], img[0], +1, alpha, r1, r2);
            }

            if(filter) {
                // Filter Cost volume
                for(int v=0; v<(leftrightcheck?2:1); ++v)
                {
                    roo::Image<float, roo::TargetDevice, roo::Manage>& I = img[v];
                    roo::ComputeMeanVarience<float,float,float>(varI, temp[0], meanI, I, Scratch, rad);

                    for(int d=0; d<maxdisp; ++d)
                    {
                        roo::Image<float> P = vol[v].ImageXY(d);
                        roo::ComputeCovariance(temp[0],temp[2],temp[1],P,meanI,I,Scratch,rad);
                        GuidedFilter(P,temp[0],varI,temp[1],meanI,I,Scratch,temp[2],temp[3],temp[4],rad,eps);
                    }
                }
            }
        }

        static int n = 0;
//        static float theta = 0;
//        go |= Pushed(dtam_reset);
//        if(go )
        if(Pushed(dtam_reset))
        {
            n = 0;
            theta.Reset();

            // Initialise primal and auxillary variables
            CostVolMinimumSubpix(imgd,vol[0], maxdisp,-1);
            imga.CopyFrom(imgd);

            // Initialise dual variable
            imgq.Memset(0);
        }

        const double min_theta = 1E-0;
        if(do_dtam && theta > min_theta)
        {
            for(int i=0; i<5; ++i ) {
                // Auxillary exhaustive search
                CostVolMinimumSquarePenaltySubpix(imga, vol[0], imgd, maxdisp, -1, lambda, (theta) );

                // Dual Ascent
                roo::WeightedHuberGradU_DualAscentP(imgq, imgd, imgw, sigma_q, huber_alpha);

                // Primal Descent
                roo::WeightedL2_u_minus_g_PrimalDescent(imgd, imgq, imga, imgw, sigma_d, 1.0f / (theta) );

                theta= theta * (1-beta*n);
                ++n;
            }
            if( theta <= min_theta && save_depthmaps ) {
                cv::Mat dmap = cv::Mat( lh, lw, CV_32FC1 );
                // convert disparity to depth
                roo::Disp2Depth(imgd, depthmap, Kl(0,0), baseline );
                depthmap.MemcpyToHost( dmap.data );

                // save depth image
                char            Index[10];
                sprintf( Index, "%05d", frame );
                std::string DepthPrefix = "SDepth-";
                std::string DepthFile;
                DepthFile = DepthPrefix + Index + ".pdm";
                std::cout << "Depth File: " << DepthFile << std::endl;
                std::ofstream pDFile( DepthFile.c_str(), std::ios::out | std::ios::binary );
                pDFile << "P7" << std::endl;
                pDFile << dmap.cols << " " << dmap.rows << std::endl;
                unsigned int Size = dmap.elemSize1() * dmap.rows * dmap.cols;
                pDFile << 4294967295 << std::endl;
                pDFile.write( (const char*)dmap.data, Size );
                pDFile.close();

                // save grey image
                std::string GreyPrefix = "Left-";
                std::string GreyFile;
                GreyFile = GreyPrefix + Index + ".pgm";
                std::cout << "Grey File: " << GreyFile << std::endl;
                cv::Mat gimg = cv::Mat( lh, lw, CV_8UC1 );
                img_pyr[0][level].MemcpyToHost( gimg.data );
                cv::imwrite( GreyFile, gimg );

                 // reset
                step = true;
                dtam_reset = true;
            }
        }

        go |= pangolin::GuiVarHasChanged();
//        if(go) {
//            if(subpix) {
//                CostVolMinimumSubpix(disp[0],vol[0], maxdisp,-1);
//                if(leftrightcheck) CostVolMinimumSubpix(disp[1],vol[1], maxdisp,+1);
//            }else{
//                CostVolMinimum<float,float>(disp[0],vol[0], maxdisp);
//                if(leftrightcheck) CostVolMinimum<float,float>(disp[1],vol[1], maxdisp);
//            }

//        }

        if(go) {
            for(int di=0; di<(leftrightcheck?2:1); ++di) {
                for(int i=0; i < domedits; ++i ) {
                    if(domed9x9) MedianFilterRejectNegative9x9(disp[di],disp[di], medi);
                    if(domed7x7) MedianFilterRejectNegative7x7(disp[di],disp[di], medi);
                    if(domed5x5) MedianFilterRejectNegative5x5(disp[di],disp[di], medi);
                }
            }

            if(leftrightcheck ) {
                LeftRightCheck(disp[1], disp[0], +1, maxdispdiff);
                LeftRightCheck(disp[0], disp[1], -1, maxdispdiff);
            }

            if(filtgradthresh > 0) {
                FilterDispGrad(disp[0], disp[0], filtgradthresh);
            }
        }

//        if(go)
        {
            // Generate point cloud from disparity image
            DisparityImageToVbo(d3d, disp[0], baseline, Kl(0,0), Kl(1,1), Kl(0,2), Kl(1,2) );

//            if(container[3].IsShown())
            {
                // Copy point cloud into VBO
                {
                    pangolin::CudaScopedMappedPtr var(vbo);
                    roo::Image<float4> dVbo((float4*)*var,lw,lh);
                    dVbo.CopyFrom(d3d);
                }

                // Generate CBO
                {
                    pangolin::CudaScopedMappedPtr var(cbo);
                    roo::Image<uchar4> dCbo((uchar4*)*var,lw,lh);
                    roo::ConvertImage<uchar4,unsigned char>(dCbo, img_pyr[0][level]);
                }
            }

            // Update texture views
            adisp.SetImageScale(1.0f/maxdisp);
//            adleft.SetLevel(show_level);
//            adright.SetLevel(show_level);
            adVol.SetImage(vol[0].ImageXY(show_slice));
        }

        /////////////////////////////////////////////////////////////
        // Draw

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glColor3f(1,1,1);

        pangolin::FinishFrame();
    }
}
예제 #2
0
int main( void )
{

	crap::audiodevice audio_device;
	
	/*
	openalcode



	*/

	//setup window
	crap::window_setup win_setup;
	win_setup.title = "Funny Window";
	win_setup.width = 1024;
	win_setup.height = 768;
	win_setup.multisampling_count = 8;
	win_setup.opengl_version = 3.3f;
    win_setup.opengl_profile = crap::compat;

	//create window
	crap::window window( win_setup );
	window.open();

	//get keyboard and mouse
	crap::keyboard keyboard;
	crap::mouse mouse;

	// temporary
	crap::opengl::enable(crap::opengl::depth_test);
	crap::opengl::setDepthComparison(crap::opengl::less);
	crap::opengl::enable(crap::opengl::cull_face);

	//camera setup
	camera cam;
	cam.setPosition( glm::vec3( 0.0f, 0.0f, 5.0f ) );
	mouse_pos = mouse.position();

	//create contentmanager
	content_manager cm;
	cm.init( "spg.ini" );

	//create vertex array
	crap::vertex_array vert_array;
	vert_array.bind();

	//test: load vbo onto GPU
	vbo cube_vbo( "cube", &cm, vbo::static_draw );
	vbo ape_vbo("ape", &cm, vbo::static_draw );
	vbo cube_big_vbo( "cube", &cm, vbo::static_draw );
	//vbo people_vbo("people", &cm, vbo::static_draw );

	//////////////////////////
	// Read our .obj file
	std::vector<glm::vec3> vertices;
	std::vector<glm::vec2> uvs;
	std::vector<glm::vec3> normals;
	bool res = loadOBJ("../../../data/geometry/dupercube.obj", vertices, uvs, normals);

	std::vector<glm::vec3> tangents;
	std::vector<glm::vec3> bitangents;
	computeTangentBasis(
		vertices, uvs, normals, // input
		tangents, bitangents    // output
	);

	std::vector<unsigned short> indices;
	std::vector<glm::vec3> indexed_vertices;
	std::vector<glm::vec2> indexed_uvs;
	std::vector<glm::vec3> indexed_normals;
	std::vector<glm::vec3> indexed_tangents;
	std::vector<glm::vec3> indexed_bitangents;
	indexVBO_TBN(
		vertices, uvs, normals, tangents, bitangents, 
		indices, indexed_vertices, indexed_uvs, indexed_normals, indexed_tangents, indexed_bitangents
	);

	GLuint vertexbuffer;
	glGenBuffers(1, &vertexbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
	glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(glm::vec3), &indexed_vertices[0], GL_STATIC_DRAW);

	GLuint uvbuffer;
	glGenBuffers(1, &uvbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
	glBufferData(GL_ARRAY_BUFFER, indexed_uvs.size() * sizeof(glm::vec2), &indexed_uvs[0], GL_STATIC_DRAW);

	GLuint normalbuffer;
	glGenBuffers(1, &normalbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
	glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(glm::vec3), &indexed_normals[0], GL_STATIC_DRAW);

	GLuint tangentbuffer;
	glGenBuffers(1, &tangentbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, tangentbuffer);
	glBufferData(GL_ARRAY_BUFFER, indexed_tangents.size() * sizeof(glm::vec3), &indexed_tangents[0], GL_STATIC_DRAW);

	GLuint bitangentbuffer;
	glGenBuffers(1, &bitangentbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, bitangentbuffer);
	glBufferData(GL_ARRAY_BUFFER, indexed_bitangents.size() * sizeof(glm::vec3), &indexed_bitangents[0], GL_STATIC_DRAW);

	// Generate a buffer for the indices as well
	GLuint elementbuffer;
	glGenBuffers(1, &elementbuffer);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW);
	/////////////////////////

	geometry_content ig;
	cm.create_content( "cube" , &ig, type_name::geometry );

	//test: load texture onto GPU
	tbo diffuse_tbo( "stone_diff", &cm, tbo::tga );
	tbo normal_tbo( "stone_norm", &cm, tbo::tga );
	tbo height_tbo( "stone_height", &cm, tbo::tga );

	//shadow stuff
	crap::frame_buffer frame_buffer;
	frame_buffer.bind();
	tbo depthmap( "", &cm, tbo::depth );
	frame_buffer.unbind();

	//shadow stuff
	crap::quad_buffer quad_buffer;

	//test: load linked shader progam onto GPU
	shader_manager sm(&cm);
	sm.add("epr_vert", "epr_frag");
	sm.add("shadow_vert", "shadow_frag");
	
	//get stuff from shader program
	//shadow shader
	sm.set_current("shadow_vert", "shadow_frag");
	crap::uniform DepthBiasMVPID = sm.current()->uniform_location("depthMVP");

	//vertex shader
	sm.set_current("epr_vert", "epr_frag");
	crap::uniform WorldMatrixID = sm.current()->uniform_location("world_matrix4x4");
	crap::uniform ViewMatrixID = sm.current()->uniform_location("view_matrix4x4");
	crap::uniform ModelMatrixID = sm.current()->uniform_location("model_matrix4x4");
	crap::uniform ModelView3x3MatrixID = sm.current()->uniform_location("model_view_matrix3x3");

	//fragment shader
	crap::uniform DiffuseTextureID  = sm.current()->uniform_location("diffuse_texture");
	crap::uniform NormalTextureID  = sm.current()->uniform_location("normal_texture");
	crap::uniform HeightTextureID = sm.current()->uniform_location("height_texture");

	crap::uniform LightAmbientPowerID = sm.current()->uniform_location("ambient_power");

	crap::uniform LightPowerArrayID = sm.current()->uniform_location("light_power");
	crap::uniform LightSpecularTypeArrayID = sm.current()->uniform_location("light_specular_type");
	crap::uniform LightSpecularLobeArrayID = sm.current()->uniform_location("light_specular_lobe");
	crap::uniform LightColorArrayID = sm.current()->uniform_location("light_color");
	crap::uniform LightSelfShadowingOnID = sm.current()->uniform_location("selfshadowing_on");

	crap::uniform DisplacementOnID = sm.current()->uniform_location("displacement_on");
	crap::uniform DisplacementStepsID = sm.current()->uniform_location("displacement_steps");
	crap::uniform DisplacementRefinementStepsID = sm.current()->uniform_location("displacement_refinement_steps");
	crap::uniform DisplacementUVFactorID = sm.current()->uniform_location("displacement_uv_factor");

	//both shaders
	crap::uniform LightPositionArrayID = sm.current()->uniform_location("light_position");
	crap::uniform LightDirectionArrayID = sm.current()->uniform_location("light_direction");
	crap::uniform LightTypeArrayID = sm.current()->uniform_location("light_type");
	crap::uniform LightStateArrayID = sm.current()->uniform_location("light_state");

	crap::uniform LightNormalMappingOnID = sm.current()->uniform_location("normal_mapping_on");

	//shadow stuff
	crap::uniform ShadowMapID = sm.current()->uniform_location("shadow_map");
	crap::uniform ShadowMappingOnID = sm.current()->uniform_location("shadow_mapping_on");
	crap::uniform ShadowDepthBiasMVPID = sm.current()->uniform_location("depth_bias_mvp");

	//SHADER DATA
	// Projection matrix : 60° Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
	float display_field_of_view = 60.f; //60°
	float display_ratio_horizontal = 4.f;
	float display_ratio_vertical = 3.f;
	float display_range_near = 0.1f;
	float display_range_far = 100.f;

	glm::mat4 projection_matrix = glm::perspective(
		display_field_of_view, 
		display_ratio_horizontal / display_ratio_vertical, 
		display_range_near, 
		display_range_far);

	glm::mat4 model_matrix(1.0f);
	glm::mat4 model_view_matrix(1.0f);
	glm::mat4 view_matrix = cam.view();
	glm::mat4 world_matrix(1.0f);
	glm::mat3 model_view_matrix3x3(1.0f);

	//light stuff
	float light_ambient_power = 0.5f;
	float light_power_array[MAX_LIGHTS] = { 1.f, 1.f, 1.f };
	int light_specular_type_array[MAX_LIGHTS] = { 1, 1, 1 };
	float light_specular_lobe_array[MAX_LIGHTS] = { 100.f, 100.f, 100.f };
	glm::vec3 light_color_array[MAX_LIGHTS] = { glm::vec3(1.f), glm::vec3(1.f), glm::vec3(1.f) };
	int light_self_shadowing_on = 1;
	glm::vec3 light_position_array[MAX_LIGHTS] = { glm::vec3(4,0,0), glm::vec3(0,0,-4), glm::vec3(4,4,4) };
	glm::vec3 light_direction_array[MAX_LIGHTS] = { glm::vec3(-4,0,0), glm::vec3(0,0,4), glm::vec3(-4,-4,-4) };
	int light_type_array[MAX_LIGHTS] = { 0, 0, 0 };
	int light_state_array[MAX_LIGHTS] = { 1, 0, 0 };
	int light_normal_mapping_on = 1;

	//shadowstuff
	int shadow_mapping_on = 1;

	//displacement stuff
	int displacement_on = 1;
	float displacement_steps = 20;
	float displacement_refinement_steps = 20;
	float displacmenet_uv_factor = 20;

	//GUI
	TwInit(TW_OPENGL, NULL);
	TwWindowSize(1024, 768);

	TwBar * GeneralGUI = TwNewBar("General settings");
	TwBar * LightGUI = TwNewBar("Light Settings");
	TwBar * DisplacementGUI = TwNewBar("Displacement Settings");

	TwSetParam(GeneralGUI, NULL, "refresh", TW_PARAM_CSTRING, 1, "0.1");
	TwSetParam(LightGUI, NULL, "refresh", TW_PARAM_CSTRING, 1, "0.1");
	TwSetParam(DisplacementGUI, NULL, "refresh", TW_PARAM_CSTRING, 1, "0.1");

	//general gui
	TwAddSeparator(GeneralGUI, "Funny seperator", NULL);
	TwAddVarRW(GeneralGUI, "Field of View", TW_TYPE_FLOAT , &display_field_of_view, "help='Field of View value'");
	TwAddVarRW(GeneralGUI, "Ratio Horizontal", TW_TYPE_FLOAT , &display_ratio_horizontal, "help='Ratio Horizontal'");
	TwAddVarRW(GeneralGUI, "Ratio Vertical", TW_TYPE_FLOAT , &display_ratio_vertical, "help='Ratio Vertical'");
	TwAddVarRW(GeneralGUI, "Range Near", TW_TYPE_FLOAT , &display_range_near, "help='Range near'");
	TwAddVarRW(GeneralGUI, "Range far", TW_TYPE_FLOAT , &display_range_far, "help='Range far'");

	//light gui
	TwAddVarRW(LightGUI, "Ambient light", TW_TYPE_FLOAT , &light_ambient_power, "help='Ambient power'");
	TwAddVarRW(LightGUI, "Self Shadowing", TW_TYPE_BOOL32, &light_self_shadowing_on, NULL);
	TwAddVarRW(LightGUI, "Normal Mapping", TW_TYPE_BOOL32, &light_normal_mapping_on, NULL);
	TwType gui_light_type = TwDefineEnumFromString("LightType", "Directionallight,Pointlight");
	TwType gui_light_specular_type = TwDefineEnumFromString("LightSpecularType", "Blinn,Phong");
	//shadow
	TwAddVarRW(LightGUI, "Cast Shadows", TW_TYPE_BOOL32, &shadow_mapping_on, NULL);
	//light1
	TwAddVarRW(LightGUI, "Light 1", TW_TYPE_BOOL32, light_state_array, NULL);
	TwAddVarRW(LightGUI, "Light Type 1", gui_light_type, light_type_array, NULL);
	TwAddVarRW(LightGUI, "Light Specular Type 1", gui_light_specular_type, light_specular_type_array, NULL);
	TwAddVarRW(LightGUI, "Light Power 1", TW_TYPE_FLOAT , light_power_array, NULL);
	TwAddVarRW(LightGUI, "Light Specular Lobe 1", TW_TYPE_FLOAT , light_specular_lobe_array, NULL);
	TwAddVarRW(LightGUI, "Light Color 1", TW_TYPE_COLOR3F , light_color_array, NULL);
	TwAddVarRW(LightGUI, "Light Position 1", TW_TYPE_DIR3F , light_position_array, NULL);
	TwAddVarRW(LightGUI, "Light Direction 1", TW_TYPE_DIR3F , light_direction_array, NULL);
	//light2
	TwAddVarRW(LightGUI, "Light 2", TW_TYPE_BOOL32, light_state_array+1, NULL);
	TwAddVarRW(LightGUI, "Light Type 2", gui_light_type, light_type_array+1, NULL);
	TwAddVarRW(LightGUI, "Light Specular Type 2", gui_light_specular_type, light_specular_type_array+1, NULL);
	TwAddVarRW(LightGUI, "Light Power 2", TW_TYPE_FLOAT , light_power_array+1, NULL);
	TwAddVarRW(LightGUI, "Light Specular Lobe 2", TW_TYPE_FLOAT , light_specular_lobe_array+1, NULL);
	TwAddVarRW(LightGUI, "Light Color 2", TW_TYPE_COLOR3F , light_color_array+1, NULL);
	TwAddVarRW(LightGUI, "Light Position 2", TW_TYPE_DIR3F , light_position_array+1, NULL);
	TwAddVarRW(LightGUI, "Light Direction 2", TW_TYPE_DIR3F , light_direction_array+1, NULL);
	//light3
	TwAddVarRW(LightGUI, "Light 3", TW_TYPE_BOOL32, light_state_array+2, NULL);
	TwAddVarRW(LightGUI, "Light Type 3", gui_light_type, light_type_array+2, NULL);
	TwAddVarRW(LightGUI, "Light Specular Type 3", gui_light_specular_type, light_specular_type_array+2, NULL);
	TwAddVarRW(LightGUI, "Light Power 3", TW_TYPE_FLOAT , light_power_array+2, NULL);
	TwAddVarRW(LightGUI, "Light Specular Lobe 3", TW_TYPE_FLOAT , light_specular_lobe_array+2, NULL);
	TwAddVarRW(LightGUI, "Light Color 3", TW_TYPE_COLOR3F , light_color_array+2, NULL);
	TwAddVarRW(LightGUI, "Light Position 3", TW_TYPE_DIR3F , light_position_array+2, NULL);
	TwAddVarRW(LightGUI, "Light Direction 3", TW_TYPE_DIR3F , light_direction_array+2, NULL);

	//displacement gui
	TwAddVarRW(DisplacementGUI, "Displacement ON/OFF", TW_TYPE_BOOL32, &displacement_on, NULL);
	TwAddVarRW(DisplacementGUI, "Displacment steps", TW_TYPE_FLOAT , &displacement_steps, NULL);
	TwAddVarRW(DisplacementGUI, "Displacement refinement", TW_TYPE_FLOAT , &displacement_refinement_steps, NULL);
	TwAddVarRW(DisplacementGUI, "Displacement UV factor", TW_TYPE_FLOAT , &displacmenet_uv_factor, NULL);

	//gui mouse setup
	mouse.set_on_pressed_function( (crap::mouse::user_button_callback_function)gui_mouse_down );
	mouse.set_on_release_function( (crap::mouse::user_button_callback_function)gui_mouse_up );
	mouse.set_on_move_function( (crap::mouse::user_move_callback_function)TwEventMousePosGLFW );
	mouse.set_on_wheel_function( (crap::mouse::user_wheel_callback_function)TwEventMouseWheelGLFW );
	keyboard.set_on_pressed_function( (crap::keyboard::user_callback_function)TwEventKeyGLFW );
	//todo set char input

	// temporary
	crap::opengl::clearColor(1.0f, 1.0f, 1.0f, 0.0f);

	while( !keyboard.is_pressed( crap::keyboard::key_escape ) && window.is_open() )
	{
		// update positions
		handleInput(keyboard, mouse, cam);

		crap::opengl::clear(crap::opengl::color_depth_buffer);

		frame_buffer.bind();
		glViewport(0,0,1024,1024); // Render on the whole framebuffer, complete from the lower left corner to the upper right
		sm.set_current("shadow_vert", "shadow_frag");
		sm.activate();

		glm::vec3 lightInvDir = light_direction_array[0]; //glm::vec3(0.5f,2,2);

		// Compute the MVP matrix from the light's point of view
		glm::mat4 depthProjectionMatrix = glm::ortho<float>(-10,10,-10,10,-10,20);
		glm::mat4 depthViewMatrix = glm::lookAt(lightInvDir, glm::vec3(0,0,0), glm::vec3(0,1,0));
		glm::mat4 depthModelMatrix = glm::mat4(1.0);
		glm::mat4 depthMVP = depthProjectionMatrix * depthViewMatrix * depthModelMatrix;

		sm.current()->uniform_matrix4f_value( DepthBiasMVPID, 1, &depthMVP[0][0]);

		sm.current()->vertex_attribute_array.enable(0);
		cube_vbo.bind_buffer( vbo::verticies );
		sm.current()->vertex_attribute_array.pointer( 0, 3, crap::gl_float, false, 0, (void*)0);

		cube_vbo.bind_buffer( vbo::indicies );
		crap::opengl::draw_elements(
			crap::opengl::triangles,		// mode
			cube_vbo.indicies_size,			// count
			crap::opengl::unsigned_short	// type
		);

		sm.current()->vertex_attribute_array.disable(0);

		frame_buffer.unbind();

		glViewport(0,0,1024,768); // Render on the whole framebuffer, complete from the lower left corner to the upper right

		crap::opengl::clear(crap::opengl::color_depth_buffer);

		sm.set_current("epr_vert", "epr_frag");
		sm.activate();

		///////////////////////////////////////
		//////////////////////////////////////

		projection_matrix = glm::perspective(
			display_field_of_view, 
			display_ratio_horizontal / display_ratio_vertical, 
			display_range_near, 
			display_range_far);

		view_matrix = cam.view();
		model_view_matrix = view_matrix * world_matrix;
		model_view_matrix3x3 = glm::mat3(model_view_matrix);
		world_matrix = projection_matrix * view_matrix * model_matrix;

		glm::mat4 biasMatrix(
			0.5, 0.0, 0.0, 0.0, 
			0.0, 0.5, 0.0, 0.0,
			0.0, 0.0, 0.5, 0.0,
			0.5, 0.5, 0.5, 1.0
		);

		glm::mat4 depthBiasMVP = biasMatrix*depthMVP;
		
		sm.current()->uniform_matrix4f_value( ShadowDepthBiasMVPID, 1, &depthBiasMVP[0][0]);
		sm.current()->uniform_1i(ShadowMappingOnID, shadow_mapping_on);

		//activate shader porgram and connect data
		//sm.activate();
		//default stuff
		sm.current()->uniform_matrix4f_value( WorldMatrixID, 1, &world_matrix[0][0]);
		sm.current()->uniform_matrix4f_value( ModelMatrixID, 1, &model_matrix[0][0]);
		sm.current()->uniform_matrix4f_value( ViewMatrixID, 1, &view_matrix[0][0]);
		sm.current()->uniform_matrix3f_value( ModelView3x3MatrixID, 1, &model_view_matrix3x3[0][0]);
		//light
		sm.activate();
		sm.current()->uniform_1f(LightAmbientPowerID, light_ambient_power);
		sm.current()->uniform_1i(LightSelfShadowingOnID, light_self_shadowing_on);
		sm.current()->uniform_1i(LightNormalMappingOnID, light_normal_mapping_on);
		sm.current()->uniform_1f_value( LightPowerArrayID, 3, light_power_array );
		sm.current()->uniform_1i_value( LightSpecularTypeArrayID, 3, light_specular_type_array );
		sm.current()->uniform_1f_value( LightSpecularLobeArrayID, 3, light_specular_lobe_array );
		sm.current()->uniform_3f_value( LightColorArrayID, 3, (f32*)light_color_array );
		sm.current()->uniform_3f_value( LightPositionArrayID, 3, (f32*)light_position_array );
		sm.current()->uniform_3f_value( LightDirectionArrayID, 3, (f32*)light_direction_array );
		sm.current()->uniform_1i_value( LightTypeArrayID, 3, light_type_array );
		sm.current()->uniform_1i_value( LightStateArrayID, 3, light_state_array );
		//displacement
		sm.current()->uniform_1i( DisplacementOnID, displacement_on );
		sm.current()->uniform_1f( DisplacementStepsID, displacement_steps);
		sm.current()->uniform_1f( DisplacementRefinementStepsID, displacement_refinement_steps);
		sm.current()->uniform_1f( DisplacementUVFactorID, displacmenet_uv_factor);

		//activate texture buffer and connect data
		diffuse_tbo.activate();
		diffuse_tbo.bind_buffer();
		sm.current()->uniform_1i( DiffuseTextureID, 0);

		normal_tbo.activate();
		normal_tbo.bind_buffer();
		sm.current()->uniform_1i( NormalTextureID, 1);

		height_tbo.activate();
		height_tbo.bind_buffer();
		sm.current()->uniform_1i( HeightTextureID, 2 );

		depthmap.activate();
		depthmap.bind_buffer();
		sm.current()->uniform_1i( ShadowMapID, 4);

		//define data of buffers
		sm.current()->vertex_attribute_array.enable(0);
		//cube_vbo.bind_buffer( vbo::verticies );
		glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
		sm.current()->vertex_attribute_array.pointer( 0, 3, crap::gl_float, false, 0, (void*)0);

		sm.current()->vertex_attribute_array.enable(1);
		glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
		//cube_vbo.bind_buffer( vbo::uvs );
		sm.current()->vertex_attribute_array.pointer( 1, 2, crap::gl_float, false, 0, (void*)0);

		sm.current()->vertex_attribute_array.enable(2);
		glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
		//cube_vbo.bind_buffer( vbo::normals );
		sm.current()->vertex_attribute_array.pointer( 2, 3, crap::gl_float, false, 0, (void*)0);

		sm.current()->vertex_attribute_array.enable(3);
		glBindBuffer(GL_ARRAY_BUFFER, tangentbuffer);
		//cube_vbo.bind_buffer( vbo::tangents );
		sm.current()->vertex_attribute_array.pointer( 3, 3, crap::gl_float, false, 0, (void*)0);

		sm.current()->vertex_attribute_array.enable(4);
		glBindBuffer(GL_ARRAY_BUFFER, bitangentbuffer);
		//cube_vbo.bind_buffer( vbo::binormals );
		sm.current()->vertex_attribute_array.pointer( 4, 3, crap::gl_float, false, 0, (void*)0);

		////draw the f**k
		cube_vbo.bind_buffer( vbo::indicies );
		crap::opengl::draw_elements(
			crap::opengl::triangles,		// mode
			cube_vbo.indicies_size,			// count
			crap::opengl::unsigned_short	// type
		);

		sm.current()->vertex_attribute_array.disable(0);
		sm.current()->vertex_attribute_array.disable(1);
		sm.current()->vertex_attribute_array.disable(2);
		sm.current()->vertex_attribute_array.disable(3);
		sm.current()->vertex_attribute_array.disable(4);

		//next object
		glm::mat4 model_matrix_2 = model_matrix * glm::translate(3.f,0.f,0.f);
		model_view_matrix = view_matrix * model_matrix_2;
		model_view_matrix3x3 = glm::mat3(model_view_matrix);
		world_matrix = projection_matrix * view_matrix * model_matrix_2;

		//activate shader porgram and connect data
		//sm.activate();
		sm.current()->uniform_matrix4f_value( WorldMatrixID, 1, &world_matrix[0][0]);
		sm.current()->uniform_matrix4f_value( ModelMatrixID, 1, &model_matrix_2[0][0]);
		sm.current()->uniform_matrix3f_value( ModelView3x3MatrixID, 1, &model_view_matrix3x3[0][0]);

		//attempt
		//define data of buffers
		sm.current()->vertex_attribute_array.enable(0);
		ape_vbo.bind_buffer( vbo::verticies );
		sm.current()->vertex_attribute_array.pointer( 0, 3, crap::gl_float, false, 0, (void*)0);

		sm.current()->vertex_attribute_array.enable(1);
		ape_vbo.bind_buffer( vbo::uvs );
		sm.current()->vertex_attribute_array.pointer( 1, 2, crap::gl_float, false, 0, (void*)0);

		sm.current()->vertex_attribute_array.enable(2);
		ape_vbo.bind_buffer( vbo::normals );
		sm.current()->vertex_attribute_array.pointer( 2, 3, crap::gl_float, false, 0, (void*)0);

		sm.current()->vertex_attribute_array.enable(3);
		ape_vbo.bind_buffer( vbo::tangents );
		sm.current()->vertex_attribute_array.pointer(3, 3, crap::gl_float, false, 0, (void*)0);

		sm.current()->vertex_attribute_array.enable(4);
		ape_vbo.bind_buffer( vbo::binormals );
		sm.current()->vertex_attribute_array.pointer( 4, 3, crap::gl_float, false, 0, (void*)0);


		//draw the f**k
		ape_vbo.bind_buffer( vbo::indicies );
		crap::opengl::draw_elements(
			crap::opengl::triangles,		// mode
			ape_vbo.indicies_size,			// count
			crap::opengl::unsigned_short	// type
		);

		//disable data define stuff
		sm.current()->vertex_attribute_array.disable(0);
		sm.current()->vertex_attribute_array.disable(1);
		sm.current()->vertex_attribute_array.disable(2);
		sm.current()->vertex_attribute_array.disable(3);
		sm.current()->vertex_attribute_array.disable(4);

		//next object
		glm::mat4 model_matrix_3 = model_matrix * glm::translate(0.f,-2.f,0.f);
		model_view_matrix = view_matrix * model_matrix_2;
		model_view_matrix3x3 = glm::mat3(model_view_matrix);
		world_matrix = projection_matrix * view_matrix * model_matrix_3;

		//activate shader porgram and connect data
		//sm.activate();
		sm.current()->uniform_matrix4f_value( WorldMatrixID, 1, &world_matrix[0][0]);
		sm.current()->uniform_matrix4f_value( ModelMatrixID, 1, &model_matrix_3[0][0]);
		sm.current()->uniform_matrix3f_value( ModelView3x3MatrixID, 1, &model_view_matrix3x3[0][0]);

		//attempt
		//define data of buffers
		sm.current()->vertex_attribute_array.enable(0);
		cube_big_vbo.bind_buffer( vbo::verticies );
		sm.current()->vertex_attribute_array.pointer( 0, 3, crap::gl_float, false, 0, (void*)0);

		sm.current()->vertex_attribute_array.enable(1);
		cube_big_vbo.bind_buffer( vbo::uvs );
		sm.current()->vertex_attribute_array.pointer( 1, 2, crap::gl_float, false, 0, (void*)0);

		sm.current()->vertex_attribute_array.enable(2);
		cube_big_vbo.bind_buffer( vbo::normals );
		sm.current()->vertex_attribute_array.pointer( 2, 3, crap::gl_float, false, 0, (void*)0);

		sm.current()->vertex_attribute_array.enable(3);
		cube_big_vbo.bind_buffer( vbo::tangents );
		sm.current()->vertex_attribute_array.pointer(3, 3, crap::gl_float, false, 0, (void*)0);

		sm.current()->vertex_attribute_array.enable(4);
		cube_big_vbo.bind_buffer( vbo::binormals );
		sm.current()->vertex_attribute_array.pointer( 4, 3, crap::gl_float, false, 0, (void*)0);


		//draw the f**k
		cube_big_vbo.bind_buffer( vbo::indicies );
		crap::opengl::draw_elements(
			crap::opengl::triangles,		// mode
			cube_big_vbo.indicies_size,			// count
			crap::opengl::unsigned_short	// type
		);

		//disable data define stuff
		sm.current()->vertex_attribute_array.disable(0);
		sm.current()->vertex_attribute_array.disable(1);
		sm.current()->vertex_attribute_array.disable(2);
		sm.current()->vertex_attribute_array.disable(3);
		sm.current()->vertex_attribute_array.disable(4);

		glMatrixMode(GL_PROJECTION);
		glLoadMatrixf((const GLfloat*)&projection_matrix[0]);
		glMatrixMode(GL_MODELVIEW);
		glm::mat4 MV = view_matrix * model_matrix;
		glLoadMatrixf((const GLfloat*)&MV[0]);

		sm.activate();

		// normals
		glColor3f(0,0,1);
		glBegin(GL_LINES);
		for (unsigned int i=0; i<ig.indices_size; i++){
			glm::vec3 p = glm::vec3(ig.positions[ig.indices[i]].x, ig.positions[ig.indices[i]].y, ig.positions[ig.indices[i]].z );
			glVertex3fv(&p.x);
			glm::vec3 o = glm::normalize( glm::vec3(ig.normals[ig.indices[i]].x, ig.normals[ig.indices[i]].y, ig.normals[ig.indices[i]].z)  );
			p+=o*0.1f;
			glVertex3fv(&p.x);
		}
		glEnd();
		// tangents
		glColor3f(1,0,0);
		glBegin(GL_LINES);
		for (unsigned int i=0; i<ig.indices_size; i++){
			glm::vec3 p = glm::vec3(ig.positions[ig.indices[i]].x, ig.positions[ig.indices[i]].y, ig.positions[ig.indices[i]].z );
			glVertex3fv(&p.x);
			glm::vec3 o = glm::normalize( glm::vec3(ig.tangents[ig.indices[i]].x, ig.tangents[ig.indices[i]].y, ig.tangents[ig.indices[i]].z)  );
			p+=o*0.1f;
			glVertex3fv(&p.x);
		}
		glEnd();

		// bitangents
		glColor3f(0,1,0);
		glBegin(GL_LINES);
		for (unsigned int i=0; i<ig.indices_size; i++){
			glm::vec3 p = glm::vec3(ig.positions[ig.indices[i]].x, ig.positions[ig.indices[i]].y, ig.positions[ig.indices[i]].z );
			glVertex3fv(&p.x);
			glm::vec3 o = glm::normalize( glm::vec3(ig.binormals[ig.indices[i]].x, ig.binormals[ig.indices[i]].y, ig.binormals[ig.indices[i]].z)  );
			p+=o*0.1f;
			glVertex3fv(&p.x);
		}
		glEnd();

		glm::vec3 debug_light;

		// light pos 1
		glColor3f(1,1,1);
		glBegin(GL_LINES);
			debug_light = light_position_array[0];
			glVertex3fv(&debug_light.x);
			debug_light+=glm::vec3(1,0,0)*0.1f;
			glVertex3fv(&debug_light.x);
			debug_light-=glm::vec3(1,0,0)*0.1f;
			glVertex3fv(&debug_light.x);
			debug_light+=glm::vec3(0,1,0)*0.1f;
			glVertex3fv(&debug_light.x);
		glEnd();


			// light pos 2
			glColor3f(1,1,1);
			glBegin(GL_LINES);
				debug_light = light_position_array[1];
				glVertex3fv(&debug_light.x);
				debug_light+=glm::vec3(1,0,0)*0.1f;
				glVertex3fv(&debug_light.x);
				debug_light-=glm::vec3(1,0,0)*0.1f;
				glVertex3fv(&debug_light.x);
				debug_light+=glm::vec3(0,1,0)*0.1f;
				glVertex3fv(&debug_light.x);
			glEnd();
	


			// light pos3
			glColor3f(1,1,1);
			glBegin(GL_LINES);
				debug_light = light_position_array[2];
				glVertex3fv(&debug_light.x);
				debug_light+=glm::vec3(1,0,0)*0.1f;
				glVertex3fv(&debug_light.x);
				debug_light-=glm::vec3(1,0,0)*0.1f;
				glVertex3fv(&debug_light.x);
				debug_light+=glm::vec3(0,1,0)*0.1f;
				glVertex3fv(&debug_light.x);
			glEnd();
		

		// Draw GUI
		TwDraw();

		//poll and swap
		window.swap();
		window.poll_events();

	}

	TwTerminate();

	//geometry_content ig;
	//cm.create_content( "ape" , &ig, type_name::geometry );

	//texture_content tc;
	//cm.create_content( "color", &tc, type_name::texture );

	//shader_content sc;
	//cm.create_content( "fragment_texture_only", &sc, type_name::shader );

	//cm.save_content( "fragment_texture_only", &sc, type_name::shader );
	return 0;
}