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 <oglplus/dsa/ext/texture.hpp>
#include <oglplus/dsa/ext/framebuffer.hpp>
#include <list>
namespace oglplus {
class ShadowProg
{
public:
{
vs.Source(
"#version 330\n"
"#define side 128\n"
"uniform mat4 ProjectionMatrix, CameraMatrix;"
"uniform float Fade;"
"uniform sampler2D Offsets;"
"uniform sampler2D Heights;"
"in vec4 Position;"
"void main(void)"
"{"
" ivec2 Coord = ivec2(gl_InstanceID%side, gl_InstanceID/side);"
" vec2 Offs = texelFetch(Offsets, Coord, 0).xy;"
" float Height = 1.0-texelFetch(Heights, Coord, 0).r;"
" gl_Position = Position;"
" gl_Position.xz += Offs;"
" gl_Position.y *= max(Height*Fade*side/2, 0.5);"
" gl_Position = ProjectionMatrix * CameraMatrix * gl_Position;"
"}"
).Compile();
fs.Source(
"#version 330\n"
"void main(void) { }"
).Compile();
result.AttachShader(vs).AttachShader(fs);
result.Link().Validate().Use();
return std::move(result);
}
Program&
self(void) {
return *
this; }
public:
ProgramUniform<Mat4f> projection_matrix, camera_matrix;
ProgramUniform<GLfloat> fade;
ShadowProg(void)
, projection_matrix(self(), "ProjectionMatrix")
, camera_matrix(self(), "CameraMatrix")
, fade(self(), "Fade")
{ }
};
class DisplayProg
{
public:
{
vs.Source(
"#version 330\n"
"#define side 128\n"
"uniform mat4 ProjectionMatrix, CameraMatrix, LightProjMatrix, LightMatrix;"
"uniform vec3 CameraPos, LightPos;"
"uniform float Fade;"
"uniform sampler2D Offsets;"
"uniform sampler2D Heights;"
"in vec4 Position;"
"in vec3 Normal;"
"out vec4 vertShadowCoord;"
"out vec3 vertViewDir;"
"out vec3 vertLightDir;"
"out vec3 vertNormal;"
"out float vertLight;"
"void main(void)"
"{"
" ivec2 Coord = ivec2(gl_InstanceID%side, gl_InstanceID/side);"
" vec2 Offs = texelFetch(Offsets, Coord, 0).xy;"
" float Depth = texelFetch(Heights, Coord, 0).r;"
" float Height = 1.0-Depth;"
" gl_Position = Position;"
" gl_Position.xz += Offs;"
" float l = (1.0-dot(Normal, vec3(0,1,0))*0.5)*0.8;"
" vertLight = (1.0-gl_Position.y*l)*sign(Height)*Fade;"
" gl_Position.y *= max(Height*Fade*side/2, 0.5);"
" vertViewDir = CameraPos - gl_Position.xyz;"
" vertLightDir = LightPos - gl_Position.xyz;"
" vertShadowCoord = LightProjMatrix * LightMatrix * gl_Position;"
" gl_Position = ProjectionMatrix * CameraMatrix * gl_Position;"
" vertNormal = Normal;"
"}"
).Compile();
fs.Source(
"#version 330\n"
"uniform sampler2DShadow Shadows;"
"const vec3 LightDir = normalize(vec3(1, 0.3, 1));"
"const vec3 BarColor = vec3(0.4, 0.4, 0.4);"
"in vec4 vertShadowCoord;"
"in vec3 vertViewDir;"
"in vec3 vertLightDir;"
"in vec3 vertNormal;"
"in float vertLight;"
"out vec3 fragColor;"
"void main(void)"
"{"
" vec3 Normal = normalize(vertNormal);"
" vec3 ViewDir = normalize(vertViewDir);"
" vec3 LightDir = normalize(vertLightDir);"
" vec3 LightRefl = reflect(-LightDir, Normal);"
" vec3 ShadowCoord = (vertShadowCoord.xyz/vertShadowCoord.w)*0.5 + 0.5;"
" float shdw = texture(Shadows, ShadowCoord);"
" float ambi = 0.15;"
" float diff = pow(max(dot(Normal, LightDir)+0.1, 0.0),2.0)*0.9;"
" float spec = pow(max(dot(ViewDir, LightRefl), 0.0), 32.0)*0.4;"
" float emis = pow(vertLight, 2.0)*0.7;"
" fragColor = "
" BarColor * (diff*shdw+ambi)+"
" vec3(1.0, 1.0, 1.0)*spec*shdw+"
" vec3(0.1, 1.0, 0.3)*emis;"
"}"
).Compile();
result.AttachShader(vs).AttachShader(fs);
result.Link().Validate().Use();
return std::move(result);
}
Program&
self(void) {
return *
this; }
public:
ProgramUniform<Mat4f> projection_matrix, camera_matrix;
ProgramUniform<Mat4f> light_proj_matrix, light_matrix;
ProgramUniform<Vec3f> camera_pos, light_pos;
ProgramUniform<GLfloat> fade;
DisplayProg(void)
, projection_matrix(self(), "ProjectionMatrix")
, camera_matrix(self(), "CameraMatrix")
, light_proj_matrix(self(), "LightProjMatrix")
, light_matrix(self(), "LightMatrix")
, camera_pos(self(), "CameraPos")
, light_pos(self(), "LightPos")
, fade(self(), "Fade")
{ }
};
class DisplayScene
{
private:
Context gl;
{
vs.Source(
"#version 330\n"
"uniform mat4 ProjectionMatrix, CameraMatrix, ModelMatrix;"
"mat4 Matrix = ProjectionMatrix*CameraMatrix*ModelMatrix;"
"in vec4 Position;"
"void main(void)"
"{"
" gl_Position = Matrix*Position;"
"}"
);
fs.Source(
"#version 330\n"
"void main(void){ }"
);
prog.AttachShader(vs).AttachShader(fs);
prog.Link().Validate().Use();
return std::move(prog);
}
ProgramUniform<Mat4f> projection_matrix, camera_matrix, model_matrix;
std::list<shapes::ShapeWrapper> shapes;
std::list<shapes::ShapeWrapper>::iterator ishape;
double shape_time, blank_time;
public:
DisplayScene(void)
: gl()
, prog(make_prog())
, projection_matrix(prog, "ProjectionMatrix")
, camera_matrix(prog, "CameraMatrix")
, model_matrix(prog, "ModelMatrix")
, ishape(shapes.end())
, shape_time(0)
, blank_time(0)
{ }
template <typename ShapeGenerator>
void AddShape(const ShapeGenerator& shape_gen)
{
shapes.emplace_back(
shape_gen,
prog
);
if(shapes.size() == 1)
{
ishape = shapes.begin();
}
}
{
assert(!shapes.empty());
assert(ishape != shapes.end());
shapes::ShapeWrapper& shape = *ishape;
const double interval = 11.0;
double segment = time - shape_time;
double fade = segment*(interval-segment);
fade -= 1.0;
if(fade < 0.0) fade = 0.0;
fade = std::sqrt(fade/interval);
if(fade > 1.0) fade = 1.0;
if(segment > interval)
{
if(++ishape == shapes.end())
{
ishape = shapes.begin();
}
shape_time = time;
}
gl.Clear().DepthBuffer();
float dist = (1.0+
SineWave(time / 13.0))*2.5;
projection_matrix.Set(
Degrees(45),
1.0,
1.0+dist,
shape.BoundingSphere().Radius()*2.0+1.0+dist
)
);
camera_matrix.Set(
shape.BoundingSphere().Radius()+1.5+dist,
)
);
model_matrix.Set(
)
);
prog.Use();
shape.Use();
shape.Draw();
return fade;
}
};
class BarDisplay
{
private:
Context gl;
const GLuint side;
const GLuint shadow_size;
GLuint width, height;
DisplayProg display_prog;
ShadowProg shadow_prog;
shapes::ShapeWrapper cube;
DSATextureEXT offsets;
DSATextureEXT heights;
DSATextureEXT shadows;
DSAFramebufferEXT heights_fbo;
DSAFramebufferEXT shadows_fbo;
void init_offsets(void)
{
std::vector<GLfloat> offset_data(side*side*2);
auto p = offset_data.begin();
for(GLuint j=0; j!=side; ++j)
{
GLfloat v = j/GLfloat(side-1) - 0.5f;
for(GLuint i=0; i!=side; ++i)
{
GLfloat u = i/GLfloat(side-1) - 0.5f;
*p++ = u*side;
*p++ = v*side;
}
}
ProgramUniformSampler(display_prog, "Offsets").Set(0);
ProgramUniformSampler(shadow_prog, "Offsets").Set(0);
offsets.target = Texture::Target::_2D;
offsets.BindMulti(0, Texture::Target::_2D);
offsets.Image2D(
0,
side, side,
0,
offset_data.data()
);
}
void init_heights(void)
{
ProgramUniformSampler(display_prog, "Heights").Set(1);
ProgramUniformSampler(shadow_prog, "Heights").Set(1);
heights.target = Texture::Target::_2D;
heights.BindMulti(1, Texture::Target::_2D);
heights.Image2D(
0,
side, side,
0,
nullptr
);
heights.BorderColor(
Vec4f(1,1,1,1));
heights_fbo.target = Framebuffer::Target::Draw;
heights_fbo.Complete();
}
void init_shadows(void)
{
ProgramUniformSampler(display_prog, "Shadows").Set(2);
shadows.target = Texture::Target::_2D;
shadows.BindMulti(2, Texture::Target::_2D);
shadows.Image2D(
0,
shadow_size, shadow_size,
0,
nullptr
);
shadows.BorderColor(
Vec4f(1,1,1,1));
shadows_fbo.target = Framebuffer::Target::Draw;
shadows_fbo.Complete();
}
public:
BarDisplay(void)
: gl()
, side(128)
, shadow_size(512)
, cube(
List(
"Position")(
"Normal").Get(),
shapes::Cube(0.95, 1.0, 0.95, 0.0, 0.5, 0.0)
), display_vao(cube.VAOForProgram(display_prog))
, shadow_vao(cube.VAOForProgram(shadow_prog))
{
init_shadows();
init_heights();
init_offsets();
Degrees(74),
1.0,
1, 3*side
);
display_prog.light_proj_matrix.Set(light_proj);
shadow_prog.projection_matrix.Set(light_proj);
gl.PolygonOffset(4.0, 4.0);
}
void Reshape(GLuint vpw, GLuint vph)
{
width = vpw;
height= vph;
display_prog.projection_matrix.Set(
Degrees(65),
double(width)/height,
1, 3*side
)
);
}
double Update(DisplayScene& scene, double time)
{
gl.Viewport(side, side);
return scene.Draw(time);
}
void Draw(
double time,
double fade)
{
gl.Viewport(shadow_size, shadow_size);
gl.Clear().DepthBuffer();
side*1.5,
Degrees(-time * 27),
);
shadow_prog.fade.Set(fade);
shadow_prog.camera_matrix.Set(light);
shadow_prog.Use();
shadow_vao.Bind();
cube.Draw(side*side);
gl.Finish();
default_fb.Bind(Framebuffer::Target::Draw);
gl.Viewport(width, height);
gl.Clear().ColorBuffer().DepthBuffer();
side*1.1,
Degrees(time * 19),
Degrees(
SineWave(time / 20.0) * 39 + 50)
);
display_prog.fade.Set(fade);
display_prog.light_pos.Set(light.Position());
display_prog.camera_pos.Set(camera.Position());
display_prog.light_matrix.Set(light);
display_prog.camera_matrix.Set(camera);
display_prog.Use();
display_vao.Bind();
cube.Draw(side*side);
}
};
class CubeExample : public Example
{
private:
Context gl;
BarDisplay bar_display;
DisplayScene scene;
public:
CubeExample(void)
{
scene.AddShape(shapes::Cage());
scene.AddShape(shapes::WickerTorus(1.0, 0.5, 0.02, 12, 12));
scene.AddShape(shapes::SpiralSphere());
scene.AddShape(shapes::TwistedTorus(0.9, 0.5, 0.02, 8, 48, 7));
scene.AddShape(shapes::Icosahedron());
gl.ClearColor(0.1f, 0.1f, 0.1f, 0.0f);
gl.ClearDepth(1.0f);
}
void Reshape(GLuint width, GLuint height)
{
bar_display.Reshape(width, height);
}
{
double fade = bar_display.Update(scene, time);
bar_display.Draw(time, fade);
}
{
return time < 120.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 CubeExample);
}
}