Copyright 2008-2014 Matus Chochlik. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <map>
#include <cmath>
namespace oglplus {
class PickingExample : public Example
{
private:
shapes::Cube make_cube;
shapes::DrawingInstructions cube_instr;
Context gl;
typedef std::pair<const GLfloat, GLint> DepthAndID;
public:
PickingExample(void)
: cube_instr(make_cube.Instructions())
, cube_indices(make_cube.Indices())
{
vs.Source(
"#version 330\n"
"uniform mat4 ProjectionMatrix, CameraMatrix;"
"in vec4 Position;"
"out vec3 vertColor;"
"flat out int vertInstanceID;"
"void main(void)"
"{"
" float x = gl_InstanceID % 6 - 2.5;"
" float y = gl_InstanceID / 6 - 2.5;"
" mat4 ModelMatrix = mat4("
" 1.0, 0.0, 0.0, 0.0,"
" 0.0, 1.0, 0.0, 0.0,"
" 0.0, 0.0, 1.0, 0.0,"
" 2*x, 2*y, 0.0, 1.0 "
" );"
" gl_Position = "
" ProjectionMatrix *"
" CameraMatrix *"
" ModelMatrix *"
" Position;"
" vertColor = vec3("
" abs(normalize((ModelMatrix*Position).xy)),"
" 0.1"
" );"
" vertInstanceID = gl_InstanceID;"
"}"
);
vs.Compile();
gs.Source(
"#version 330\n"
"layout(triangles) in;"
"layout(points, max_vertices = 1) out;"
"flat in int vertInstanceID[];"
"uniform vec2 MousePos;"
"out int geomInstanceID;"
"out float geomDepth;"
"vec2 barycentric_coords(vec4 a, vec4 b, vec4 c)"
"{"
" vec2 ad = vec2(a.x/a.w, a.y/a.w);"
" vec2 bd = vec2(b.x/b.w, b.y/b.w);"
" vec2 cd = vec2(c.x/c.w, c.y/c.w);"
" vec2 u = cd - ad;"
" vec2 v = bd - ad;"
" vec2 r = MousePos - ad;"
" float d00 = dot(u, u);"
" float d01 = dot(u, v);"
" float d02 = dot(u, r);"
" float d11 = dot(v, v);"
" float d12 = dot(v, r);"
" float id = 1.0 / (d00 * d11 - d01 * d01);"
" float ut = (d11 * d02 - d01 * d12) * id;"
" float vt = (d00 * d12 - d01 * d02) * id;"
" return vec2(ut, vt);"
"}"
"vec3 intersection(vec3 a, vec3 b, vec3 c, vec2 bc)"
"{"
" return (c - a)*bc.x + (b - a)*bc.y;"
"}"
"bool inside_triangle(vec2 b)"
"{"
" return ("
" (b.x >= 0.0) &&"
" (b.y >= 0.0) &&"
" (b.x + b.y <= 1.0)"
" );"
"}"
"void main(void)"
"{"
" vec2 bc = barycentric_coords("
" gl_in[0].gl_Position,"
" gl_in[1].gl_Position,"
" gl_in[2].gl_Position "
" );"
" if(inside_triangle(bc))"
" {"
" gl_Position = vec4(intersection("
" gl_in[0].gl_Position.xyz,"
" gl_in[1].gl_Position.xyz,"
" gl_in[2].gl_Position.xyz,"
" bc"
" ), 1.0);"
" geomDepth = gl_Position.z;"
" geomInstanceID = vertInstanceID[0];"
" EmitVertex();"
" EndPrimitive();"
" }"
"}"
);
gs.Compile();
fs.Source(
"#version 330\n"
"flat in int vertInstanceID;"
"in vec3 vertColor;"
"uniform int Picked;"
"out vec4 fragColor;"
"void main(void)"
"{"
" if(vertInstanceID == Picked)"
" fragColor = vec4(1.0, 1.0, 1.0, 1.0);"
" else fragColor = vec4(vertColor, 1.0);"
"}"
);
fs.Compile();
pick_prog.AttachShader(vs);
pick_prog.AttachShader(gs);
const GLchar* var_names[2] = {"geomDepth", "geomInstanceID"};
pick_prog.TransformFeedbackVaryings(
2, var_names,
);
pick_prog.Link();
draw_prog.AttachShader(vs);
draw_prog.AttachShader(fs);
draw_prog.Link();
cube.Bind();
picked_instances.BindBase(
0
);
{
std::vector<DepthAndID> data(36, DepthAndID(0.0, 0));
Buffer::Resize(
BufferSize::Of<DepthAndID>(36)
);
}
verts.Bind(Buffer::Target::Array);
{
std::vector<GLfloat> data;
GLuint n_per_vertex = make_cube.Positions(data);
Buffer::Data(Buffer::Target::Array, data);
VertexArrayAttrib draw_attr(draw_prog, "Position");
draw_attr.Setup<GLfloat>(n_per_vertex);
draw_attr.Enable();
}
gl.ClearColor(0.9f, 0.9f, 0.9f, 0.0f);
gl.ClearDepth(1.0f);
gl.FrontFace(make_cube.FaceWinding());
}
void Reshape(GLuint width, GLuint height)
{
gl.Viewport(width, height);
Degrees(60),
double(width)/height,
1, 80
);
draw_prog.Use();
Uniform<Mat4f>(draw_prog,
"ProjectionMatrix").
Set(perspective);
pick_prog.Use();
Uniform<Mat4f>(pick_prog,
"ProjectionMatrix").
Set(perspective);
}
void MouseMoveNormalized(float x, float y, float )
{
pick_prog.Use();
Uniform<Vec2f>(pick_prog,
"MousePos").
Set(x, y);
}
{
gl.Clear().ColorBuffer().DepthBuffer();
16.0,
);
pick_prog.Use();
Uniform<Mat4f>(pick_prog,
"CameraMatrix").
Set(camera);
GLuint picked_count = 0;
{
QueryExecution<GLuint> query_exec(
count_query,
Query::Target::
picked_count
);
TransformFeedback::Activator xfb_act(
);
cube_instr.Draw(cube_indices, 36);
xfb_act.Finish();
query_exec.WaitForResult();
}
std::map<GLfloat, GLint> picked_objs;
{
BufferTypedMap<DepthAndID> picked_instances_map(
);
picked_objs.insert(
picked_instances_map.Data(),
picked_instances_map.Data()+picked_count
);
}
draw_prog.Use();
Uniform<GLint> picked(draw_prog, "Picked");
if(picked_objs.empty()) picked = -1;
else picked = picked_objs.begin()->second;
Uniform<Mat4f>(draw_prog,
"CameraMatrix").
Set(camera);
cube_instr.Draw(cube_indices, 36);
}
{
return time < 30.0;
}
};
void setupExample(ExampleParams& ){ }
std::unique_ptr<ExampleThread> makeExampleThread(
Example& ,
unsigned ,
const ExampleParams&
){ return std::unique_ptr<ExampleThread>(); }
std::unique_ptr<Example> makeExample(const ExampleParams& )
{
return std::unique_ptr<Example>(new PickingExample);
}
}