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 <cmath>
namespace oglplus {
class SphereExample : public Example
{
private:
shapes::Sphere make_sphere;
shapes::DrawingInstructions sphere_instr;
GLuint hole_count;
float hole_diameter;
Context gl;
Buffer hole_verts, transf_hole_verts;
static void make_hole_data(std::vector<GLfloat>& data, GLuint hole_count)
{
const GLuint ne = 5;
const float el[ne] = {0.50f, 0.33f, 0.21f, 0.11f, 0.07f};
const GLuint ea[ne] = {1, 6, 6, 6, 6};
const float ao[ne] = {0.00f, 0.00f, 0.50f,-0.08f, 0.42f};
const float si[2] = {1.0f, -1.0f};
GLuint k = 0;
if(ne != 0)
{
GLuint hn = 0;
for(GLuint e=0; e!=ne; ++e)
hn += ea[e];
assert(hn * 2 == hole_count);
data.resize(hn * 2 * 3);
}
for(GLuint s=0; s!= 2; ++s)
for(GLuint e=0; e!=ne; ++e)
{
GLuint na = ea[e];
if(na == 1)
{
data[k++] = 0.0f;
data[k++] = si[s];
data[k++] = 0.0f;
}
else if(na > 1)
{
float elev = el[e] * math::Pi();
float a_step = 1.0f / na;
for(GLuint a=0; a!=na; ++a)
{
float azim = si[s]*ao[e]+a*a_step*math::TwoPi();
data[k++] = std::cos(elev)*std::cos(azim);
data[k++] = std::sin(elev * si[s]);
data[k++] = std::cos(elev)*std::sin(azim);
}
}
}
OGLPLUS_FAKE_USE(hole_count);
assert(k == hole_count * 3);
assert(k == data.size());
}
public:
SphereExample(void)
: sphere_instr(make_sphere.Instructions())
, sphere_indices(make_sphere.Indices())
, hole_count(50)
, hole_diameter(0.30f)
{
vs_tfb.Source(
"#version 330\n"
"uniform mat4 CameraMatrix, ModelMatrix;"
"uniform float Diameter;"
"in vec3 Hole;"
"out vec3 vertTransfHole;"
"void main(void)"
"{"
" vertTransfHole = ("
" CameraMatrix *"
" ModelMatrix *"
" vec4(Hole * (1.0 + 0.5 * Diameter), 0.0)"
" ).xyz;"
"}"
);
vs_tfb.Compile();
prog_tfb.AttachShader(vs_tfb);
const GLchar* var_name = "vertTransfHole";
prog_tfb.TransformFeedbackVaryings(
1, &var_name,
);
prog_tfb.Link();
prog_tfb.Use();
Uniform<GLfloat> diameter(prog_tfb, "Diameter");
diameter.Set(hole_diameter);
holes.Bind();
hole_verts.Bind(Buffer::Target::Array);
{
std::vector<GLfloat> data;
make_hole_data(data, hole_count);
Buffer::Data(Buffer::Target::Array, data);
VertexArrayAttrib attr(prog_tfb, "Hole");
attr.Enable();
}
transf_hole_verts.BindBase(
0
);
vs.Source(
"#version 330\n"
"uniform mat4 ProjectionMatrix, CameraMatrix, ModelMatrix;"
"in vec4 Position;"
"in vec3 Normal;"
"out vec3 vertNormal;"
"out vec3 vertLight;"
"const vec3 LightPos = vec3(2.0, 3.0, 3.0);"
"void main(void)"
"{"
" gl_Position = ModelMatrix * Position;"
" vertNormal = mat3(ModelMatrix)*Normal;"
" vertLight = LightPos-gl_Position.xyz;"
" gl_Position = ProjectionMatrix * CameraMatrix * gl_Position;"
"}"
);
vs.Compile();
fs.Source(
"#version 330\n"
"in vec3 vertNormal;"
"in vec3 vertLight;"
"out vec4 fragColor;"
"const int HoleCount = 50;"
"uniform vec3 TransfHole[50];"
"uniform float Diameter;"
"void main(void)"
"{"
" int imax = 0;"
" float dmax = -1.0;"
" for(int i=0; i!=HoleCount; ++i)"
" {"
" float d = dot(vertNormal, TransfHole[i]);"
" if(dmax < d)"
" {"
" dmax = d;"
" imax = i;"
" }"
" }"
" float l = length(vertLight);"
" vec3 FragDiff = TransfHole[imax] - vertNormal;"
" vec3 FinalNormal = "
" length(FragDiff) > Diameter?"
" vertNormal:"
" normalize(FragDiff+vertNormal*Diameter);"
" float i = (l > 0.0) ? dot("
" FinalNormal, "
" normalize(vertLight)"
" ) / l : 0.0;"
" i = 0.2+max(i*2.5, 0.0);"
" fragColor = vec4(i, i, i, 1.0);"
"}"
);
fs.Compile();
prog.AttachShader(vs);
prog.AttachShader(fs);
prog.Link();
prog.Use();
diameter.Set(hole_diameter);
sphere.Bind();
verts.Bind(Buffer::Target::Array);
{
std::vector<GLfloat> data;
GLuint n_per_vertex = make_sphere.Positions(data);
Buffer::Data(Buffer::Target::Array, data);
VertexArrayAttrib attr(prog, "Position");
attr.Setup<GLfloat>(n_per_vertex);
attr.Enable();
}
normals.Bind(Buffer::Target::Array);
{
std::vector<GLfloat> data;
GLuint n_per_vertex = make_sphere.Normals(data);
Buffer::Data(Buffer::Target::Array, data);
VertexArrayAttrib attr(prog, "Normal");
attr.Setup<GLfloat>(n_per_vertex);
attr.Enable();
}
gl.ClearColor(0.8f, 0.8f, 0.7f, 0.0f);
gl.ClearDepth(1.0f);
}
void Reshape(GLuint width, GLuint height)
{
gl.Viewport(width, height);
prog.Use();
Uniform<Mat4f>(prog,
"ProjectionMatrix").
Set(
Degrees(75),
double(width)/height,
1, 20
)
);
}
{
gl.Clear().ColorBuffer().DepthBuffer();
4.5f,
Degrees(time * 50),
);
auto model =
0.0f,
0.0f
) *
prog_tfb.Use();
Uniform<Mat4f>(prog_tfb,
"CameraMatrix").
Set(camera);
Uniform<Mat4f>(prog_tfb,
"ModelMatrix").
Set(model);
holes.Bind();
{
TransformFeedback::Activator activates_tfb(
);
}
prog.Use();
Uniform<Mat4f>(prog,
"CameraMatrix").
Set(camera);
Uniform<Mat4f>(prog,
"ModelMatrix").
Set(model);
BufferTypedMap<GLfloat> transf_hole_verts_map(
);
Uniform<Vec3f>(prog, "TransfHole").SetValues(
transf_hole_verts_map.Count()*3,
transf_hole_verts_map.Data()
);
sphere.Bind();
sphere_instr.Draw(sphere_indices);
}
{
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 SphereExample);
}
}