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 {
template <class ShapeMaker>
class Shape
{
private:
ShapeMaker make_shape;
shapes::DrawingInstructions shape_instr;
typename ShapeMaker::IndexArray shape_indices;
{
prog.AttachShader(vs).AttachShader(fs).Link().Use();
return std::move(prog);
}
Uniform<Mat4f> projection_matrix, camera_matrix, model_matrix;
Uniform<Vec3f> light_pos;
Buffer verts, normals, texcoords;
public:
: shape_instr(make_shape.Instructions())
, shape_indices(make_shape.Indices())
, prog(make(vs, fs))
, projection_matrix(prog, "ProjectionMatrix")
, camera_matrix(prog, "CameraMatrix")
, model_matrix(prog, "ModelMatrix")
, light_pos(prog, "LightPos")
{
shape.Bind();
const GLuint n_attr = 3;
typedef GLuint (ShapeMaker::*Func)(std::vector<GLfloat>&) const;
Func func[n_attr] = {
&ShapeMaker::Positions,
&ShapeMaker::Normals,
&ShapeMaker::TexCoordinates
};
Reference<Buffer> vbo[n_attr] = {verts, normals, texcoords};
const GLchar* ident[n_attr] = {"Position", "Normal", "TexCoord"};
for(GLuint i=0; i!=n_attr; ++i)
{
vbo[i].Bind(Buffer::Target::Array);
std::vector<GLfloat> data;
GLuint n_per_vertex = (make_shape.*func[i])(data);
Buffer::Data(Buffer::Target::Array, data);
VertexArrayAttrib attr(prog, ident[i]);
attr.Setup<GLfloat>(n_per_vertex);
attr.Enable();
}
}
void SetProjection(
const Mat4f& projection)
{
prog.Use();
projection_matrix.Set(projection);
}
void Render(
)
{
prog.Use();
light_pos.Set(light);
camera_matrix.Set(camera);
model_matrix.Set(model);
shape.Bind();
shape_instr.Draw(shape_indices);
}
};
class ShapeExample : public Example
{
private:
Context gl;
{
shader.Source(
"#version 330\n"
"uniform mat4 ProjectionMatrix, CameraMatrix, ModelMatrix;"
"in vec4 Position;"
"in vec3 Normal;"
"in vec2 TexCoord;"
"out vec2 vertTexCoord;"
"out vec3 vertNormal;"
"out vec3 vertLight;"
"uniform vec3 LightPos;"
"void main(void)"
"{"
" vertTexCoord = TexCoord;"
" gl_Position = ModelMatrix * Position;"
" vertNormal = mat3(ModelMatrix)*Normal;"
" vertLight = LightPos - gl_Position.xyz;"
" gl_Position = ProjectionMatrix * CameraMatrix * gl_Position;"
"}"
);
shader.Compile();
return shader;
}
static const GLchar* fs_prologue(void)
{
return
"#version 330\n"
"in vec2 vertTexCoord;"
"in vec3 vertNormal;"
"in vec3 vertLight;"
"out vec4 fragColor;"
"void main(void)"
"{"
" float Len = dot(vertLight, vertLight);"
" float Dot = Len > 0.0 ? dot("
" vertNormal, "
" normalize(vertLight)"
" ) / Len : 0.0;"
" float Intensity = 0.2 + max(Dot, 0.0) * 4.0;";
}
static const GLchar* fs_epilogue(void)
{
return
" fragColor = vec4(Color * Intensity, 1.0);"
"}";
}
static const GLchar* fs_bw_checker(void)
{
return
" float c = ("
" 1 +"
" int(vertTexCoord.x*8) % 2+"
" int(vertTexCoord.y*8) % 2"
" ) % 2;"
" vec3 Color = vec3(c, c, c);";
}
static const GLchar* fs_yb_strips(void)
{
return
" float m = int((vertTexCoord.x+vertTexCoord.y)*16) % 2;"
" vec3 Color = mix("
" vec3(0.0, 0.0, 0.0),"
" vec3(1.0, 1.0, 0.0),"
" m"
" );";
}
static const GLchar* fs_wo_vstrips(void)
{
return
" float m = int(vertTexCoord.x*8) % 2;"
" vec3 Color = mix("
" vec3(1.0, 0.6, 0.1),"
" vec3(1.0, 0.9, 0.8),"
" m"
" );";
}
static const GLchar* fs_br_circles(void)
{
return
" vec2 center = vertTexCoord - vec2(0.5, 0.5);"
" float m = int(sqrt(length(center))*16) % 2;"
" vec3 Color = mix("
" vec3(1.0, 0.0, 0.0),"
" vec3(0.0, 0.0, 1.0),"
" m"
" );";
}
static const GLchar* fs_wg_spirals(void)
{
return
" vec2 center = (vertTexCoord - vec2(0.5, 0.5)) * 16.0;"
" float l = length(center);"
" float t = atan(center.y, center.x)/(2.0*asin(1.0));"
" float m = int(l+t) % 2;"
" vec3 Color = mix("
" vec3(0.0, 1.0, 0.0),"
" vec3(1.0, 1.0, 1.0),"
" m"
" );";
}
static Shader make_fs(
const char* color_fs,
const char* desc)
{
const GLchar* src[3] = {fs_prologue(), color_fs, fs_epilogue()};
shader.Source(src);
shader.Compile();
return shader;
}
Shape<shapes::Sphere> sphere;
Shape<shapes::Cube> cubeX, cubeY, cubeZ;
Shape<shapes::Torus> torus;
public:
ShapeExample(void)
: vs(make_vs())
, sphere(vs,make_fs(fs_yb_strips(), "Y/B strips"))
, cubeX(vs, make_fs(fs_bw_checker(), "B/W checker"))
, cubeY(vs, make_fs(fs_br_circles(), "B/R circles"))
, cubeZ(vs, make_fs(fs_wg_spirals(), "W/G spirals"))
, torus(vs, make_fs(fs_wo_vstrips(), "W/O vstrips"))
{
gl.ClearColor(0.5f, 0.5f, 0.5f, 0.0f);
gl.ClearDepth(1.0f);
}
void Reshape(GLuint width, GLuint height)
{
gl.Viewport(width, height);
Degrees(60),
double(width)/height,
1, 50
);
sphere.SetProjection(projection);
cubeX.SetProjection(projection);
cubeY.SetProjection(projection);
cubeZ.SetProjection(projection);
torus.SetProjection(projection);
}
{
gl.Clear().ColorBuffer().DepthBuffer();
auto light =
Vec3f(2.0f, 2.0f, 2.0f);
6.0,
Degrees(time * 15),
);
sphere.Render(light, camera,
Mat4f());
cubeX.Render(
light,
camera,
);
cubeY.Render(
light,
camera,
);
cubeZ.Render(
light,
camera,
);
torus.Render(
light,
camera,
Degrees(time * 45)
) *
);
}
{
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 ShapeExample);
}
}