void ImageProcessingComputeExample::Initialize(const char * title)
{
    base::Initialize(title);

    // Initialize our compute program
    compute_prog = glCreateProgram();

    static const char compute_shader_source[] =
        "#version 430 core\n"
        "\n"
        "layout (local_size_x = 1024) in;\n"
        "\n"
        "layout (rgba32f, binding = 0) uniform image2D input_image;\n"
        "layout (rgba32f, binding = 1) uniform image2D output_image;\n"
        "\n"
        "shared vec4 scanline[1024];\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n"
        "    scanline[pos.x] = imageLoad(input_image, pos);\n"
        "    barrier();\n"
        "    imageStore(output_image, pos.yx, scanline[min(pos.x + 1, 1023)] - scanline[max(pos.x - 1, 0)]);\n"
        "}\n"
    ;

    vglAttachShaderSource(compute_prog, GL_COMPUTE_SHADER, compute_shader_source);

    glLinkProgram(compute_prog);

    // Load a texture to process
    input_image = vglLoadTexture("D:/svn/Vermilion-Book/trunk/Code/media/curiosity.dds", 0, NULL);

    glGenTextures(1, &intermediate_image);
    glBindTexture(GL_TEXTURE_2D, intermediate_image);
    glTexStorage2D(GL_TEXTURE_2D, 8, GL_RGBA32F, 1024, 1024);

    // This is the texture that the compute program will write into
    glGenTextures(1, &output_image);
    glBindTexture(GL_TEXTURE_2D, output_image);
    glTexStorage2D(GL_TEXTURE_2D, 8, GL_RGBA32F, 1024, 1024);

    // Now create a simple program to visualize the result
    render_prog = glCreateProgram();

    static const char render_vs[] =
        "#version 430 core\n"
        "\n"
        "in vec4 vert;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    gl_Position = vert;\n"
        "}\n";

    static const char render_fs[] =
        "#version 430 core\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "\n"
        "layout (binding = 0) uniform sampler2D output_image;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    color = abs(texture(output_image, vec2(1.0, -1.0) * vec2(gl_FragCoord.xy) / vec2(textureSize(output_image, 0)))) * 1.0;\n"
        "}\n";

    vglAttachShaderSource(render_prog, GL_VERTEX_SHADER, render_vs);
    vglAttachShaderSource(render_prog, GL_FRAGMENT_SHADER, render_fs);

    glLinkProgram(render_prog);

    // This is the VAO containing the data to draw the quad (including its associated VBO)
    glGenVertexArrays(1, &render_vao);
    glBindVertexArray(render_vao);
    glEnableVertexAttribArray(0);
    glGenBuffers(1, &render_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, render_vbo);
    static const float verts[] =
    {
        -1.0f, -1.0f, 0.5f, 1.0f,
         1.0f, -1.0f, 0.5f, 1.0f,
         1.0f,  1.0f, 0.5f, 1.0f,
        -1.0f,  1.0f, 0.5f, 1.0f,
    };
    glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);
}
void LoadTextureExample::Initialize(const char * title)
{
    base::Initialize(title);

    base_prog = glCreateProgram();

    static const char quad_shader_vs[] =
        "#version 330 core\n"
        "\n"
        "layout (location = 0) in vec2 in_position;\n"
        "layout (location = 1) in vec2 in_tex_coord;\n"
        "\n"
        "out vec2 tex_coord;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    gl_Position = vec4(in_position, 0.5, 1.0);\n"
        "    tex_coord = in_tex_coord;\n"
        "}\n"
    ;

    static const char quad_shader_fs[] =
        "#version 330 core\n"
        "\n"
        "in vec2 tex_coord;\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "\n"
        "uniform sampler2D tex;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    color = texture(tex, tex_coord);\n"
        "}\n"
    ;

    vglAttachShaderSource(base_prog, GL_VERTEX_SHADER, quad_shader_vs);
    vglAttachShaderSource(base_prog, GL_FRAGMENT_SHADER, quad_shader_fs);

    glGenBuffers(1, &quad_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, quad_vbo);

    static const GLfloat quad_data[] =
    {
         0.75f, -0.75f,
        -0.75f, -0.75f,
        -0.75f, 0.75f,
         0.75f, 0.75f,

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

    glBufferData(GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW);

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(8 * sizeof(float)));

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glLinkProgram(base_prog);

    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexStorage2D(GL_TEXTURE_2D, 4, GL_RGBA8, 8, 8);

    static const unsigned char texture_data[] =
    {
        0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
        0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
        0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
        0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
        0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
        0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
        0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
        0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF
    };

    glTexSubImage2D(GL_TEXTURE_2D,
                    0,
                    0, 0,
                    8, 8,
                    GL_RED, GL_UNSIGNED_BYTE,
                    texture_data);

    static const GLint swizzles[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzles);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glGenerateMipmap(GL_TEXTURE_2D);
}
void ViewportArrayApplication::Initialize(const char * title)
{
    int i;

    base::Initialize(title);

    glGenTransformFeedbacks(1, &xfb);
    glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, xfb);

    sort_prog = glCreateProgram();

    static const char sort_vs_source[] =
            "#version 410\n"
            "\n"
            "uniform mat4 model_matrix;\n"
            "\n"
            "layout (location = 0) in vec4 position;\n"
            "layout (location = 1) in vec3 normal;\n"
            "\n"
            "out vec3 vs_normal;\n"
            "\n"
            "void main(void)\n"
            "{\n"
            "    vs_normal = (model_matrix * vec4(normal, 0.0)).xyz;\n"
            "    gl_Position = model_matrix * position;\n"
            "}\n";

    static const char sort_gs_source[] =
        "#version 410\n"
        "\n"
        "layout (triangles) in;\n"
        "layout (points, max_vertices = 3) out;\n"
        "\n"
        "uniform mat4 projection_matrix;\n"
        "\n"
        "in vec3 vs_normal[];\n"
        "\n"
        "layout (stream = 0) out vec4 rf_position;\n"
        "layout (stream = 0) out vec3 rf_normal;\n"
        "\n"
        "layout (stream = 1) out vec4 lf_position;\n"
        "layout (stream = 1) out vec3 lf_normal;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    vec4 A = gl_in[0].gl_Position;\n"
        "    vec4 B = gl_in[1].gl_Position;\n"
        "    vec4 C = gl_in[2].gl_Position;\n"
        "    vec3 AB = (B - A).xyz;\n"
        "    vec3 AC = (C - A).xyz;\n"
        "    vec3 face_normal = cross(AB, AC);\n"
        "    int i;\n"
        "\n"
        "    if (face_normal.x < 0.0)\n"
        "    {\n"
        "        for (i = 0; i < gl_in.length(); i++)\n"
        "        {\n"
        "            rf_position = projection_matrix * (gl_in[i].gl_Position - vec4(30.0, 0.0, 0.0, 0.0));\n"
        "            rf_normal = vs_normal[i];\n"
        "            EmitStreamVertex(0);\n"
        "        }\n"
        "        EndStreamPrimitive(0);\n"
        "    }\n"
        "    else\n"
        "    {\n"
        "        for (i = 0; i < gl_in.length(); i++)\n"
        "        {\n"
        "            lf_position = projection_matrix * (gl_in[i].gl_Position + vec4(30.0, 0.0, 0.0, 0.0));\n"
        "            lf_normal = vs_normal[i];\n"
        "            EmitStreamVertex(1);\n"
        "        }\n"
        "        EndStreamPrimitive(1);\n"
        "    }\n"
        "}\n";

    vglAttachShaderSource(sort_prog, GL_VERTEX_SHADER, sort_vs_source);
    vglAttachShaderSource(sort_prog, GL_GEOMETRY_SHADER, sort_gs_source);

    static const char * varyings[] =
    {
        "rf_position", "rf_normal",
        "gl_NextBuffer",
        "lf_position", "lf_normal"
    };

    glTransformFeedbackVaryings(sort_prog, 5, varyings, GL_INTERLEAVED_ATTRIBS);

    glLinkProgram(sort_prog);
    glUseProgram(sort_prog);

    model_matrix_pos = glGetUniformLocation(sort_prog, "model_matrix");
    projection_matrix_pos = glGetUniformLocation(sort_prog, "projection_matrix");

    glGenVertexArrays(2, vao);
    glGenBuffers(2, vbo);

    for (i = 0; i < 2; i++)
    {
        glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, vbo[i]);
        glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1024 * 1024 * sizeof(GLfloat), NULL, GL_DYNAMIC_COPY);
        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, i, vbo[i]);

        glBindVertexArray(vao[i]);
        glBindBuffer(GL_ARRAY_BUFFER, vbo[i]);
        glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vmath::vec4) + sizeof(vmath::vec3), NULL);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vmath::vec4) + sizeof(vmath::vec3), (GLvoid *)(sizeof(vmath::vec4)));
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
    }

    render_prog = glCreateProgram();

    static const char render_vs_source[] =
        "#version 410\n"
        "\n"
        "layout (location = 0) in vec4 position;\n"
        "layout (location = 1) in vec3 normal;\n"
        "\n"
        "out vec3 vs_normal;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    vs_normal = normal;\n"
        "    gl_Position = position;\n"
        "}\n";

    static const char render_fs_source[] =
        "#version 410\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "\n"
        "uniform vec4 pass_color;\n"
        "\n"
        "in vec3 vs_normal;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    color = pass_color * (0.2 + pow(abs(vs_normal.z), 4.0)) + vec4(1.0, 1.0, 1.0, 0.0) * pow(abs(vs_normal.z), 37.0);\n"
        "}\n";

    vglAttachShaderSource(render_prog, GL_VERTEX_SHADER, render_vs_source);
    vglAttachShaderSource(render_prog, GL_FRAGMENT_SHADER, render_fs_source);

    glLinkProgram(render_prog);

    object.LoadFromVBM("D:/svn/Vermilion-Book/trunk/Code/media/ninja.vbm", 0, 1, 2);
}
void MultiTextureExample::Initialize(const char * title)
{
    base::Initialize(title);

    base_prog = glCreateProgram();

    static const char quad_shader_vs[] =
        "#version 330 core\n"
        "\n"
        "layout (location = 0) in vec2 in_position;\n"
        "layout (location = 1) in vec2 in_tex_coord;\n"
        "\n"
        "out vec2 tex_coord0;\n"
        "out vec2 tex_coord1;\n"
        "\n"
        "uniform float time;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    mat2 m = mat2( vec2(cos(time), sin(time)),\n"
        "                   vec2(-sin(time), cos(time)) );\n"
        "    gl_Position = vec4(in_position, 0.5, 1.0);\n"
        "    tex_coord0 = in_tex_coord * m;\n"
        "    tex_coord1 = in_tex_coord * transpose(m);\n"
        "}\n"
    ;

    static const char quad_shader_fs[] =
        "#version 330 core\n"
        "\n"
        "in vec2 tex_coord0;\n"
        "in vec2 tex_coord1;\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "\n"
        "uniform sampler2D tex1;\n"
        "uniform sampler2D tex2;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    color = texture(tex1, tex_coord0) + texture(tex2, tex_coord1);\n"
        "}\n"
    ;

    vglAttachShaderSource(base_prog, GL_VERTEX_SHADER, quad_shader_vs);
    vglAttachShaderSource(base_prog, GL_FRAGMENT_SHADER, quad_shader_fs);

    glGenBuffers(1, &quad_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, quad_vbo);

    static const GLfloat quad_data[] =
    {
         1.0f, -1.0f,
        -1.0f, -1.0f,
        -1.0f, 1.0f,
         1.0f, 1.0f,

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

    glBufferData(GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW);

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(8 * sizeof(float)));

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glLinkProgram(base_prog);

    char buf[1024];
    glGetProgramInfoLog(base_prog, 1024, NULL, buf);

    glUseProgram(base_prog);

    time_loc = glGetUniformLocation(base_prog, "time");
    glUniform1i(glGetUniformLocation(base_prog, "tex1"), 0);
    glUniform1i(glGetUniformLocation(base_prog, "tex2"), 1);

    vglImageData image;

    tex1 = vglLoadTexture("media/test.dds", 0, &image);

    glBindTexture(image.target, tex1);
    glTexParameteri(image.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

    vglUnloadImage(&image);

    tex2 = vglLoadTexture("media/test3.dds", 0, &image);

    vglUnloadImage(&image);
}
void LoadTextureExample::Initialize(const char * title)
{
    base::Initialize(title);

    base_prog = glCreateProgram();

    static const char quad_shader_vs[] =
        "#version 330 core\n"
        "\n"
        "layout (location = 0) in vec2 in_position;\n"
        "layout (location = 1) in vec2 in_tex_coord;\n"
        "\n"
        "out vec2 tex_coord;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    gl_Position = vec4(in_position, 0.5, 1.0);\n"
        "    tex_coord = in_tex_coord;\n"
        "}\n"
    ;

    static const char quad_shader_fs[] =
        "#version 330 core\n"
        "\n"
        "in vec2 tex_coord;\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "\n"
        "uniform sampler2D tex;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    color = texture(tex, tex_coord);\n"
        "}\n"
    ;

    vglAttachShaderSource(base_prog, GL_VERTEX_SHADER, quad_shader_vs);
    vglAttachShaderSource(base_prog, GL_FRAGMENT_SHADER, quad_shader_fs);

    glGenBuffers(1, &quad_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, quad_vbo);

    static const GLfloat quad_data[] =
    {
         1.0f, -1.0f,
        -1.0f, -1.0f,
        -1.0f, 1.0f,
         1.0f, 1.0f,

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

    glBufferData(GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW);

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(8 * sizeof(float)));

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glLinkProgram(base_prog);

    char buf[1024];
    glGetProgramInfoLog(base_prog, 1024, NULL, buf);

    vglImageData image;

    tex = vglLoadTexture("d:/svn/Vermilion-Book/trunk/Code/media/test.dds", 0, &image);

    glTexParameteri(image.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

    vglUnloadImage(&image);
}
void CubeMapExample::Initialize(const char * title)
{
    base::Initialize(title);

    skybox_prog = glCreateProgram();

    static const char skybox_shader_vs[] =
        "#version 330 core\n"
        "\n"
        "layout (location = 0) in vec3 in_position;\n"
        "\n"
        "out vec3 tex_coord;\n"
        "\n"
        "uniform mat4 tc_rotate;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    gl_Position = tc_rotate * vec4(in_position, 1.0);\n"
        "    tex_coord = in_position;\n"
        "}\n"
    ;

    static const char skybox_shader_fs[] =
        "#version 330 core\n"
        "\n"
        "in vec3 tex_coord;\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "\n"
        "uniform samplerCube tex;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    color = texture(tex, tex_coord);\n"
        "}\n"
    ;

    vglAttachShaderSource(skybox_prog, GL_VERTEX_SHADER, skybox_shader_vs);
    vglAttachShaderSource(skybox_prog, GL_FRAGMENT_SHADER, skybox_shader_fs);

    glLinkProgram(skybox_prog);

    static const char object_shader_vs[] =
        "#version 330 core\n"
        "\n"
        "layout (location = 0) in vec4 in_position;\n"
        "layout (location = 1) in vec3 in_normal;\n"
        "\n"
        "out vec3 vs_fs_normal;\n"
        "out vec3 vs_fs_position;\n"
        "\n"
        "uniform mat4 mat_mvp;\n"
        "uniform mat4 mat_mv;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    gl_Position = mat_mvp * in_position;\n"
        "    vs_fs_normal = mat3(mat_mv) * in_normal;\n"
        "    vs_fs_position = (mat_mv * in_position).xyz;\n"
        "}\n"
    ;

    static const char object_shader_fs[] =
        "#version 330 core\n"
        "\n"
        "in vec3 vs_fs_normal;\n"
        "in vec3 vs_fs_position;\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "\n"
        "uniform samplerCube tex;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    vec3 tc =  reflect(vs_fs_position, normalize(vs_fs_normal));\n"
        "    color = vec4(0.3, 0.2, 0.1, 1.0) + vec4(0.97, 0.83, 0.79, 0.0) * texture(tex, tc);\n"
        "}\n"
    ;

    object_prog = glCreateProgram();

    vglAttachShaderSource(object_prog, GL_VERTEX_SHADER, object_shader_vs);
    vglAttachShaderSource(object_prog, GL_FRAGMENT_SHADER, object_shader_fs);

    glLinkProgram(object_prog);

    glGenBuffers(1, &cube_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, cube_vbo);

    static const GLfloat cube_vertices[] =
    {
        -1.0f, -1.0f, -1.0f,
        -1.0f, -1.0f,  1.0f,
        -1.0f,  1.0f, -1.0f,
        -1.0f,  1.0f,  1.0f,
         1.0f, -1.0f, -1.0f,
         1.0f, -1.0f,  1.0f,
         1.0f,  1.0f, -1.0f,
         1.0f,  1.0f,  1.0f
    };

    static const GLushort cube_indices[] =
    {
        0, 1, 2, 3, 6, 7, 4, 5,         // First strip
        2, 6, 0, 4, 1, 5, 3, 7          // Second strip
    };

    glBufferData(GL_ARRAY_BUFFER, sizeof(cube_vertices), cube_vertices, GL_STATIC_DRAW);

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(0);

    glGenBuffers(1, &cube_element_buffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube_element_buffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cube_indices), cube_indices, GL_STATIC_DRAW);

    skybox_rotate_loc = glGetUniformLocation(skybox_prog, "tc_rotate");
    object_mat_mvp_loc = glGetUniformLocation(object_prog, "mat_mvp");
    object_mat_mv_loc = glGetUniformLocation(object_prog, "mat_mv");

    vglImageData image;

    tex = vglLoadTexture("../../media/TantolundenCube.dds", 0, &image);

    GLenum e;

    e = glGetError();

    vglUnloadImage(&image);

    object.LoadFromVBM("../../media/unit_torus.vbm", 0, 1, 2);
}
void SimpleComputeShaderExample::Initialize(const char * title)
{
    base::Initialize(title);

    // Initialize our compute program
    compute_prog = glCreateProgram();

    static const char compute_shader_source[] =
        "#version 430 core\n"
        "\n"
        "layout (local_size_x = 32, local_size_y = 16) in;\n"
        "\n"
        "layout (rgba32f) uniform image2D output_image;\n"
        "void main(void)\n"
        "{\n"
        "    imageStore(output_image,\n"
        "    ivec2(gl_GlobalInvocationID.xy),\n"
        "    vec4(vec2(gl_LocalInvocationID.xy) / vec2(gl_WorkGroupSize.xy), 0.0, 0.0));\n"
        "}\n"
    ;

    vglAttachShaderSource(compute_prog, GL_COMPUTE_SHADER, compute_shader_source);

    glLinkProgram(compute_prog);

    // This is the texture that the compute program will write into
    glGenTextures(1, &output_image);
    glBindTexture(GL_TEXTURE_2D, output_image);
    glTexStorage2D(GL_TEXTURE_2D, 8, GL_RGBA32F, 256, 256);

    // Now create a simple program to visualize the result
    render_prog = glCreateProgram();

    static const char render_vs[] =
        "#version 430 core\n"
        "\n"
        "in vec4 vert;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    gl_Position = vert;\n"
        "}\n";

    static const char render_fs[] =
        "#version 430 core\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "\n"
        "uniform sampler2D output_image;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    color = texture(output_image, vec2(gl_FragCoord.xy) / vec2(textureSize(output_image, 0)));\n"
        "}\n";

    vglAttachShaderSource(render_prog, GL_VERTEX_SHADER, render_vs);
    vglAttachShaderSource(render_prog, GL_FRAGMENT_SHADER, render_fs);

    glLinkProgram(render_prog);

    // This is the VAO containing the data to draw the quad (including its associated VBO)
    glGenVertexArrays(1, &render_vao);
    glBindVertexArray(render_vao);
    glEnableVertexAttribArray(0);
    glGenBuffers(1, &render_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, render_vbo);
    static const float verts[] =
    {
        -1.0f, -1.0f, 0.5f, 1.0f,
         1.0f, -1.0f, 0.5f, 1.0f,
         1.0f,  1.0f, 0.5f, 1.0f,
        -1.0f,  1.0f, 0.5f, 1.0f,
    };
    glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);
}
void FurApplication::Initialize(const char * title)
{
    base::Initialize(title);

    base_prog = glCreateProgram();

    static const char base_vs_source[] =
        "#version 410\n"
        "\n"
        "layout (location = 0) in vec4 position_in;\n"
        "layout (location = 1) in vec3 normal_in;\n"
        "layout (location = 2) in vec2 texcoord_in;\n"
        "\n"
        "uniform mat4 model_matrix;\n"
        "uniform mat4 projection_matrix;\n"
        "\n"
        "out VS_FS_VERTEX\n"
        "{\n"
        "    vec3 normal;\n"
        "} vertex_out;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    vertex_out.normal = normal_in;\n"
        "    gl_Position = projection_matrix * (model_matrix * position_in);\n"
        "}\n";

    static const char base_fs_source[] =
        "#version 410\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "\n"
        "in VS_FS_VERTEX\n"
        "{\n"
        "    vec3 normal;\n"
        "} vertex_in;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    vec3 normal = vertex_in.normal;\n"
        "    color = vec4(0.2, 0.1, 0.5, 1.0) * (0.2 + pow(abs(normal.z), 4.0)) + vec4(0.8, 0.8, 0.8, 0.0) * pow(abs(normal.z), 137.0);\n"
        "}\n";

    vglAttachShaderSource(base_prog, GL_VERTEX_SHADER, base_vs_source);
    vglAttachShaderSource(base_prog, GL_FRAGMENT_SHADER, base_fs_source);

    glLinkProgram(base_prog);
    glUseProgram(base_prog);

    base_model_matrix_pos = glGetUniformLocation(base_prog, "model_matrix");
    base_projection_matrix_pos = glGetUniformLocation(base_prog, "projection_matrix");

    fur_prog = glCreateProgram();

    static const char fur_vs_source[] =
        "#version 410\n"
        "\n"
        "layout (location = 0) in vec4 position_in;\n"
        "layout (location = 1) in vec3 normal_in;\n"
        "layout (location = 2) in vec2 texcoord_in;\n"
        "\n"
        "out VS_GS_VERTEX\n"
        "{\n"
        "    vec3 normal;\n"
        "    vec2 tex_coord;\n"
        "} vertex_out;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    vertex_out.normal = normal_in;\n"
        "    vertex_out.tex_coord = texcoord_in;\n"
        "    gl_Position = position_in;\n"
        "}\n";

    static const char fur_gs_source[] =
        "#version 410\n"
        "\n"
        "layout (triangles) in;\n"
        "layout (triangle_strip, max_vertices = 240) out;\n"
        "\n"
        "uniform mat4 model_matrix;\n"
        "uniform mat4 projection_matrix;\n"
        "\n"
        "uniform int fur_layers = 30;\n"
        "uniform float fur_depth = 5.0;\n"
        "\n"
        "in VS_GS_VERTEX\n"
        "{\n"
        "    vec3 normal;\n"
        "    vec2 tex_coord;\n"
        "} vertex_in[];\n"
        "\n"
        "out GS_FS_VERTEX\n"
        "{\n"
        "    vec3 normal;\n"
        "    vec2 tex_coord;\n"
        "    flat float fur_strength;\n"
        "} vertex_out;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    int i, layer;\n"
        "    float disp_delta = 1.0 / float(fur_layers);\n"
        "    float d = 0.0;\n"
        "    vec4 position;\n"
        "\n"
        "    for (layer = 0; layer < fur_layers; layer++)\n"
        "    {\n"
        "        for (i = 0; i < gl_in.length(); i++) {\n"
        "            vec3 n = vertex_in[i].normal;\n"
        "            vertex_out.normal = n;\n"
        "            vertex_out.tex_coord = vertex_in[i].tex_coord;\n"
        "            vertex_out.fur_strength = 1.0 - d;\n"
        "            position = gl_in[i].gl_Position + vec4(n * d * fur_depth, 0.0);\n"
        "            gl_Position = projection_matrix * (model_matrix * position);\n"
        "            EmitVertex();\n"
        "        }\n"
        "        d += disp_delta;\n"
        "        EndPrimitive();\n"
        "    }\n"
        "}\n";

    static const char fur_fs_source[] =
        "#version 410\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "\n"
        "uniform sampler2D fur_texture;\n"
        "uniform vec4 fur_color = vec4(0.8, 0.8, 0.9, 1.0);\n"
        "\n"
        "in GS_FS_VERTEX\n"
        "{\n"
        "    vec3 normal;\n"
        "    vec2 tex_coord;\n"
        "    flat float fur_strength;\n"
        "} fragment_in;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    vec4 rgba = texture(fur_texture, fragment_in.tex_coord);\n"
        "    float t = rgba.a;\n"
        "    t *= fragment_in.fur_strength;\n"
        "    color = fur_color * vec4(1.0, 1.0, 1.0, t);\n"
        "}\n";

    vglAttachShaderSource(fur_prog, GL_VERTEX_SHADER, fur_vs_source);
    vglAttachShaderSource(fur_prog, GL_GEOMETRY_SHADER, fur_gs_source);
    vglAttachShaderSource(fur_prog, GL_FRAGMENT_SHADER, fur_fs_source);

    glLinkProgram(fur_prog);
    glUseProgram(fur_prog);

    fur_model_matrix_pos = glGetUniformLocation(fur_prog, "model_matrix");
    fur_projection_matrix_pos = glGetUniformLocation(fur_prog, "projection_matrix");

    glGenTextures(1, &fur_texture);
    unsigned char * tex = (unsigned char *)malloc(1024 * 1024 * 4);
    memset(tex, 0, 1024 * 1024 * 4);

    int n, m;

    for (n = 0; n < 256; n++)
    {
        for (m = 0; m < 1270; m++)
        {
            int x = rand() & 0x3FF;
            int y = rand() & 0x3FF;
            tex[(y * 1024 + x) * 4 + 0] = (rand() & 0x3F) + 0xC0;
            tex[(y * 1024 + x) * 4 + 1] = (rand() & 0x3F) + 0xC0;
            tex[(y * 1024 + x) * 4 + 2] = (rand() & 0x3F) + 0xC0;
            tex[(y * 1024 + x) * 4 + 3] = n;
        }
    }

    glBindTexture(GL_TEXTURE_2D, fur_texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    free(tex);

    object.LoadFromVBM("C:/Vermilion-Book/trunk/Code/media/ninja.vbm", 0, 1, 2);
}
void LightingExample::Initialize(const char * title)
{
    base::Initialize(title);

    // Now create a simple program to visualize the result
    render_prog = glCreateProgram();

    static const char render_vs[] =
        "#version 430 core\n"
        "\n"
        "uniform mat4 model_matrix;\n"
        "uniform mat4 proj_matrix;\n"
        "\n"
        "layout (location = 0) in vec4 position;\n"
        "layout (location = 1) in vec3 normal;\n"
        "\n"
        "out vec3 vs_worldpos;\n"
        "out vec3 vs_normal;\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    vec4 position = proj_matrix * model_matrix * position;\n"
        "    gl_Position = position;\n"
        "    vs_worldpos = position.xyz;\n"
        "    vs_normal = mat3(model_matrix) * normal;\n"
        "}\n"
        ;

    static const char render_fs[] =
        "#version 430 core\n"
        "\n"
        "layout (location = 0) out vec4 color;\n"
        "\n"
        "in vec3 vs_worldpos;\n"
        "in vec3 vs_normal;\n"
        "\n"
        "uniform vec4 color_ambient = vec4(0.1, 0.2, 0.5, 1.0);\n"
        "uniform vec4 color_diffuse = vec4(0.2, 0.3, 0.6, 1.0);\n"
        "uniform vec4 color_specular = vec4(0.0); // vec4(1.0, 1.0, 1.0, 1.0);\n"
        "uniform float shininess = 77.0f;\n"
        "\n"
        "uniform vec3 light_position = vec3(12.0f, 32.0f, 560.0f);\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    vec3 light_direction = normalize(light_position - vs_worldpos);\n"
        "    vec3 normal = normalize(vs_normal);\n"
        "    vec3 half_vector = normalize(light_direction + normalize(vs_worldpos));\n"
        "    float diffuse = max(0.0, dot(normal, light_direction));\n"
        "    float specular = pow(max(0.0, dot(vs_normal, half_vector)), shininess);\n"
        "    color = color_ambient + diffuse * color_diffuse + specular * color_specular;\n"
        "}\n";

    vglAttachShaderSource(render_prog, GL_VERTEX_SHADER, render_vs);
    vglAttachShaderSource(render_prog, GL_FRAGMENT_SHADER, render_fs);

    glLinkProgram(render_prog);

    mv_mat_loc = glGetUniformLocation(render_prog, "model_matrix");
    prj_mat_loc = glGetUniformLocation(render_prog, "proj_matrix");
    col_amb_loc = glGetUniformLocation(render_prog, "color_ambient");
    col_diff_loc = glGetUniformLocation(render_prog, "color_diffuse");
    col_spec_loc = glGetUniformLocation(render_prog, "color_specular");

    object.LoadFromVBM("D:\\svn\\Vermilion-Book2\\trunk\\Code\\media\\unit_torus.vbm", 0, 1, 2);
}