void PointsRenderer::updateVaoAndVbo(const Cloud::Key &key, const std::shared_ptr<Cloud> &cloud) {
  auto points = cloud->point_cloud()->points;
  set_size(key, points.size());
  vbo(key)->copyData(points.size() * sizeof(Cloud::PointT), points.data());
  cinder::gl::ScopedVao svao(vao(key));
  cinder::gl::ScopedBuffer svbo(vbo(key));
  cinder::gl::enableVertexAttribArray(0);
  cinder::gl::enableVertexAttribArray(1);
  cinder::gl::vertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Cloud::PointT), (const GLvoid*)offsetof(Cloud::PointT, data));
  cinder::gl::vertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(Cloud::PointT), (const GLvoid*)offsetof(Cloud::PointT, rgba));
}
Beispiel #2
0
sf::VertexArray Tilemap::buildVertexArray(const sf::IntRect& rect) const
{
	sf::VertexArray vbo(sf::Quads, rect.width * rect.height * 4); // Amount of tiles * vertice per square

	for(int x = rect.left, xl = 0; x < std::min(static_cast<int>(wid), rect.left + rect.width); ++x, ++xl)
	for(int y = rect.top, yl = 0; y < std::min(static_cast<int>(hei), rect.top + rect.height); ++y, ++yl)
	{
		const unsigned int vloc = (xl + (yl * rect.width)) * 4, // VBO location
						   rloc = (x + (y * wid)); // Tileset location
		if (tiles[rloc] != -1) // air
		{
			vbo[vloc].position     = sf::Vector2f(x * tilesize,       y * tilesize);
			vbo[vloc + 1].position = sf::Vector2f((x + 1) * tilesize, y * tilesize);
			vbo[vloc + 2].position = sf::Vector2f((x + 1) * tilesize, (y + 1) * tilesize);
			vbo[vloc + 3].position = sf::Vector2f(x * tilesize,       (y + 1) * tilesize);

			const sf::FloatRect texrect = metatexture.getTexRect(tiles[rloc]);
			vbo[vloc].texCoords     = sf::Vector2f(texrect.left, texrect.top);
			vbo[vloc + 1].texCoords = sf::Vector2f(texrect.left + texrect.width, texrect.top);
			vbo[vloc + 2].texCoords = sf::Vector2f(texrect.left + texrect.width, texrect.top + texrect.height);
			vbo[vloc + 3].texCoords = sf::Vector2f(texrect.left, texrect.top + texrect.height);
		}
	}

	return vbo;
}
Beispiel #3
0
Geometry::Geometry()
:	pose_(Eigen::Matrix4f::Identity()),
	material_(0.5f, 0.0f, 0.5f)
{
	mesh_ = pastry::single_mesh(GL_TRIANGLES);
	pastry::array_buffer vbo(
		{
			{"pos", GL_FLOAT, 3},
			{"uv", GL_FLOAT, 2},
			{"normal", GL_FLOAT, 3}
		},
		GL_STATIC_DRAW
	);
	mesh_.set_vertex_bo(vbo);

	sp_ = pastry::load_program("assets/deferred/render");

	va_ = pastry::vertex_array(sp_, {
		{"position", vbo, "pos"},
		{"texcoord", vbo, "uv"},
		{"normal", vbo, "normal"}
	});
	va_.bind();

}
unique_ptr<RenderableObject> RenderableObject::quad(int startX, 
                                                    int startY, 
                                                    int width, 
                                                    int height, 
                                                    const glm::vec4 &color, GLenum primitive)
{
    glm::vec3 mi(startX, startY, 0.0f);
    glm::vec3 ma(startX + width, startY + height, 0.0f);

    vector<glm::vec3> vertices;
    vector<glm::vec3> normals;
    vector<glm::vec3> texCoords;

    float d = 0.1;

    vertices.push_back(glm::vec3(mi.x, mi.y, d));
    vertices.push_back(glm::vec3(mi.x, ma.y, d));
    vertices.push_back(glm::vec3(ma.x, ma.y, d));
    vertices.push_back(glm::vec3(ma.x, mi.y, d));

    normals.push_back(glm::vec3(0.0f, 1.0f, 0.0f));
    normals.push_back(glm::vec3(0.0f, 1.0f, 0.0f));
    normals.push_back(glm::vec3(0.0f, 1.0f, 0.0f));
    normals.push_back(glm::vec3(0.0f, 1.0f, 0.0f));

    texCoords.push_back(glm::vec3(0.0f, 0.0f, 0.0f));
    texCoords.push_back(glm::vec3(0.0f, 1.0f, 0.0f));
    texCoords.push_back(glm::vec3(1.0f, 1.0f, 0.0f));
    texCoords.push_back(glm::vec3(1.0f, 0.0f, 0.0f));

    // Indices
    vector<GLuint> indices ={
        0, 1, 2,
        0, 2, 3
    };

    uint nrVertices = vertices.size();
    vector<RenderableObject::Vertex> attrData(nrVertices);

    for(uint i=0; i<nrVertices; ++i)
    {    
        glm::vec3 v = vertices[i];
        glm::vec3 n = normals[i];
        glm::vec3 t = texCoords[i];

        attrData[i].Position = v;
        attrData[i].Normal = n;
        attrData[i].Color = color;
        attrData[i].TexCoords = glm::vec4(t.x, t.y, 0.0f, 0.0f);
    }

    unique_ptr<RenderableObject> vbo(new RenderableObject);
    vbo->setData(attrData, indices, primitive);

    return vbo;
}
Beispiel #5
0
 shared_ptr<TexturedMesh> GeometryFactory::createBoundingBox()
 {
     // vertex array
     shared_ptr<BufferedVertexData> vbo(new BufferedVertexData(sizeof(Vec3) * 8,
                                                               sizeof(Vec3), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr));
     
     vbo->setAttribute("in_position", VertexData::AttribProps(0, 3, GL_FLOAT));
     
     Vec3 * vertex_array = (Vec3 *)vbo->mapData();
     
     float half_x = 1 / 2.0;
     float half_y = 1 / 2.0;
     float half_z = 1 / 2.0;
     
     vertex_array[0] = Vec3(-half_x, -half_y,  half_z);
     vertex_array[1] = Vec3( half_x, -half_y,  half_z);
     vertex_array[2] = Vec3( half_x, -half_y, -half_z);
     vertex_array[3] = Vec3(-half_x, -half_y, -half_z);
     
     vertex_array[4] = Vec3(-half_x, half_y, half_z);
     vertex_array[5] = Vec3( half_x, half_y, half_z);
     vertex_array[6] = Vec3( half_x, half_y, -half_z);
     vertex_array[7] = Vec3(-half_x, half_y, -half_z);
     
     vbo->unmapData();
     
     // indices
     shared_ptr<BufferedVertexData> ibo(new BufferedVertexData(sizeof(unsigned short) * 16,
                                                               sizeof(unsigned short), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr));
     
     unsigned short * indices = (unsigned short*)ibo->mapData();
     
     indices[0] = 4;
     indices[1] = 0;
     indices[2] = 1;
     indices[3] = 5;
     indices[4] = 6;
     indices[5] = 2;
     indices[6] = 3;
     indices[7] = 7;
     indices[8] = 4;
     indices[9] = 5;
     indices[10] = 1;
     indices[11] = 2;
     indices[12] = 6;
     indices[13] = 7;
     indices[14] = 3;
     indices[15] = 0;
     
     ibo->unmapData();
     
     return shared_ptr<TexturedMesh>(new TexturedMesh(ibo, vbo, GL_LINE_STRIP, 16));
 }
Beispiel #6
0
 shared_ptr<TexturedMesh> GeometryFactory::createPlane()
 {
     float width = 1;
     float height = 1;
     
     int subdivs = 30;
     float offsetX = 1.0 / subdivs;
     float offsetZ = 1.0 / subdivs;
     
     unsigned size = subdivs * (4 + subdivs * 2) * sizeof(Vec3) * 3;
     
     shared_ptr<BufferedVertexData> vbo(new BufferedVertexData(size, sizeof(Vec3) * 3, GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr));
     
     vbo->setAttribute("in_position", VertexData::AttribProps(0, 3, GL_FLOAT));
     vbo->setAttribute("in_normal",   VertexData::AttribProps(sizeof(Vec3), 3, GL_FLOAT));
     vbo->setAttribute("in_texcoord", VertexData::AttribProps(sizeof(Vec3) * 2, 2, GL_FLOAT));
     
     Vec3 * vbo_array = (Vec3 *)vbo->mapData();
     
     int idx = 0;
     for (int j = 1; j <= subdivs; j++) {
         vbo_array[idx++] = Vec3((offsetX * (j - 1) - 0.5) * width, 0, - 0.5 * height);  // vertex
         vbo_array[idx++] = Vec3(0, 1, 0);                                               // normal
         vbo_array[idx++] = Vec3(offsetX * (j - 1), 0.0, 0);                             // texture coordinate
         
         vbo_array[idx++] = Vec3((offsetX * j - 0.5) * width, 0, - 0.5 * height);
         vbo_array[idx++] = Vec3(0, 1, 0);
         vbo_array[idx++] = Vec3(offsetX * j, 0.0, 0);
         
         for (int i = 1; i <= subdivs; i++) {
             vbo_array[idx++] = Vec3((offsetX * (j - 1) - 0.5) * width, 0, (offsetZ * i - 0.5) * height);
             vbo_array[idx++] = Vec3(0, 1, 0);
             vbo_array[idx++] = Vec3(offsetX * (j - 1), offsetZ * i, 0);
             
             vbo_array[idx++] = Vec3((offsetX * j - 0.5) * width, 0, (offsetZ * i - 0.5) * height);
             vbo_array[idx++] = Vec3(0, 1, 0);
             vbo_array[idx++] = Vec3(offsetX * j, offsetZ * i, 0);
         }
         
         vbo_array[idx++] = Vec3((offsetX * j - 0.5) * width, 0, (offsetZ * subdivs - 0.5) * height);
         vbo_array[idx++] = Vec3(0, 1, 0);
         vbo_array[idx++] = Vec3(offsetX * j - 1.0, offsetX * subdivs, 0);
         
         vbo_array[idx++] = Vec3((offsetX * j - 0.5) * width, 0, - 0.5 * height);
         vbo_array[idx++] = Vec3(0, 1, 0);
         vbo_array[idx++] = Vec3(offsetX * j, 0.0, 0);
     }
     
     vbo->unmapData();
     
     return shared_ptr<TexturedMesh>(new TexturedMesh(nullptr, vbo, GL_TRIANGLE_STRIP, idx/3));
 }
Beispiel #7
0
 shared_ptr<TexturedMesh> GeometryFactory::createBox()
 {
     shared_ptr<BufferedVertexData> vbo(new BufferedVertexData(216 * sizeof(float), sizeof(float) * 6, GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr));
     
     vbo->setAttribute("in_position", VertexData::AttribProps(0, 3, GL_FLOAT));
     vbo->setAttribute("in_normal", VertexData::AttribProps(sizeof(float) * 3, 3, GL_FLOAT));
     
     float * vertex_array = (float *)vbo->mapData();
     memcpy(vertex_array, CubeVertexData, sizeof(float)*216);
     vbo->unmapData();
     
     return shared_ptr<TexturedMesh>(new TexturedMesh(nullptr, vbo, GL_TRIANGLES, 36));
 }
Beispiel #8
0
osg::ref_ptr<osg::Node> MeshManager::getTerrain(int size)
{
    auto iter = mTerrainCache.find(size);
    if(iter != mTerrainCache.end())
    {
        osg::ref_ptr<osg::Node> node;
        if(iter->second.lock(node))
            return node;
    }

    if(!mTerrainProgram)
    {
        mTerrainProgram = new osg::Program();
        mTerrainProgram->addShader(osgDB::readShaderFile(osg::Shader::VERTEX, "shaders/terrain.vert"));
        mTerrainProgram->addShader(osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/terrain.frag"));
    }

    osg::ref_ptr<osg::Vec3Array> vtxs(new osg::Vec3Array(4));
    (*vtxs)[0] = osg::Vec3(  0.0f, 0.0f,    0.0f);
    (*vtxs)[1] = osg::Vec3(  0.0f, 0.0f, -256.0f);
    (*vtxs)[2] = osg::Vec3(256.0f, 0.0f, -256.0f);
    (*vtxs)[3] = osg::Vec3(256.0f, 0.0f,    0.0f);
    osg::ref_ptr<osg::Vec2Array> texcrds(new osg::Vec2Array(4));
    (*texcrds)[0] = osg::Vec2(0.0f, 0.0f);
    (*texcrds)[1] = osg::Vec2(0.0f, 1.0f);
    (*texcrds)[2] = osg::Vec2(1.0f, 1.0f);
    (*texcrds)[3] = osg::Vec2(1.0f, 0.0f);

    osg::ref_ptr<osg::VertexBufferObject> vbo(new osg::VertexBufferObject());
    vtxs->setVertexBufferObject(vbo);
    texcrds->setVertexBufferObject(vbo);

    osg::ref_ptr<osg::Geometry> geometry(new osg::Geometry);
    geometry->setVertexArray(vtxs);
    geometry->setTexCoordArray(0, texcrds, osg::Array::BIND_PER_VERTEX);
    geometry->setUseDisplayList(false);
    geometry->setUseVertexBufferObjects(true);
    geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vtxs->size(), size*size));
    geometry->setInitialBound(osg::BoundingBox(osg::Vec3(0.0f, -0.5f, -256.0f*size), osg::Vec3(256.0f*size, 0.5f, 0.0f)));

    osg::StateSet *ss = geometry->getOrCreateStateSet();
    ss->setAttributeAndModes(mTerrainProgram);
    ss->addUniform(new osg::Uniform("diffuseTex", 0));
    ss->addUniform(new osg::Uniform("tilemapTex", 1));

    osg::ref_ptr<osg::Geode> base(new osg::Geode());
    base->addDrawable(geometry);

    mTerrainCache[size] = osg::ref_ptr<osg::Node>(base);
    return base;
}
void VertexAttributeBindingImplementation_Legacy::finish(const VertexAttributeBinding * binding) const
{
    assert(bindingData(binding) != nullptr);

    vao(binding)->bind();

    void * offset = nullptr;

    if (vbo(binding))
    {
        vbo(binding)->bind(GL_ARRAY_BUFFER);
        const auto offset64 = static_cast<GLuint64>(bindingData(binding)->baseoffset + bindingData(binding)->format.relativeoffset);
        offset = reinterpret_cast<void *>(offset64);
    }
    else
    {
        Buffer::unbind(GL_ARRAY_BUFFER);
    }

    const GLint attribute = attributeIndex(binding);

    switch (bindingData(binding)->format.method)
    {
    case Format::Method::I:
        glVertexAttribIPointer(attribute, bindingData(binding)->format.size, bindingData(binding)->format.type
            , bindingData(binding)->stride, offset);
        break;

    case Format::Method::L:
        glVertexAttribLPointer(attribute, bindingData(binding)->format.size, bindingData(binding)->format.type
            , bindingData(binding)->stride, offset);
        break;

    default:
        glVertexAttribPointer(attribute, bindingData(binding)->format.size, bindingData(binding)->format.type
            , bindingData(binding)->format.normalized, bindingData(binding)->stride, offset);
    }
}
void NetworkAccessTest::testCase1()
{
#ifdef USE_CUDA
    QVERIFY( cudaSuccess == cudaGLSetGLDevice( 0 ) );
#ifndef __APPLE__ // glewInit is not needed on Mac
    QVERIFY( 0==glewInit() );
#endif
    pVbo vbo( new Vbo(1024, GL_ARRAY_BUFFER, GL_STATIC_DRAW));
    MappedVbo<float> mapping(vbo, DataStorageSize(256,1,1));
    DataStorage<float>::ptr copy( new DataStorage<float>(*mapping.data) );
	mappedVboTestCuda( copy );
    QVERIFY2(true, "Failure");
#endif
}
Beispiel #11
0
void RigGeometry::setSourceGeometry(osg::ref_ptr<osg::Geometry> sourceGeometry)
{
    mSourceGeometry = sourceGeometry;

    for (unsigned int i=0; i<2; ++i)
    {
        const osg::Geometry& from = *sourceGeometry;
        mGeometry[i] = new osg::Geometry(from, osg::CopyOp::SHALLOW_COPY);
        osg::Geometry& to = *mGeometry[i];
        to.setSupportsDisplayList(false);
        to.setUseVertexBufferObjects(true);
        to.setCullingActive(false); // make sure to disable culling since that's handled by this class
        to.setComputeBoundingBoxCallback(new CopyBoundingBoxCallback());
        to.setComputeBoundingSphereCallback(new CopyBoundingSphereCallback());

        // vertices and normals are modified every frame, so we need to deep copy them.
        // assign a dedicated VBO to make sure that modifications don't interfere with source geometry's VBO.
        osg::ref_ptr<osg::VertexBufferObject> vbo (new osg::VertexBufferObject);
        vbo->setUsage(GL_DYNAMIC_DRAW_ARB);

        osg::ref_ptr<osg::Array> vertexArray = osg::clone(from.getVertexArray(), osg::CopyOp::DEEP_COPY_ALL);
        if (vertexArray)
        {
            vertexArray->setVertexBufferObject(vbo);
            to.setVertexArray(vertexArray);
        }

        if (const osg::Array* normals = from.getNormalArray())
        {
            osg::ref_ptr<osg::Array> normalArray = osg::clone(normals, osg::CopyOp::DEEP_COPY_ALL);
            if (normalArray)
            {
                normalArray->setVertexBufferObject(vbo);
                to.setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX);
            }
        }

        if (const osg::Vec4Array* tangents = dynamic_cast<const osg::Vec4Array*>(from.getTexCoordArray(7)))
        {
            mSourceTangents = tangents;
            osg::ref_ptr<osg::Array> tangentArray = osg::clone(tangents, osg::CopyOp::DEEP_COPY_ALL);
            tangentArray->setVertexBufferObject(vbo);
            to.setTexCoordArray(7, tangentArray, osg::Array::BIND_PER_VERTEX);
        }
        else
            mSourceTangents = nullptr;
    }
}
unique_ptr<RenderableObject> RenderableObject::sphere(float radius, 
                                                      int iterations, 
                                                      const glm::vec4 &color, 
                                                      GLenum primitive)
{
    vector<FACET3> f((int)pow(4.0, iterations));
    int n = CreateUnitSphere(f, iterations);

    vector<glm::vec3> vertices;
    vector<glm::vec3> normals;

    for(int i=0; i<n; ++i)
    {
        FACET3& facet = f[i];
        vertices.push_back(facet.p1 * radius);
        vertices.push_back(facet.p2 * radius);
        vertices.push_back(facet.p3 * radius);

        facet.p1 = glm::normalize(facet.p1);
        facet.p2 = glm::normalize(facet.p2);
        facet.p3 = glm::normalize(facet.p3);
        normals.push_back(facet.p1);
        normals.push_back(facet.p2);
        normals.push_back(facet.p3);
    }

    uint nrVertices = vertices.size();
    vector<RenderableObject::Vertex> attrData(nrVertices);

    for(uint i=0; i<nrVertices; ++i)
    {    
        glm::vec3 v = vertices[i];
        glm::vec3 n = normals[i];

        attrData[i].Position = v;
        attrData[i].Normal = n;
        attrData[i].Color = color;
    }

    unique_ptr<RenderableObject> vbo(new RenderableObject);
    vbo->setData(attrData, primitive);

    return vbo;
}
unique_ptr<RenderableObject> RenderableObject::quadLines(int startX, 
                                                         int startY, 
                                                         int width, 
                                                         int height, 
                                                         const glm::vec4 &color)
{
    glm::vec3 mi(startX, startY, 0.0f);
    glm::vec3 ma(startX + width, startY + height, 0.0f);

    vector<glm::vec3> vertices;
    vector<glm::vec3> normals;

    float d = 0.1;

    vertices.push_back(glm::vec3(mi.x, mi.y, d));
    vertices.push_back(glm::vec3(mi.x, ma.y, d));

    vertices.push_back(glm::vec3(mi.x, ma.y, d));
    vertices.push_back(glm::vec3(ma.x, ma.y, d));

    vertices.push_back(glm::vec3(ma.x, ma.y, d));
    vertices.push_back(glm::vec3(ma.x, mi.y, d));

    vertices.push_back(glm::vec3(ma.x, mi.y, d));
    vertices.push_back(glm::vec3(mi.x, mi.y, d));

    uint nrVertices = vertices.size();
    vector<RenderableObject::Vertex> attrData(nrVertices);

    for(uint i=0; i<nrVertices; ++i)
    {    
        glm::vec3 v = vertices[i];

        attrData[i].Position = v;
        attrData[i].Color = color;
    }

    unique_ptr<RenderableObject> vbo(new RenderableObject);
    vbo->setData(attrData, GL_LINES);

    return vbo;
}
Beispiel #14
0
int
main()
{
  // Setup SDL wrapper
  sdl::set_error_callback([](const std::string &err) {
    std::cout << err << std::endl;
  });

  sdl::window window(width, height, false, "Test Renderer");
  sdl::ogl_context context(window);
  

  // Setup Simple Renderer
  renderer::set_log_callback([](const uint32_t id, const std::string &err) {
    std::cout << id << " : " << std::endl;
  });

  renderer::initialize();
  renderer::clear_color(0.4f, 0.2f, 0.2f);

  // Load assets and shader
  const auto resource_path = util::get_resource_path() + "assets/";

  const std::vector<std::string> models = {
    "test_scene.obj",
  };

  std::vector<renderer::vertex_buffer> buffers;

  for(const auto &m : models)
  {
    const auto model = util::load_obj(resource_path + m);

    // Load meshes
    for(const auto &mesh : model.meshes)
    {
      const auto gl_model = util::convert_to_open_gl_mesh(mesh);

      renderer::vertex_buffer vbo(gl_model.mesh_data);
      buffers.emplace_back(std::move(vbo));
      assert(buffers.back().is_valid());
    }
  }

  // Shaders
  const std::string fullbright_shader_code_raw          = util::get_contents_from_file(resource_path + "fullbright.shd");
  const std::string fullbright_shader_code_preprocessed = util::hash_include_string(fullbright_shader_code_raw, {resource_path});  
  const auto fullbright_shd_code                        = renderer::shader_utils::get_shader_code_from_tagged_string(fullbright_shader_code_preprocessed);

  renderer::shader fullbright_shader(fullbright_shd_code.vs_code, "", fullbright_shd_code.ps_code);
  assert(fullbright_shader.is_valid());

  const std::string forward_shader_code_raw             = util::get_contents_from_file(resource_path + "forward_lighting.shd");
  const std::string forward_shader_code_preprocessed    = util::hash_include_string(forward_shader_code_raw, {resource_path});
  const auto forward_shd_code                           = renderer::shader_utils::get_shader_code_from_tagged_string(forward_shader_code_preprocessed);

  renderer::shader forward_shader(forward_shd_code.vs_code, "", forward_shd_code.ps_code);
  assert(forward_shader.is_valid());

  const std::string shadow_sahder_code_raw              = util::get_contents_from_file(resource_path + "shadow_map.shd");
  const std::string shadow_sahder_code_preprocessed     = util::hash_include_string(shadow_sahder_code_raw, {resource_path});
  const auto shadow_map_shd_code                        = renderer::shader_utils::get_shader_code_from_tagged_string(shadow_sahder_code_preprocessed);

  renderer::shader shadow_shader(shadow_map_shd_code.vs_code, "", shadow_map_shd_code.ps_code);
  assert(shadow_shader.is_valid());

  const std::vector<renderer::attr_format_desc> vertex_desc = {
    renderer::attr_format_desc{"in_vs_position",  renderer::attr_type::FLOAT3},
    renderer::attr_format_desc{"in_vs_texcoord",  renderer::attr_type::FLOAT2},
    renderer::attr_format_desc{"in_vs_normal",    renderer::attr_type::FLOAT3},
  };

  renderer::vertex_format vert_fmt(vertex_desc);
  assert(vert_fmt.is_valid());

  // Texture
  int32_t width = 0;
  int32_t height = 0;

  const auto file_path = resource_path + "test.png";
  unsigned char *image0 = SOIL_load_image(file_path.c_str(), &width, &height, 0, SOIL_LOAD_RGBA);

  renderer::texture test_texture0(image0, width, height);
  assert(test_texture0.is_valid());

  SOIL_free_image_data(image0);

  Light_utils::create_direction_light(&lights);
  Light_utils::create_random_point_lights_inside_range(&lights, 5, 5);


  // Shadow cube map
  GLuint m_fbo;
  GLuint m_shadowMap;
  GLuint m_depth;

  const uint32_t cube_size = 2048;

  // Create the FBO
  glGenFramebuffers(1, &m_fbo);

  // Create the depth buffer
  glGenTextures(1, &m_depth);
  glBindTexture(GL_TEXTURE_2D, m_depth);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
  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_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glBindTexture(GL_TEXTURE_2D, 0);

  // Create the cube map
  glGenTextures(1, &m_shadowMap);
  glBindTexture(GL_TEXTURE_CUBE_MAP, m_shadowMap);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

  for (uint i = 0 ; i < 6 ; i++) {
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_R32F, cube_size, cube_size, 0, GL_RED, GL_FLOAT, NULL);
  }

  glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depth, 0);


  // Disable writes to the color buffer
  glDrawBuffer(GL_NONE);

  // Disable reads from the color buffer
  glReadBuffer(GL_NONE);

  GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

  if (Status != GL_FRAMEBUFFER_COMPLETE) {
    printf("FB error, status: 0x%x\n", Status);
    return false;
  }

  glBindFramebuffer(GL_FRAMEBUFFER, 0);


  // Game loop
  while(!window.wants_to_quit())
  {
    sdl::message_pump();

      const uint32_t NUM_OF_LAYERS = 6;

      struct Cam_dir
      {
        GLint cube;
        math::vec3 tar;
        math::vec3 up;
      };

      std::array<Cam_dir, NUM_OF_LAYERS> cam_dirs = 
      {
        Cam_dir{ GL_TEXTURE_CUBE_MAP_POSITIVE_X, math::vec3_init(1.0f, 0.0f, 0.0f),  math::vec3_init(0.0f, -1.0f, 0.0f)  },
        Cam_dir{ GL_TEXTURE_CUBE_MAP_NEGATIVE_X, math::vec3_init(-1.0f, 0.0f, 0.0f), math::vec3_init(0.0f, -1.0f, 0.0f)  },
        Cam_dir{ GL_TEXTURE_CUBE_MAP_POSITIVE_Y, math::vec3_init(0.0f, 1.0f, 0.0f),  math::vec3_init(0.0f, 0.0f, -1.0f)  },
        Cam_dir{ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, math::vec3_init(0.0f, -1.0f, 0.0f), math::vec3_init(0.0f, 0.0f, 1.0f)   },
        Cam_dir{ GL_TEXTURE_CUBE_MAP_POSITIVE_Z, math::vec3_init(0.0f, 0.0f, 1.0f),  math::vec3_init(0.0f, -1.0f, 0.0f)  },
        Cam_dir{ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, math::vec3_init(0.0f, 0.0f, -1.0f), math::vec3_init(0.0f, -1.0f, 0.0f)  }
      };

    renderer::clear();
    renderer::reset();
    glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
    //glEnable(GL_TEXTURE_CUBE_MAP);

    // Hack! we just copy them to remove errors from rotation transform
    static float angle = 0.f;
    angle += 0.005f;

    auto copy_lights = lights;
    Light_utils::rotate_points_around_origin(&copy_lights, angle);

    // Shadows
    {

      glCullFace(GL_FRONT);
      glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);


      //glClearColor(1.0, 1.0, 1.0, 1.0);

      for (uint i = 0 ; i < NUM_OF_LAYERS ; i++)
      {
        // Bind FBO?
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, cam_dirs.at(i).cube, m_shadowMap, 0);
        glDrawBuffer(GL_COLOR_ATTACHMENT0);

        const math::mat4 sh_proj   = math::mat4_projection(1, 1, 0.1f, 100.f, math::quart_tau());
        const math::mat4 sh_world  = math::mat4_id();

        const math::vec3 light_pos = math::vec3_init(copy_lights.points[0].position[0], copy_lights.points[0].position[1], copy_lights.points[0].position[2]);
        const math::vec3 dir       = math::vec3_add(light_pos, cam_dirs.at(i).tar);

        const math::mat4 sh_view  = math::mat4_lookat(light_pos, dir, cam_dirs.at(i).up);
        const math::mat4 sh_wvp   = math::mat4_multiply(sh_world, sh_view, sh_proj);

        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

        shadow_shader.set_raw_data("uni_wvp_mat",         math::mat4_get_data(sh_wvp),    sizeof(float) * 16);
        shadow_shader.set_raw_data("uni_world_mat",       math::mat4_get_data(sh_world),  sizeof(float) * 16);
        shadow_shader.set_raw_data("uni_light_world_pos", &copy_lights.points[0].position[0], sizeof(float) * 3);

        for(const auto &buff : buffers)
        {
          shadow_shader.bind();
          buff.bind(vert_fmt, shadow_shader);

          const uint32_t number_of_vertices = buff.get_number_entries() / vert_fmt.get_number_of_entires();

          glDrawArrays(GL_TRIANGLES, 0, number_of_vertices);
        }
      }

      glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    }

    renderer::reset();
    glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);

    // Lighting
    renderer::shader &curr_shader = [&]() -> renderer::shader&
    {
      if(current_render_path == Render_path::forward_lighting)
      {
        const float spec_power     = 10.f;
        const float spec_intensity = 10.f;

        glUseProgram(forward_shader.get_program_gl_id());

        // eek
        glActiveTexture(GL_TEXTURE0 + 1);
        glBindTexture(GL_TEXTURE_CUBE_MAP, m_shadowMap);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

        forward_shader.set_raw_data("specular_intensity",   &spec_power,    sizeof(float));
        forward_shader.set_raw_data("specular_power",       &spec_power,    sizeof(float));
        forward_shader.set_raw_data("eye_position",         &eye_position,  sizeof(float) * 3);
        

        // For Dir lights
        for(uint32_t i = 0; i < std::min<uint32_t>(copy_lights.directionals.size(), 0); ++i)
        {
          forward_shader.set_raw_data("dir_light[" + std::to_string(i) + "].color",      copy_lights.directionals[i].color,        sizeof(float) * 3);
          forward_shader.set_raw_data("dir_light[" + std::to_string(i) + "].direction",  copy_lights.directionals[i].direction,    sizeof(float) * 3);
          forward_shader.set_raw_data("dir_light[" + std::to_string(i) + "].ambient",    &copy_lights.directionals[i].ambient,     sizeof(float));
          forward_shader.set_raw_data("dir_light[" + std::to_string(i) + "].diffuse",    &copy_lights.directionals[i].diffuse,     sizeof(float));        
        }

        // For Point lights
        for(uint32_t i = 0; i < std::min<uint32_t>(copy_lights.points.size(), 1); ++i)
        {
          forward_shader.set_raw_data("point_light[" + std::to_string(i) + "].color",            copy_lights.points[i].color,           sizeof(float) * 3);
          forward_shader.set_raw_data("point_light[" + std::to_string(i) + "].position",         copy_lights.points[i].position,        sizeof(float) * 3);
          forward_shader.set_raw_data("point_light[" + std::to_string(i) + "].ambient",          &copy_lights.points[i].ambient,        sizeof(float));
          forward_shader.set_raw_data("point_light[" + std::to_string(i) + "].diffuse",          &copy_lights.points[i].diffuse,        sizeof(float));
          forward_shader.set_raw_data("point_light[" + std::to_string(i) + "].atten.constant",   &copy_lights.points[i].atten_constant, sizeof(float));
          forward_shader.set_raw_data("point_light[" + std::to_string(i) + "].atten.linear",     &copy_lights.points[i].atten_linear,   sizeof(float));
          forward_shader.set_raw_data("point_light[" + std::to_string(i) + "].atten.expon",      &copy_lights.points[i].atten_expon,    sizeof(float));
        }

        return forward_shader;
      }

      return fullbright_shader;

    }(); // functional burger!

    for(const auto &buff : buffers)
    {
      const math::vec3 light_pos = math::vec3_init(copy_lights.points[0].position[0], copy_lights.points[0].position[1], copy_lights.points[0].position[2]);
      const math::vec3 dir       = math::vec3_add(light_pos, cam_dirs.at(0).tar);
      auto test_view             = math::mat4_lookat(light_pos, dir, cam_dirs.at(0).up);

      curr_shader.set_raw_data("view",    math::mat4_get_data(view),  sizeof(float) * 16);
      curr_shader.set_raw_data("proj",    math::mat4_get_data(proj),  sizeof(float) * 16);
      curr_shader.set_raw_data("model",   math::mat4_get_data(world), sizeof(float) * 16);
      curr_shader.set_texture("diffuse_map", test_texture0);

      renderer::draw(curr_shader, vert_fmt, buff);
    }

    window.flip_buffer();
  }

  return 0;
}
Beispiel #15
0
osg::ref_ptr<osg::Node> TerrainGrid::buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter)
{
    if (chunkSize * mNumSplits > 1.f)
    {
        // keep splitting
        osg::ref_ptr<osg::Group> group (new osg::Group);
        if (parent)
            parent->addChild(group);

        float newChunkSize = chunkSize/2.f;
        buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, newChunkSize/2.f));
        buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, -newChunkSize/2.f));
        buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(-newChunkSize/2.f, newChunkSize/2.f));
        buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(-newChunkSize/2.f, -newChunkSize/2.f));
        return group;
    }
    else
    {
        float minH, maxH;
        if (!mStorage->getMinMaxHeights(chunkSize, chunkCenter, minH, maxH))
            return NULL; // no terrain defined

        osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize();
        osg::ref_ptr<SceneUtil::PositionAttitudeTransform> transform (new SceneUtil::PositionAttitudeTransform);
        transform->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f));

        if (parent)
            parent->addChild(transform);

        osg::ref_ptr<osg::Vec3Array> positions (new osg::Vec3Array);
        osg::ref_ptr<osg::Vec3Array> normals (new osg::Vec3Array);
        osg::ref_ptr<osg::Vec4Array> colors (new osg::Vec4Array);

        osg::ref_ptr<osg::VertexBufferObject> vbo (new osg::VertexBufferObject);
        positions->setVertexBufferObject(vbo);
        normals->setVertexBufferObject(vbo);
        colors->setVertexBufferObject(vbo);

        mStorage->fillVertexBuffers(0, chunkSize, chunkCenter, positions, normals, colors);

        osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
        geometry->setVertexArray(positions);
        geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
        geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
        geometry->setUseDisplayList(false);
        geometry->setUseVertexBufferObjects(true);

        geometry->addPrimitiveSet(mCache.getIndexBuffer(0));

        // we already know the bounding box, so no need to let OSG compute it.
        osg::Vec3f min(-0.5f*mStorage->getCellWorldSize()*chunkSize,
                       -0.5f*mStorage->getCellWorldSize()*chunkSize,
                       minH);
        osg::Vec3f max (0.5f*mStorage->getCellWorldSize()*chunkSize,
                           0.5f*mStorage->getCellWorldSize()*chunkSize,
                           maxH);
        osg::BoundingBox bounds(min, max);
        geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds));

        std::vector<LayerInfo> layerList;
        std::vector<osg::ref_ptr<osg::Image> > blendmaps;
        mStorage->getBlendmaps(chunkSize, chunkCenter, false, blendmaps, layerList);

        // For compiling textures, I don't think the osgFX::Effect does it correctly
        osg::ref_ptr<osg::Node> textureCompileDummy (new osg::Node);
        unsigned int dummyTextureCounter = 0;

        bool useShaders = mResourceSystem->getSceneManager()->getForceShaders();
        if (!mResourceSystem->getSceneManager()->getClampLighting())
            useShaders = true; // always use shaders when lighting is unclamped, this is to avoid lighting seams between a terrain chunk with normal maps and one without normal maps
        std::vector<TextureLayer> layers;
        {
            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mTextureCacheMutex);
            for (std::vector<LayerInfo>::const_iterator it = layerList.begin(); it != layerList.end(); ++it)
            {
                TextureLayer textureLayer;
                textureLayer.mSpecular = it->mSpecular;
                osg::ref_ptr<osg::Texture2D> texture = mTextureCache[it->mDiffuseMap];
                if (!texture)
                {
                    texture = new osg::Texture2D(mResourceSystem->getImageManager()->getImage(it->mDiffuseMap));
                    texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
                    texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
                    mResourceSystem->getSceneManager()->applyFilterSettings(texture);
                    mTextureCache[it->mDiffuseMap] = texture;
                }
                textureLayer.mDiffuseMap = texture;
                textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, texture);

                if (!it->mNormalMap.empty())
                {
                    texture = mTextureCache[it->mNormalMap];
                    if (!texture)
                    {
                        texture = new osg::Texture2D(mResourceSystem->getImageManager()->getImage(it->mNormalMap));
                        texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
                        texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
                        mResourceSystem->getSceneManager()->applyFilterSettings(texture);
                        mTextureCache[it->mNormalMap] = texture;
                    }
                    textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, texture);
                    textureLayer.mNormalMap = texture;
                }

                if (it->requiresShaders())
                    useShaders = true;

                layers.push_back(textureLayer);
            }
        }

        std::vector<osg::ref_ptr<osg::Texture2D> > blendmapTextures;
        for (std::vector<osg::ref_ptr<osg::Image> >::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it)
        {
            osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D);
            texture->setImage(*it);
            texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
            texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
            texture->setResizeNonPowerOfTwoHint(false);
            blendmapTextures.push_back(texture);

            textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, blendmapTextures.back());
        }

        // use texture coordinates for both texture units, the layer texture and blend texture
        for (unsigned int i=0; i<2; ++i)
            geometry->setTexCoordArray(i, mCache.getUVBuffer());

        float blendmapScale = ESM::Land::LAND_TEXTURE_SIZE*chunkSize;
        osg::ref_ptr<osgFX::Effect> effect (new Terrain::Effect(mShaderManager ? useShaders : false, mResourceSystem->getSceneManager()->getForcePerPixelLighting(), mResourceSystem->getSceneManager()->getClampLighting(),
                                                                mShaderManager, layers, blendmapTextures, blendmapScale, blendmapScale));

        effect->addCullCallback(new SceneUtil::LightListCallback);

        transform->addChild(effect);

        osg::Node* toAttach = geometry.get();

        effect->addChild(toAttach);

        if (mIncrementalCompileOperation)
        {
            mIncrementalCompileOperation->add(toAttach);
            mIncrementalCompileOperation->add(textureCompileDummy);
        }

        return transform;
    }
}
Beispiel #16
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();
    }
}
void liveAdvectTexture(){
	Window::init();
	Window window("Realtime Texture Advection");
	//Set an fps cap
	const float FPS = 60.0f;

	//Setup a quad to draw too
	GL::VertexArray vao;
	vao.elementBuffer(quadElems);
	GL::VertexBuffer vbo(quad, GL::USAGE::STATIC_DRAW);	

	//Setup program
	GL::Program prog("../res/shader.v.glsl", "../res/shader.f.glsl");
	
	//Setup the attributes
	vao.setAttribPointer(vbo, prog.getAttribute("position"), 3, GL_FLOAT, GL_FALSE);
	vao.setAttribPointer(vbo, prog.getAttribute("texIn"), 3, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(glm::vec3) * 4));
	
	glm::mat4 view = glm::lookAt<float>(glm::vec3(0, 0, 1), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0));
	glm::mat4 proj = glm::perspective(60.0f, (float)(window.box().w) /  (float)(window.box().h), 0.1f, 100.0f);
	glm::mat4 model = glm::scale(0.55f, 0.55f, 1.0f);
	glm::mat4 mvp = proj * view * model;
	prog.uniformMat4x4("mvp", mvp);

	/*
	* I don't think OpenCL or OpenGL provide a simple method for copying images/textures so 
	* instead we'll flip the in/out image each step and draw the out image by setting active = out
	*/
	//Make textures to work with
	GL::Texture texA("../res/map.png", true, SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB);
	GL::Texture texB("../res/blank.png", true, SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB);
	//Active is the actual texture we will draw
	GL::Texture active = texB;

	//Setup our OpenCL context + program and kernel
	CL::TinyCL tiny(CL::DEVICE::GPU, true);
	cl::Program program = tiny.loadProgram("../res/simpleAdvect.cl");
	cl::Kernel kernel = tiny.loadKernel(program, "simpleAdvect");

	//Setup our OpenCL data
#ifdef CL_VERSION_1_2
	cl::ImageGL imgA = tiny.imageFromTexture(CL::MEM::READ_WRITE, texA);
	cl::ImageGL imgB = tiny.imageFromTexture(CL::MEM::READ_WRITE, texB);
#else
	cl::Image2DGL imgA = tiny.imageFromTexture(CL::MEM::READ_WRITE, texA);
	cl::Image2DGL imgB = tiny.imageFromTexture(CL::MEM::READ_WRITE, texB);
#endif
	const float speed = 0.2f;
	float velocity[2] = { 0.0f, 0.0f };
	cl::Buffer velBuf = tiny.buffer(CL::MEM::READ_ONLY, 2 * sizeof(float), velocity);

	//Setup our GL objects vector
	std::vector<cl::Memory> glObjs;
	glObjs.push_back(imgA);
	glObjs.push_back(imgB);

	//The time step will be constant and velocity won't change each step, so set'em now
	float dt = 1.0f / FPS;
	kernel.setArg(0, sizeof(float), &dt);
	kernel.setArg(1, velBuf);
	
	//Query the preferred work group size
	int workSize = tiny.preferredWorkSize(kernel);
	//fixed for now
	int imgSize = 256;
	cl::NDRange local(workSize, workSize);
	cl::NDRange global(imgSize, imgSize);
	//Track the run number so we know which texture to set as in/out and which to draw
	int run = 0;

	//Our event structure
	SDL_Event e;
	//Limit framerate with a timer
	Timer delta;
	//For tracking if we want to quit
	bool quit = false, paused = false;
	while (!quit){
		delta.Start();
		//Event Polling
		while (SDL_PollEvent(&e)){
			//If user closes he window
			if (e.type == SDL_QUIT)
				quit = true;
			//If user presses any key
			if (e.type == SDL_KEYDOWN){
				switch (e.key.keysym.sym){
					//So we can change velocity
					case SDLK_w:
						velocity[1] = speed;
						tiny.writeData(velBuf, 2 * sizeof(float), velocity);
						break;
					case SDLK_s:
						velocity[1] = -speed;
						tiny.writeData(velBuf, 2 * sizeof(float), velocity);
						break;
					case SDLK_a:
						velocity[0] = -speed;
						tiny.writeData(velBuf, 2 * sizeof(float), velocity);
						break;
					case SDLK_d:
						velocity[0] = speed;
						tiny.writeData(velBuf, 2 * sizeof(float), velocity);
						break;
					case SDLK_r:
						velocity[0] = 0.0f;
						velocity[1] = 0.0f;
						tiny.writeData(velBuf, 2 * sizeof(float), velocity);
						break;
					//Toggle pause
					case SDLK_SPACE:
						paused = !paused;
						break;
					//For quitting, escape key
					case SDLK_ESCAPE:
						quit = true;
						break;
					default:
						break;
				}
			}
		}
		//Run the kernel, setting the in/out textures properly. On even runs the output will be
		//in texB, on odd runs output will be in texA
		if (!paused){
			try {
				//On even runs and the first run texB/imgB is our output, on odd runs it's flipped
				//Is this really the best way to do this? Maybe there is some faster way to copy the image over
				//instead of updating this each time
				if (run % 2 == 0 || run == 0){
					kernel.setArg(2, imgA);
					kernel.setArg(3, imgB);
					active = texB;
				}
				else {
					kernel.setArg(2, imgB);
					kernel.setArg(3, imgA);
					active = texA;
				}
				glFinish();
				tiny.mQueue.enqueueAcquireGLObjects(&glObjs);

				tiny.runKernel(kernel, local, global);
			
				tiny.mQueue.enqueueReleaseGLObjects(&glObjs);
				tiny.mQueue.finish();
				++run;
			}
			catch (const cl::Error &e){
				std::cout << "Error: " << e.what() << " code: " << e.err() << std::endl;
			}
		}
		//RENDERING
		window.clear();

		prog.use();
		glBindVertexArray(vao);
		glActiveTexture(GL_TEXTURE0);
		//Shouldn't we be drawing active here?
		glBindTexture(GL_TEXTURE_2D, texA);
		glDrawElements(GL_TRIANGLES, vao.numElements(), GL_UNSIGNED_SHORT, NULL);

		window.present();

		//Cap fps
		if (delta.Ticks() < 1000 / FPS)
			SDL_Delay(1000 / FPS - delta.Ticks());
	}
	window.close();
	Window::quit();
}
unique_ptr<RenderableObject> RenderableObject::box(const glm::vec3 &mi, 
                                                   const glm::vec3 &ma, 
                                                   const glm::vec4 &color, 
                                                   GLenum primitive)
{
    vector<glm::vec3> vertices;
    vector<glm::vec3> normals;

    // Face 1
    vertices.push_back(glm::vec3(mi.x, ma.y, mi.z));
    vertices.push_back(glm::vec3(mi.x, ma.y, ma.z));
    vertices.push_back(glm::vec3(ma.x, ma.y, ma.z));
    vertices.push_back(glm::vec3(ma.x, ma.y, mi.z));

    normals.push_back(glm::vec3(0.0f, 1.0f, 0.0f));
    normals.push_back(glm::vec3(0.0f, 1.0f, 0.0f));
    normals.push_back(glm::vec3(0.0f, 1.0f, 0.0f));
    normals.push_back(glm::vec3(0.0f, 1.0f, 0.0f));

    // Face 2
    vertices.push_back(glm::vec3(mi.x, mi.y, mi.z));
    vertices.push_back(glm::vec3(ma.x, mi.y, mi.z));
    vertices.push_back(glm::vec3(ma.x, mi.y, ma.z));
    vertices.push_back(glm::vec3(mi.x, mi.y, ma.z));

    normals.push_back(glm::vec3(0.0f, -1.0f, 0.0f));
    normals.push_back(glm::vec3(0.0f, -1.0f, 0.0f));
    normals.push_back(glm::vec3(0.0f, -1.0f, 0.0f));
    normals.push_back(glm::vec3(0.0f, -1.0f, 0.0f));    

    // Face 3
    vertices.push_back(glm::vec3(mi.x, mi.y, mi.z));
    vertices.push_back(glm::vec3(mi.x, ma.y, mi.z));
    vertices.push_back(glm::vec3(ma.x, ma.y, mi.z));
    vertices.push_back(glm::vec3(ma.x, mi.y, mi.z));

    normals.push_back(glm::vec3(0.0f, 0.0f, -1.0f));
    normals.push_back(glm::vec3(0.0f, 0.0f, -1.0f));
    normals.push_back(glm::vec3(0.0f, 0.0f, -1.0f));
    normals.push_back(glm::vec3(0.0f, 0.0f, -1.0f));

    // Face 4
    vertices.push_back(glm::vec3(mi.x, mi.y, ma.z));
    vertices.push_back(glm::vec3(ma.x, mi.y, ma.z));
    vertices.push_back(glm::vec3(ma.x, ma.y, ma.z));
    vertices.push_back(glm::vec3(mi.x, ma.y, ma.z));

    normals.push_back(glm::vec3(0.0f, 0.0f, 1.0f));
    normals.push_back(glm::vec3(0.0f, 0.0f, 1.0f));
    normals.push_back(glm::vec3(0.0f, 0.0f, 1.0f));
    normals.push_back(glm::vec3(0.0f, 0.0f, 1.0f));

    // Face 5
    vertices.push_back(glm::vec3(mi.x, mi.y, mi.z));
    vertices.push_back(glm::vec3(mi.x, mi.y, ma.z));
    vertices.push_back(glm::vec3(mi.x, ma.y, ma.z));
    vertices.push_back(glm::vec3(mi.x, ma.y, mi.z));

    normals.push_back(glm::vec3(-1.0f, 0.0f, 0.0f));
    normals.push_back(glm::vec3(-1.0f, 0.0f, 0.0f));
    normals.push_back(glm::vec3(-1.0f, 0.0f, 0.0f));
    normals.push_back(glm::vec3(-1.0f, 0.0f, 0.0f));

    // Face 6
    vertices.push_back(glm::vec3(ma.x, mi.y, mi.z));
    vertices.push_back(glm::vec3(ma.x, ma.y, mi.z));
    vertices.push_back(glm::vec3(ma.x, ma.y, ma.z));
    vertices.push_back(glm::vec3(ma.x, mi.y, ma.z));

    normals.push_back(glm::vec3(1.0f, 0.0f, 0.0f));
    normals.push_back(glm::vec3(1.0f, 0.0f, 0.0f));
    normals.push_back(glm::vec3(1.0f, 0.0f, 0.0f));
    normals.push_back(glm::vec3(1.0f, 0.0f, 0.0f));

    // Indices
    vector<GLuint> indices ={
        0, 1, 2,
        0, 2, 3,
        4, 5, 6,
        4, 6, 7,
        8, 9, 10,
        8, 10, 11,
        12, 13, 14,
        12, 14, 15
    };

    uint nrVertices = vertices.size();
    vector<RenderableObject::Vertex> attrData(nrVertices);

    for(uint i=0; i<nrVertices; ++i)
    {    
        glm::vec3 v = vertices[i];
        glm::vec3 n = normals[i];

        attrData[i].Position = v;
        attrData[i].Normal = n;
        attrData[i].Color = color;
    }

    unique_ptr<RenderableObject> vbo(new RenderableObject);
    vbo->setData(attrData, indices, primitive);

    return vbo;
}
Beispiel #19
0
int main() {
	if(-1 == SDL_Init(SDL_INIT_VIDEO)) {
		std::cerr << "Unable to initialize SDL" << std::endl;
		return EXIT_FAILURE;
	}

	if(NULL == SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, SDL_OPENGL)) {
		std::cerr << "Unable to open the window and get an OpenGL context" << std::endl;
		return EXIT_FAILURE;
	}

	SDL_WM_SetCaption("OpenGL4Imacs", NULL);

	GLenum glewCode = glewInit();
	if(GLEW_OK != glewCode) {
		std::cerr << "Unable to initialize GLEW : " << glewGetErrorString(glewCode) << std::endl;
		return EXIT_FAILURE;
	}
	
	Button2D jouer(-1,-1,0.5,0.2);
	
	// Initialisation VBO
	glimac::LowLevelVBO vbo(jouer.getVertices(), 8 * sizeof(GLfloat), GL_STATIC_DRAW, GL_ARRAY_BUFFER);

	// Initialisation VAO
	glimac::VAO vao;
	// Binder le vao
	vao.bind();

	glEnableVertexAttribArray(0);
	// Binder le vbo
	vbo.bind();
	
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (const GLvoid*) (0 * sizeof(GLfloat)));

	glBindBuffer(GL_ARRAY_BUFFER, 0);

	// Debinder le vao
	glBindVertexArray(0);

	bool done = false;
	while(!done) {
		Uint32 tStart = SDL_GetTicks();
		
		// Rendering code goes here
		glClear(GL_COLOR_BUFFER_BIT);
		
		vao.bind();
		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
		glBindVertexArray(0);
		// Application code goes here

		SDL_Event e;
		while(SDL_PollEvent(&e)) {
			switch(e.type) {
				default:
					break;
				case SDL_QUIT:
					done = true;
					break;
			}
		}

		// Mise à jour de la fenêtre (synchronisation implicite avec OpenGL)
		SDL_GL_SwapBuffers();

		Uint32 tEnd = SDL_GetTicks();
		Uint32 d = tEnd - tStart;
		if(d < FRAME_DURATION) {
			SDL_Delay(FRAME_DURATION - d);
		}
	}
	// Destruction des ressources
	SDL_Quit();

	return EXIT_SUCCESS;
}
Beispiel #20
0
void SceneManagerTriangle::InitScene(uint16 width, uint16 height)
{
	m_width = width;
	m_height = height;

	float cube[] = {
		-1, -1, 0, 1,
		-1,  1, 0, 1,
		 1,  1, 0, 1,
		 1, -1, 0, 1,

		-1.5, -1.5, -1, 1,
		-1.5,  1.5, -1, 1,
		 1.5,  1.5, -1, 1,
		 1.5, -1.5, -1, 1,
	};

	//uint32 cubeColor[] = {
	//	0xff0000,
	//	0x00ff00,
	//	0x0000ff,
	//	0xff0000,
	//};

	float uv[] = {
		0.0f, 1.0f,
		0.5f, 0.0f,
		0.0f, 0.0f,
		0.0f, 1.0f,
		0.5f, 1.0f,
		0.5f, 0.0f,

		0.5f, 1.0f,
		1.0f, 0.0f,
		0.5f, 0.0f,
		0.5f, 1.0f,
		1.0f, 1.0f,
		1.0f, 0.0f,
	};

	float cubeNormal[] = {
		0.0f, 0.0f, 1.0f,
		0.0f, 0.0f, 1.0f,
		0.0f, 0.0f, 1.0f,
		0.0f, 0.0f, 1.0f,
	};

	uint32 cubeIndex[] = {
		0, 2, 1,
		0, 3, 2,
		//4, 6, 5,
		//4, 7, 6,
	};

	shared_ptr<VertexBufferObject> vbo(new VertexBufferObject());
	vbo->CopyVertexBuffer(cube, sizeof(cube) / sizeof(float));
	//vbo->CopyColorBuffer(cubeColor, sizeof(cubeColor) / sizeof(uint32));
	vbo->CopyUVBuffer(uv, sizeof(uv) / sizeof(float));
	//vbo->CopyNormalBuffer(cubeNormal, sizeof(cubeNormal) / sizeof(float));
	vbo->CopyIndexBuffer(cubeIndex, sizeof(cubeIndex) / sizeof(uint32));

	vbo->m_mode = VertexBufferObject::RENDER_TRIANGLE;
	//vbo->m_mode = VertexBufferObject::RENDER_LINE;
	vbo->m_cullMode = VertexBufferObject::CULL_NONE;
	Soft3dPipeline::Instance()->SetVBO(vbo);

	uint32 tex_data[] = {
		0xa7dbff, 0xefed7a, 0xb8ecff,  0x136888, 0xeb5f25, 0x136999,
		0xefed7a, 0xb8ecff, 0xefed7a,  0xeb5f25, 0x136999, 0xeb5f25,
		0xb8ecff, 0xefed7a, 0xb8ecff,  0x136999, 0xeb5f25, 0x136999,
	};

	shared_ptr<Texture> tex(new Texture());
	tex->CopyFromBuffer(tex_data, 6, 3);
	tex->filter_mode = Texture::NEAREST;
	Soft3dPipeline::Instance()->SetTexture(tex);

	Soft3dPipeline::Instance()->AddKeyboardEventCB(boost::bind(&SceneManagerTriangle::KeyboardEventCB, this, _1));
}
Beispiel #21
0
osg::ref_ptr<osg::Node> MeshManager::loadFlat(size_t texid, bool centered, size_t *num_frames)
{
    auto iter = mFlatCache.find(std::make_pair(texid, centered));
    if(iter != mFlatCache.end())
    {
        osg::ref_ptr<osg::Node> node;
        if(iter->second.lock(node))
        {
            if(num_frames)
            {
                osg::ref_ptr<osg::Texture> tex = TextureManager::get().getTexture(texid);
                *num_frames = tex->getTextureDepth();
            }
            return node;
        }
    }

    if(!mFlatProgram)
    {
        mFlatProgram = new osg::Program();
        mFlatProgram->addShader(osgDB::readShaderFile(osg::Shader::VERTEX, "shaders/sprite.vert"));
        mFlatProgram->addShader(osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/sprite.frag"));
    }

    int16_t xoffset, yoffset;
    float xscale, yscale;
    osg::ref_ptr<osg::Texture> tex = TextureManager::get().getTexture(
        texid, &xoffset, &yoffset, &xscale, &yscale
    );
    if(num_frames)
        *num_frames = tex->getTextureDepth();

    float width = tex->getTextureWidth();
    float height = tex->getTextureHeight();

    osg::Matrix mat(osg::Matrixf::scale(xscale, yscale, xscale));
    //mat.postMultTranslate(osg::Vec3(xoffset, yoffset, 0)); seems to be incorrect values??
    osg::ref_ptr<osg::MatrixTransform> base(new osg::MatrixTransform(mat));

    osg::ref_ptr<osg::Billboard> bb(new osg::Billboard());
    bb->setMode(osg::Billboard::AXIAL_ROT);
    bb->setAxis(osg::Vec3(0.0f, 1.0f, 0.0f));
    bb->setNormal(osg::Vec3(0.0f, 0.0f, -1.0f));

    osg::ref_ptr<osg::Vec3Array> vtxs(new osg::Vec3Array(4));
    (*vtxs)[0] = osg::Vec3(width* 0.5f, height*-0.5f, 0.0f);
    (*vtxs)[1] = osg::Vec3(width*-0.5f, height*-0.5f, 0.0f);
    (*vtxs)[2] = osg::Vec3(width*-0.5f, height* 0.5f, 0.0f);
    (*vtxs)[3] = osg::Vec3(width* 0.5f, height* 0.5f, 0.0f);
    osg::ref_ptr<osg::Vec2Array> texcrds(new osg::Vec2Array(4));
    (*texcrds)[0] = osg::Vec2(1.0f, 0.0f);
    (*texcrds)[1] = osg::Vec2(0.0f, 0.0f);
    (*texcrds)[2] = osg::Vec2(0.0f, 1.0f);
    (*texcrds)[3] = osg::Vec2(1.0f, 1.0f);
    osg::ref_ptr<osg::Vec3Array> nrms(new osg::Vec3Array(4));
    (*nrms)[0] = osg::Vec3(0.0f, 0.0f, -1.0f);
    (*nrms)[1] = osg::Vec3(0.0f, 0.0f, -1.0f);
    (*nrms)[2] = osg::Vec3(0.0f, 0.0f, -1.0f);
    (*nrms)[3] = osg::Vec3(0.0f, 0.0f, -1.0f);
    osg::ref_ptr<osg::Vec4ubArray> colors(new osg::Vec4ubArray(4));
    (*colors)[0] = osg::Vec4ub(255, 255, 255, 255);
    (*colors)[1] = osg::Vec4ub(255, 255, 255, 255);
    (*colors)[2] = osg::Vec4ub(255, 255, 255, 255);
    (*colors)[3] = osg::Vec4ub(255, 255, 255, 255);
    colors->setNormalize(true);

    osg::ref_ptr<osg::VertexBufferObject> vbo(new osg::VertexBufferObject());
    vtxs->setVertexBufferObject(vbo);
    texcrds->setVertexBufferObject(vbo);
    nrms->setVertexBufferObject(vbo);
    colors->setVertexBufferObject(vbo);

    osg::ref_ptr<osg::Geometry> geometry(new osg::Geometry);
    geometry->setVertexArray(vtxs);
    geometry->setTexCoordArray(0, texcrds, osg::Array::BIND_PER_VERTEX);
    geometry->setNormalArray(nrms, osg::Array::BIND_PER_VERTEX);
    geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
    geometry->setUseDisplayList(false);
    geometry->setUseVertexBufferObjects(true);
    geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));

    osg::StateSet *ss = geometry->getOrCreateStateSet();
    ss->setAttributeAndModes(mFlatProgram);
    // Alpha test is reversed, because the shader will set alpha=0 for texels
    // that should be kept, and consequently have no specular, and alpha=1 for
    // texels that should be dropped.
    ss->setAttributeAndModes(new osg::AlphaFunc(osg::AlphaFunc::LESS, 0.5f));
    ss->addUniform(new osg::Uniform("diffuseTex", 0));
    ss->setTextureAttribute(0, tex);

    if(centered)
        bb->addDrawable(geometry);
    else
        bb->addDrawable(geometry, osg::Vec3(0.0f, height*-0.5f, 0.0f));
    base->addChild(bb);

    mFlatCache[std::make_pair(texid, centered)] = osg::ref_ptr<osg::Node>(base);
    return base;
}
Beispiel #22
0
osg::ref_ptr<osg::Node> MeshManager::get(size_t idx)
{
    /* Not sure if this cache is a good idea since it shares the whole model
     * tree. OSG can parent the same sub-tree to multiple points, which should
     * be okay as long as the individual sub-trees don't need changing.
     */
    auto iter = mModelCache.find(idx);
    if(iter != mModelCache.end())
    {
        osg::ref_ptr<osg::Node> node;
        if(iter->second.lock(node))
            return node;
    }

    if(!mModelProgram)
    {
        mModelProgram = new osg::Program();
        mModelProgram->addShader(osgDB::readShaderFile(osg::Shader::VERTEX, "shaders/object.vert"));
        mModelProgram->addShader(osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/object.frag"));
    }

    DFOSG::Mesh *mesh = DFOSG::MeshLoader::get().load(idx);

    osg::ref_ptr<osg::Geode> geode(new osg::Geode());
    for(auto iter = mesh->getPlanes().begin();iter != mesh->getPlanes().end();)
    {
        osg::ref_ptr<osg::Vec3Array> vtxs(new osg::Vec3Array());
        osg::ref_ptr<osg::Vec3Array> nrms(new osg::Vec3Array());
        osg::ref_ptr<osg::Vec3Array> binrms(new osg::Vec3Array());
        osg::ref_ptr<osg::Vec2Array> texcrds(new osg::Vec2Array());
        osg::ref_ptr<osg::Vec4ubArray> colors(new osg::Vec4ubArray());
        osg::ref_ptr<osg::DrawElementsUShort> idxs(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES));
        uint16_t texid = iter->getTextureId();

        osg::ref_ptr<osg::Texture> tex = TextureManager::get().getTexture(texid);
        float width = tex->getTextureWidth();
        float height = tex->getTextureHeight();

        do {
            const std::vector<DFOSG::MdlPlanePoint> &pts = iter->getPoints();
            size_t last_total = vtxs->size();

            vtxs->resize(last_total + pts.size());
            nrms->resize(last_total + pts.size());
            binrms->resize(last_total + pts.size());
            texcrds->resize(last_total + pts.size());
            colors->resize(last_total + pts.size());
            idxs->resize((last_total + pts.size() - 2) * 3);

            size_t j = last_total;
            for(const DFOSG::MdlPlanePoint &pt : pts)
            {
                uint32_t vidx = pt.getIndex();

                (*vtxs)[j].x() = mesh->getPoints()[vidx].x() / 256.0f;
                (*vtxs)[j].y() = mesh->getPoints()[vidx].y() / 256.0f;
                (*vtxs)[j].z() = mesh->getPoints()[vidx].z() / 256.0f;

                (*nrms)[j].x() = iter->getNormal().x() / 256.0f;
                (*nrms)[j].y() = iter->getNormal().y() / 256.0f;
                (*nrms)[j].z() = iter->getNormal().z() / 256.0f;

                (*binrms)[j].x() = iter->getBinormal().x() / 256.0f;
                (*binrms)[j].y() = iter->getBinormal().y() / 256.0f;
                (*binrms)[j].z() = iter->getBinormal().z() / 256.0f;

                (*texcrds)[j].x() = pt.u() / width;
                (*texcrds)[j].y() = pt.v() / height;

                (*colors)[j] = osg::Vec4ub(255, 255, 255, 255);

                if(j >= last_total+2)
                {
                    (*idxs)[(j-2)*3 + 0] = last_total;
                    (*idxs)[(j-2)*3 + 1] = j-1;
                    (*idxs)[(j-2)*3 + 2] = j;
                }

                ++j;
            }
        } while(++iter != mesh->getPlanes().end() && iter->getTextureId() == texid);

        osg::ref_ptr<osg::VertexBufferObject> vbo(new osg::VertexBufferObject());
        vtxs->setVertexBufferObject(vbo);
        nrms->setVertexBufferObject(vbo);
        texcrds->setVertexBufferObject(vbo);
        colors->setVertexBufferObject(vbo);
        colors->setNormalize(true);

        osg::ref_ptr<osg::ElementBufferObject> ebo(new osg::ElementBufferObject());
        idxs->setElementBufferObject(ebo);

        osg::ref_ptr<osg::Geometry> geometry(new osg::Geometry);
        geometry->setVertexArray(vtxs);
        geometry->setNormalArray(nrms, osg::Array::BIND_PER_VERTEX);
        geometry->setTexCoordArray(1, binrms, osg::Array::BIND_PER_VERTEX);
        geometry->setTexCoordArray(0, texcrds, osg::Array::BIND_PER_VERTEX);
        geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
        geometry->setUseDisplayList(false);
        geometry->setUseVertexBufferObjects(true);

        geometry->addPrimitiveSet(idxs);

        /* Cache the stateset used for this texture, so it can be reused for
         * multiple models (should help OSG batch together objects with similar
         * state).
         */
        auto &stateiter = mStateSetCache[texid];
        osg::ref_ptr<osg::StateSet> ss;
        if(stateiter.lock(ss) && ss)
            geometry->setStateSet(ss);
        else
        {
            ss = geometry->getOrCreateStateSet();
            ss->setAttributeAndModes(mModelProgram);
            ss->addUniform(new osg::Uniform("diffuseTex", 0));
            ss->setTextureAttribute(0, tex);
            stateiter = ss;
        }

        geode->addDrawable(geometry);
    }

    mModelCache[idx] = osg::ref_ptr<osg::Node>(geode);
    return geode;
}
void SimpleFluid::testVelocityField(){
	//Setup a quad to draw too
	GL::VertexArray vao;
	vao.elementBuffer(quadElems);
	GL::VertexBuffer vbo(quad, GL::USAGE::STATIC_DRAW);	

	//Setup program
	GL::Program prog("../res/shader.v.glsl", "../res/shader.f.glsl");
	
	//Setup the attributes
	vao.setAttribPointer(vbo, prog.getAttribute("position"), 3, GL_FLOAT, GL_FALSE);
	vao.setAttribPointer(vbo, prog.getAttribute("texIn"), 3, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(glm::vec3) * 4));
	
	glm::mat4 view = glm::lookAt<float>(glm::vec3(0, 0, 1), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0));
	//I suppose later I should pass in the window w/h for setting this properly
	glm::mat4 proj = glm::perspective(60.0f, 
		static_cast<float>(window.box().w) /  static_cast<float>(window.box().h), 0.1f, 100.0f);
	glm::mat4 model = glm::scale(0.35f, 0.35f, 1.0f);
	glm::mat4 mvp = proj * view * model;
	prog.uniformMat4x4("mvp", mvp);

	//Make textures to work with
	GL::Texture fieldA("../res/simplefluid/fluid32.png", true, SOIL_FLAG_INVERT_Y);
	GL::Texture fieldB("../res/simplefluid/fluid32.png", true, SOIL_FLAG_INVERT_Y);
	GL::Texture velocity("../res/simplefluid/right_velocity_32.png", true, SOIL_FLAG_INVERT_Y);
	//Output is the advection output texture, which will flip each run
	GL::Texture output = fieldB;

	//Setup our OpenCL data
#ifdef CL_VERSION_1_2
	cl::ImageGL imgA = tiny.imageFromTexture(CL::MEM::READ_WRITE, fieldA);
	cl::ImageGL imgB = tiny.imageFromTexture(CL::MEM::READ_WRITE, fieldB);
	cl::ImageGL imgVel = tiny.imageFromTexture(CL::MEM::READ_ONLY, velocity);
#else
	cl::Image2DGL imgA = tiny.imageFromTexture(CL::MEM::READ_WRITE, fieldA);
	cl::Image2DGL imgB = tiny.imageFromTexture(CL::MEM::READ_WRITE, fieldB);
	cl::Image2DGL imgVel = tiny.imageFromTexture(CL::MEM::READ_ONLY, velocity);
#endif
	std::vector<cl::Memory> glObjs;
	glObjs.push_back(imgA);
	glObjs.push_back(imgB);
	glObjs.push_back(imgVel);

	cl::Program advectProgram = tiny.loadProgram("../res/simplefluid/advectImageField.cl");
	cl::Kernel advect = tiny.loadKernel(advectProgram, "advectImageField");

	//We'll pick an arbitray time step for now
	advect.setArg(0, 1.f / 30.f);
	advect.setArg(1, imgVel);
	advect.setArg(2, imgA);
	advect.setArg(3, imgB);

	int workSize = tiny.preferredWorkSize(advect);
	cl::NDRange local(workSize, workSize);
	cl::NDRange global(dim, dim);

	//We use the run number to decide which field image should be input and which should be output
	//on even runs A is in, B is out and odd runs we flip
	int run = 0;

	Input::Init();
	while (!Input::Quit()){
		Input::PollEvents();
		if (Input::KeyDown(SDL_SCANCODE_ESCAPE))
			Input::Quit(true);

		//Advect the field
		if (run % 2 == 0 || run == 0){
			advect.setArg(2, imgA);
			advect.setArg(3, imgB);
			output = fieldB;
		}
		else {
			advect.setArg(2, imgB);
			advect.setArg(3, imgA);
			output = fieldA;
		}
		glFinish();
		tiny.mQueue.enqueueAcquireGLObjects(&glObjs);
		tiny.runKernel(advect, local, global);
		tiny.mQueue.enqueueReleaseGLObjects(&glObjs);
		tiny.mQueue.finish();
		++run;

		//RENDERING
		window.clear();

		prog.use();
		glBindVertexArray(vao);
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, output);
		glDrawElements(GL_TRIANGLES, vao.numElements(), GL_UNSIGNED_SHORT, NULL);

		window.present();
	}
}
Beispiel #24
0
osg::ref_ptr<osg::Node> TerrainGrid::buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter)
{
    if (chunkSize * mNumSplits > 1.f)
    {
        // keep splitting
        osg::ref_ptr<osg::Group> group (new osg::Group);
        if (parent)
            parent->addChild(group);

        float newChunkSize = chunkSize/2.f;
        buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, newChunkSize/2.f));
        buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, -newChunkSize/2.f));
        buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(-newChunkSize/2.f, newChunkSize/2.f));
        buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(-newChunkSize/2.f, -newChunkSize/2.f));
        return group;
    }
    else
    {
        float minH, maxH;
        if (!mStorage->getMinMaxHeights(chunkSize, chunkCenter, minH, maxH))
            return NULL; // no terrain defined

        osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize();
        osg::ref_ptr<SceneUtil::PositionAttitudeTransform> transform (new SceneUtil::PositionAttitudeTransform);
        transform->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f));

        if (parent)
            parent->addChild(transform);

        osg::ref_ptr<osg::Vec3Array> positions (new osg::Vec3Array);
        osg::ref_ptr<osg::Vec3Array> normals (new osg::Vec3Array);
        osg::ref_ptr<osg::Vec4Array> colors (new osg::Vec4Array);

        osg::ref_ptr<osg::VertexBufferObject> vbo (new osg::VertexBufferObject);
        positions->setVertexBufferObject(vbo);
        normals->setVertexBufferObject(vbo);
        colors->setVertexBufferObject(vbo);

        mStorage->fillVertexBuffers(0, chunkSize, chunkCenter, positions, normals, colors);

        osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
        geometry->setVertexArray(positions);
        geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
        geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
        geometry->setUseDisplayList(false);
        geometry->setUseVertexBufferObjects(true);

        geometry->addPrimitiveSet(mCache.getIndexBuffer(0));

        // we already know the bounding box, so no need to let OSG compute it.
        osg::Vec3f min(-0.5f*mStorage->getCellWorldSize()*chunkSize,
                       -0.5f*mStorage->getCellWorldSize()*chunkSize,
                       minH);
        osg::Vec3f max (0.5f*mStorage->getCellWorldSize()*chunkSize,
                           0.5f*mStorage->getCellWorldSize()*chunkSize,
                           maxH);
        osg::BoundingBox bounds(min, max);
        geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds));

        std::vector<LayerInfo> layerList;
        std::vector<osg::ref_ptr<osg::Image> > blendmaps;
        mStorage->getBlendmaps(chunkSize, chunkCenter, false, blendmaps, layerList);

        // For compiling textures, I don't think the osgFX::Effect does it correctly
        osg::ref_ptr<osg::Node> textureCompileDummy (new osg::Node);

        std::vector<osg::ref_ptr<osg::Texture2D> > layerTextures;
        for (std::vector<LayerInfo>::const_iterator it = layerList.begin(); it != layerList.end(); ++it)
        {
            layerTextures.push_back(mResourceSystem->getTextureManager()->getTexture2D(it->mDiffuseMap, osg::Texture::REPEAT, osg::Texture::REPEAT));
            textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back());
        }

        std::vector<osg::ref_ptr<osg::Texture2D> > blendmapTextures;
        for (std::vector<osg::ref_ptr<osg::Image> >::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it)
        {
            osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D);
            texture->setImage(*it);
            texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
            texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
            texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
            texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
            texture->setResizeNonPowerOfTwoHint(false);
            blendmapTextures.push_back(texture);

            textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back());
        }

        // use texture coordinates for both texture units, the layer texture and blend texture
        for (unsigned int i=0; i<2; ++i)
            geometry->setTexCoordArray(i, mCache.getUVBuffer());

        float blendmapScale = ESM::Land::LAND_TEXTURE_SIZE*chunkSize;
        osg::ref_ptr<osgFX::Effect> effect (new Terrain::Effect(layerTextures, blendmapTextures, blendmapScale, blendmapScale));

        effect->addCullCallback(new SceneUtil::LightListCallback);

        transform->addChild(effect);

#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
        osg::Node* toAttach = geometry.get();
#else
        osg::ref_ptr<osg::Geode> geode (new osg::Geode);
        geode->addDrawable(geometry);
        osg::Node* toAttach = geode.get();
#endif

        effect->addChild(toAttach);

        if (mIncrementalCompileOperation)
        {
            mIncrementalCompileOperation->add(toAttach);
            mIncrementalCompileOperation->add(textureCompileDummy);
        }

        return transform;
    }
}