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 <sstream>
namespace oglplus {
class TorusExample : public Example
{
private:
shapes::TwistedTorus make_torus;
shapes::DrawingInstructions torus_instr;
std::vector<shapes::Plane> make_plane;
shapes::DrawingInstructions plane_instr;
static std::vector<shapes::Plane> make_plane_builders(void)
{
std::vector<shapes::Plane> result;
result.push_back(shapes::Plane(
Vec3f( 0.0f, 2.0f, 0.0f),
));
result.push_back(shapes::Plane(
Vec3f( 2.0f, 0.0f, 0.0f),
Vec3f( 0.0f, 0.0f, -2.0f)
));
result.push_back(shapes::Plane(
Vec3f( 2.0f, 0.0f, 0.0f),
));
return result;
}
Context gl;
std::vector<ProgramUniform<GLfloat>> torus_clip_signs;
std::vector<ProgramUniform<GLfloat>> plane_clip_signs;
Lazy<ProgramUniform<Vec3f>> plane_normal;
Lazy<ProgramUniform<Mat4f>>
plane_camera_matrix,
torus_camera_matrix,
torus_model_matrix;
Array<VertexArray> plane;
Buffer torus_positions, torus_texcoords;
Array<Buffer> plane_positions;
public:
TorusExample(void)
: make_torus()
, torus_instr(make_torus.Instructions())
, torus_indices(make_torus.Indices())
, make_plane(make_plane_builders())
, plane_instr(make_plane[0].Instructions())
, plane_indices(make_plane[0].Indices())
, torus_prog(ObjectDesc("Torus"))
, plane_prog(ObjectDesc("Plane"))
, plane_normal(plane_prog, "Normal")
, plane_camera_matrix(plane_prog, "CameraMatrix")
, torus_camera_matrix(torus_prog, "CameraMatrix")
, torus_model_matrix(torus_prog, "ModelMatrix")
, plane(make_plane.size())
, plane_positions(make_plane.size())
{
std::stringstream config;
config << "#define PlaneCount " << plane.size() << '\n';
torus_vs.Source(
"#version 330\n"
"#extension GL_ARB_shading_language_include : enable\n"
"#include <config.glsl>\n"
"uniform mat4 ProjectionMatrix, ModelMatrix, CameraMatrix;"
"uniform float ClipSign[PlaneCount];"
"uniform vec4 ClipPlane[PlaneCount];"
"in vec4 Position;"
"in vec2 TexCoord;"
"out vec2 vertTexCoord;"
"void main(void)"
"{"
" vertTexCoord = TexCoord;"
" gl_Position = "
" ModelMatrix *"
" Position;"
" for(int p=0; p!=PlaneCount; ++p)"
" {"
" gl_ClipDistance[p] = "
" ClipSign[p]* "
" dot(ClipPlane[p], gl_Position);"
" }"
" gl_Position = "
" ProjectionMatrix *"
" CameraMatrix *"
" gl_Position;"
"}"
);
torus_fs.Source(
"#version 330\n"
"in vec2 vertTexCoord;"
"out vec4 fragColor;"
"void main(void)"
"{"
" float i = ("
" int(vertTexCoord.x*36) % 2+"
" int(vertTexCoord.y*24) % 2"
" ) % 2;"
" fragColor = vec4(1-i/2, 1-i/2, 1-i/2, 1.0);"
"}"
);
torus_prog.AttachShader(torus_vs);
torus_prog.AttachShader(torus_fs);
torus_prog.BuildInclude("/");
torus_prog.Use();
torus.Bind();
torus_positions.Bind(Buffer::Target::Array);
{
std::vector<GLfloat> data;
GLuint n_per_vertex = make_torus.Positions(data);
Buffer::Data(Buffer::Target::Array, data);
VertexArrayAttrib attr(torus_prog, "Position");
attr.Setup<GLfloat>(n_per_vertex);
attr.Enable();
}
torus_texcoords.Bind(Buffer::Target::Array);
{
std::vector<GLfloat> data;
GLuint n_per_vertex = make_torus.TexCoordinates(data);
Buffer::Data(Buffer::Target::Array, data);
VertexArrayAttrib attr(torus_prog, "TexCoord");
attr.Setup<GLfloat>(n_per_vertex);
attr.Enable();
}
plane_vs.Source(
"#version 330\n"
"#extension GL_ARB_shading_language_include : enable\n"
"#include <config.glsl>\n"
"uniform mat4 ProjectionMatrix, CameraMatrix;"
"uniform float ClipSign[PlaneCount];"
"uniform vec4 ClipPlane[PlaneCount];"
"uniform vec3 Normal;"
"in vec4 Position;"
"out vec3 vertColor;"
"void main(void)"
"{"
" gl_Position = Position;"
" for(int p=0; p!=PlaneCount; ++p)"
" {"
" gl_ClipDistance[p] = "
" ClipSign[p]* "
" dot(ClipPlane[p], gl_Position);"
" }"
" gl_Position = "
" ProjectionMatrix *"
" CameraMatrix *"
" gl_Position;"
" vertColor = normalize("
" abs(Normal) + "
" 0.4*Position.xyz"
" );"
"}"
).CompileInclude("/");
plane_fs.Source(
"#version 330\n"
"in vec3 vertColor;"
"out vec4 fragColor;"
"void main(void)"
"{"
" fragColor = vec4(vertColor, 0.7);"
"}"
).Compile();
plane_prog.AttachShader(plane_vs);
plane_prog.AttachShader(plane_fs);
plane_prog.Link();
plane_prog.Use();
ProgramUniform<Vec4f> torus_clip_plane(torus_prog, "ClipPlane");
ProgramUniform<Vec4f> plane_clip_plane(plane_prog, "ClipPlane");
ProgramUniform<GLfloat> torus_clip_sign(torus_prog, "ClipSign");
ProgramUniform<GLfloat> plane_clip_sign(plane_prog, "ClipSign");
for(std::size_t p=0; p!=plane.size(); ++p)
{
plane[p].Bind();
plane_positions[p].Bind(Buffer::Target::Array);
{
std::vector<GLfloat> data;
GLuint n = make_plane[p].Positions(data);
Buffer::Data(Buffer::Target::Array, data);
VertexArrayAttrib attr(plane_prog, "Position");
attr.Setup<GLfloat>(n);
attr.Enable();
}
{
auto eq = make_plane[p].Equation();
torus_clip_plane[p].Set(eq);
plane_clip_plane[p].Set(eq);
}
{
torus_clip_signs.push_back(torus_clip_sign[p]);
plane_clip_signs.push_back(plane_clip_sign[p]);
}
}
gl.ClearColor(0.8f, 0.8f, 0.7f, 0.0f);
gl.ClearDepth(1.0f);
gl.FrontFace(make_torus.FaceWinding());
}
void Reshape(GLuint width, GLuint height)
{
gl.Viewport(width, height);
Degrees(60),
double(width)/height,
1, 30
);
ProgramUniform<Mat4f>(torus_prog,
"ProjectionMatrix").
Set(proj);
ProgramUniform<Mat4f>(plane_prog,
"ProjectionMatrix").
Set(proj);
}
void RenderTorus(void)
{
torus_prog.Use();
torus.Bind();
torus_instr.Draw(torus_indices);
}
void RenderPlane(std::size_t p)
{
plane_prog.Use();
plane_normal.Set(make_plane[p].Normal());
plane[p].Bind();
plane_instr.Draw(plane_indices);
}
void BSP(
const Mat4f& camera, std::size_t p)
{
assert(p < std::size_t(plane.size()));
Vec4f normal(make_plane[p].Normal(), 0.0);
GLfloat sign = ((camera*normal).z() >= 0.0f)? 1.0f: -1.0f;
bool at_leaf = p+1 == plane.size();
torus_clip_signs[p].Set(-sign);
plane_clip_signs[p].Set(-sign);
if(at_leaf) RenderTorus();
else BSP(camera, p+1);
RenderPlane(p);
torus_clip_signs[p].Set(+sign);
plane_clip_signs[p].Set(+sign);
if(at_leaf) RenderTorus();
else BSP(camera, p+1);
}
{
gl.Clear().ColorBuffer().DepthBuffer();
6.0,
Degrees(45.0 +
SineWave(time / 7.0)*30.0)
);
plane_camera_matrix.Set(camera);
torus_camera_matrix.Set(camera);
torus_model_matrix.Set(model);
BSP(camera, 0);
}
{
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 TorusExample);
}
}