void Clipping::attach(const ClipPlane &p)
{
- if(find(planes, &p)!=planes.end())
+ if(find_member(planes, &p, &AttachedPlane::plane)!=planes.end())
return;
if(planes.size()>=get_n_attach_points())
throw invalid_operation("Clipping::attach");
void Clipping::detach(const ClipPlane &p)
{
- vector<const ClipPlane *>::iterator i = find(planes, &p);
+ vector<AttachedPlane>::iterator i = find_member(planes, &p, &AttachedPlane::plane);
if(i!=planes.end())
{
planes.erase(i);
void Clipping::detach(unsigned i)
{
if(i<planes.size())
- detach(*planes[i]);
+ detach(*planes[i].plane);
}
-void Clipping::update_shader_data(ProgramData &shdata, const Matrix &view_matrix) const
+const ProgramData &Clipping::get_shader_data() const
{
- Matrix view_inverse = invert(view_matrix);
for(unsigned i=0; i<planes.size(); ++i)
- planes[i]->update_shader_data(shdata, view_inverse, i);
+ if(planes[i].plane->get_generation()!=planes[i].generation)
+ {
+ planes[i].plane->update_shader_data(shdata, i);
+ planes[i].generation = planes[i].plane->get_generation();
+ }
+
+ return shdata;
}
void Clipping::bind() const
#include <vector>
#include <msp/core/attributes.h>
#include "bindable.h"
+#include "programdata.h"
namespace Msp {
namespace GL {
class ClipPlane;
class Matrix;
-class ProgramData;
class Clipping: public Bindable<Clipping>
{
private:
- std::vector<const ClipPlane *> planes;
+ struct AttachedPlane
+ {
+ const ClipPlane *plane;
+ mutable unsigned generation;
+
+ AttachedPlane(const ClipPlane *p): plane(p), generation(0) { }
+ };
+
+ std::vector<AttachedPlane> planes;
+ mutable ProgramData shdata;
public:
static unsigned get_n_attach_points();
DEPRECATED void attach(unsigned, const ClipPlane &p) { attach(p); }
DEPRECATED void detach(unsigned);
- void update_shader_data(ProgramData &, const Matrix &) const;
+ const ProgramData &get_shader_data() const;
void bind() const;
namespace GL {
ClipPlane::ClipPlane():
- eq(0, 0, 0, 1)
+ eq(0, 0, 0, 1),
+ generation(0)
{ }
ClipPlane::ClipPlane(const Vector4 &e):
- eq(e)
+ eq(e),
+ generation(0)
{ }
ClipPlane::ClipPlane(const Vector3 &p, const Vector3 &d):
- eq(compose(d, -dot(p, d)))
+ eq(compose(d, -dot(p, d))),
+ generation(0)
{ }
void ClipPlane::set_equation(const Vector4 &e)
{
eq = e;
+ ++generation;
}
void ClipPlane::set_plane(const Vector3 &p, const Vector3 &d)
set_equation(compose(nd, -dot(p, nd)));
}
-void ClipPlane::update_shader_data(ProgramData &shdata, const Matrix &view_inverse, unsigned i) const
+void ClipPlane::update_shader_data(ProgramData &shdata, unsigned i) const
{
- shdata.uniform(format("clip_planes[%d].equation", i), eq*view_inverse);
+ shdata.uniform(format("clip_planes[%d].equation", i), eq);
}
} // namespace GL
{
private:
Vector4 eq;
+ unsigned generation;
public:
ClipPlane();
void set_equation(const Vector4 &);
void set_plane(const Vector3 &, const Vector3 &);
- void update_shader_data(ProgramData &, const Matrix &, unsigned) const;
+ void update_shader_data(ProgramData &, unsigned) const;
+
+ unsigned get_generation() const { return generation; }
};
} // namespace GL
position(0, 0, 1, 0),
spot_dir(0, 0, -1),
spot_exp(0),
- spot_cutoff(Geometry::Angle<float>::straight())
+ spot_cutoff(Geometry::Angle<float>::straight()),
+ generation(0)
{
attenuation[0] = 1;
attenuation[1] = 0;
void Light::set_color(const Color &c)
{
color = c;
+ ++generation;
}
void Light::set_transmittance(const Color &t)
{
transmittance = t;
+ ++generation;
}
void Light::set_matrix(const Matrix &m)
spot_dir = normalize(-matrix.column(2).slice<3>(0));
direction = (position.w ? spot_dir : normalize(-position.slice<3>(0)));
update_matrix();
+ ++generation;
}
void Light::set_position(const Vector4 &p)
if(!position.w)
direction = normalize(-position.slice<3>(0));
update_matrix();
+ ++generation;
}
void Light::set_spot_direction(const Vector3 &d)
if(position.w)
direction = spot_dir;
update_matrix();
+ ++generation;
}
void Light::set_spot_exponent(float e)
throw invalid_argument("Light::set_spot_exponent");
spot_exp = e;
+ ++generation;
}
void Light::set_spot_cutoff(const Geometry::Angle<float> &c)
throw invalid_argument("Light::set_spot_cutoff");
spot_cutoff = c;
+ ++generation;
}
void Light::disable_spot_cutoff()
{
set_spot_cutoff(Geometry::Angle<float>::straight());
+ ++generation;
}
void Light::set_attenuation(float c, float l, float q)
attenuation[0] = c;
attenuation[1] = l;
attenuation[2] = q;
+ ++generation;
}
-void Light::update_shader_data(ProgramData &shdata, const Matrix &view_matrix, unsigned i) const
+void Light::update_shader_data(ProgramData &shdata, unsigned i) const
{
string base = format("light_sources[%d]", i);
- shdata.uniform(base+".position", view_matrix*position);
+ shdata.uniform(base+".position", position);
shdata.uniform(base+".color", color.r*transmittance.r, color.g*transmittance.g, color.b*transmittance.b);
+ shdata.uniform(base+".enabled", 1);
}
float spot_exp;
Geometry::Angle<float> spot_cutoff;
float attenuation[3];
+ unsigned generation;
public:
Light();
void set_attenuation(float, float, float);
const float *get_attenuation() const { return attenuation; }
- /** Updates a ProgramData object with the uniforms for the Light. A view
- matrix and light source index must be passed in. */
- void update_shader_data(ProgramData &, const Matrix &, unsigned) const;
+ unsigned get_generation() const { return generation; }
+
+ /** Updates a ProgramData object with the uniforms for the Light. A light
+ source index must be passed in. Primarily used by Lighting. */
+ void update_shader_data(ProgramData &, unsigned) const;
};
} // namespace GL
namespace GL {
Lighting::Lighting():
- ambient(0.2),
zenith_direction(0, 0, 1),
- horizon_angle(Geometry::Angle<float>::zero()),
- fog_color(0.0f, 0.0f, 0.0f, 0.0f),
- fog_density(0.0f)
-{ }
+ horizon_angle(Geometry::Angle<float>::zero())
+{
+ set_ambient(0.2f);
+ set_fog_color(Color(0.0f, 0.0f, 0.0f, 0.0f));
+ set_fog_density(0.0f);
+}
Lighting::~Lighting()
{
void Lighting::set_ambient(const Color &a)
{
ambient = a;
+ shdata.uniform("ambient_color", ambient);
}
void Lighting::set_sky_color(const Color &s)
{
sky_color = s;
+ shdata.uniform("sky_color", sky_color);
}
void Lighting::set_zenith_direction(const Vector3 &d)
{
zenith_direction = d;
+ shdata.uniform("world_zenith_dir", zenith_direction);
}
void Lighting::set_horizon_angle(const Geometry::Angle<float> &a)
{
horizon_angle = a;
+ shdata.uniform("horizon_limit", horizon_angle.radians());
}
void Lighting::set_fog_color(const Color &c)
{
fog_color = c;
+ shdata.uniform("fog_color", fog_color);
}
void Lighting::set_fog_density(float d)
throw invalid_argument("Lighting::set_fog_density");
fog_density = d;
+ shdata.uniform("fog_density", fog_density);
}
void Lighting::set_fog_half_distance(float d)
void Lighting::attach(const Light &l)
{
- if(find(lights, &l)==lights.end())
+ if(find_member(lights, &l, &AttachedLight::light)==lights.end())
lights.push_back(&l);
}
void Lighting::detach(const Light &l)
{
- vector<const Light *>::iterator i = find(lights, &l);
+ vector<AttachedLight>::iterator i = find_member(lights, &l, &AttachedLight::light);
if(i!=lights.end())
lights.erase(i);
}
if(i>=lights.size())
return;
- detach(*lights[i]);
+ detach(*lights[i].light);
}
const Light *Lighting::get_attached_light(unsigned i) const
{
- return i<lights.size() ? lights[i] : 0;
+ return i<lights.size() ? lights[i].light : 0;
}
-void Lighting::update_shader_data(ProgramData &shdata, const Matrix &view_matrix) const
+void Lighting::update_shader_data(ProgramData &sd, const Matrix &) const
{
- shdata.uniform("ambient_color", ambient);
- shdata.uniform("sky_color", sky_color);
- shdata.uniform("world_zenith_dir", zenith_direction);
- shdata.uniform("horizon_limit", horizon_angle.radians());
- shdata.uniform("fog_color", fog_color);
- shdata.uniform("fog_density", fog_density);
+ sd.uniform("ambient_color", ambient);
+ sd.uniform("sky_color", sky_color);
+ sd.uniform("world_zenith_dir", zenith_direction);
+ sd.uniform("horizon_limit", horizon_angle.radians());
+ sd.uniform("fog_color", fog_color);
+ sd.uniform("fog_density", fog_density);
for(unsigned i=0; i<lights.size(); ++i)
- if(lights[i])
- lights[i]->update_shader_data(shdata, view_matrix, i);
+ if(lights[i].light)
+ lights[i].light->update_shader_data(sd, i);
+}
+
+const ProgramData &Lighting::get_shader_data() const
+{
+ for(unsigned i=0; i<lights.size(); ++i)
+ if(lights[i].light->get_generation()!=lights[i].generation)
+ {
+ lights[i].light->update_shader_data(shdata, i);
+ lights[i].generation = lights[i].light->get_generation();
+ }
+
+ return shdata;
+}
+
+void Lighting::set_debug_name(const string &name)
+{
+#ifdef DEBUG
+ shdata.set_debug_name(name+" [UBO]");
+#else
+ (void)name;
+#endif
}
void Lighting::Loader::ambient(float r, float g, float b)
{
- obj.ambient = Color(r, g, b);
+ obj.set_ambient(Color(r, g, b));
}
void Lighting::Loader::fog_color(float r, float g, float b)
};
private:
+ struct AttachedLight
+ {
+ const Light *light;
+ mutable unsigned generation;
+
+ AttachedLight(const Light *l): light(l), generation(0) { }
+ };
+
Color ambient;
Color sky_color;
Vector3 zenith_direction;
Geometry::Angle<float> horizon_angle;
Color fog_color;
float fog_density;
- std::vector<const Light *> lights;
+ std::vector<AttachedLight> lights;
std::vector<Light *> owned_data;
+ mutable ProgramData shdata;
public:
Lighting();
is returned. */
DEPRECATED const Light *get_attached_light(unsigned) const;
- const std::vector<const Light *> &get_attached_lights() const { return lights; }
-
/** Updates a ProgramData object with the uniforms for the Lighting,
including all attached light sources. A view matrix must be passed in. */
- void update_shader_data(ProgramData &, const Matrix &) const;
+ DEPRECATED void update_shader_data(ProgramData &, const Matrix &) const;
+
+ const ProgramData &get_shader_data() const;
+
+ void set_debug_name(const std::string &);
};
} // namespace GL
#include "camera.h"
#include "matrix.h"
+using namespace std;
+
namespace Msp {
namespace GL {
else
proj_matrix = Matrix::ortho(left, right, bottom, top, clip_near, clip_far);
proj_matrix = Matrix::rotation(rotate, Vector3(0, 0, 1))*proj_matrix;
+
+ shdata.uniform("clip_eye_matrix", proj_matrix);
}
void Camera::update_object_matrix()
columns[3] = compose(position, 1.0f);
matrix = Matrix::from_columns(columns);
view_matrix = invert(matrix);
+
+ shdata.uniform("eye_world_matrix", view_matrix);
+}
+
+void Camera::set_debug_name(const string &name)
+{
+#ifdef DEBUG
+ shdata.set_debug_name(name+" [UBO]");
+#else
+ (void)name;
+#endif
}
#include <msp/datafile/objectloader.h>
#include "placeable.h"
+#include "programdata.h"
namespace Msp {
namespace GL {
Vector3 up_dir;
Matrix view_matrix;
Matrix proj_matrix;
+ ProgramData shdata;
public:
Camera();
Vector4 unproject(const Vector4 &) const;
Vector3 unproject(const Vector3 &) const;
+ const ProgramData &get_shader_data() const { return shdata; }
+
private:
void update_projection_matrix();
void update_object_matrix();
+
+public:
+ void set_debug_name(const std::string &);
};
} // namespace GL
state_stack.push_back(State());
shdata_stack.reserve(32);
state = &state_stack.back();
-
- standard_shdata.uniform("clip_eye_matrix", Matrix());
- standard_shdata.uniform("eye_world_matrix", Matrix());
}
Renderer::~Renderer()
void Renderer::set_camera(const Camera &c)
{
state->camera = &c;
- standard_shdata.uniform("clip_eye_matrix", state->camera->get_projection_matrix());
- standard_shdata.uniform("eye_world_matrix", state->camera->get_view_matrix());
- changed |= STANDARD_SHDATA;
+ changed |= CAMERA_SHDATA;
set_matrix(Matrix());
}
void Renderer::set_lighting(const Lighting *l)
{
state->lighting = l;
- if(l)
- {
- l->update_shader_data(standard_shdata, Matrix());
- changed |= STANDARD_SHDATA;
- }
+ changed |= LIGHTING_SHDATA;
}
void Renderer::set_clipping(const Clipping *c)
{
state->clipping = c;
- if(c)
- {
- c->update_shader_data(standard_shdata, Matrix());
- changed |= STANDARD_SHDATA;
- }
+ changed |= CLIPPING_SHDATA;
}
void Renderer::set_shader_program(const Program *p, const ProgramData *d)
changed |= MATRIX;
bool camera_changed = (state->camera!=old_camera);
if(camera_changed)
- {
- if(state->camera)
- {
- standard_shdata.uniform("clip_eye_matrix", state->camera->get_projection_matrix());
- standard_shdata.uniform("eye_world_matrix", state->camera->get_view_matrix());
- }
- else
- {
- standard_shdata.uniform("clip_eye_matrix", Matrix());
- standard_shdata.uniform("eye_world_matrix", Matrix());
- }
- changed |= STANDARD_SHDATA;
- }
+ changed |= CAMERA_SHDATA;
if(state->lighting!=old_lighting)
- {
- if(state->lighting)
- {
- state->lighting->update_shader_data(standard_shdata, Matrix());
- changed |= STANDARD_SHDATA;
- }
- }
+ changed |= LIGHTING_SHDATA;
if(state->clipping!=old_clipping)
- {
- if(state->clipping)
- {
- state->clipping->update_shader_data(standard_shdata, Matrix());
- changed |= STANDARD_SHDATA;
- }
- }
+ changed |= CLIPPING_SHDATA;
}
void Renderer::end()
*state = State();
if(default_camera)
set_camera(*default_camera);
- else
- standard_shdata.uniform("clip_eye_matrix", Matrix());
shdata_stack.clear();
excluded.clear();
changed = (changed&~MATRIX)|STANDARD_SHDATA;
}
+ if(state->camera && ((changed&CAMERA_SHDATA) || shprog_changed))
+ {
+ state->camera->get_shader_data().apply();
+ changed &= ~CAMERA_SHDATA;
+ }
+
if(state->material && ((changed&MATERIAL_SHDATA) || shprog_changed))
{
state->material->get_shader_data().apply();
changed &= ~MATERIAL_SHDATA;
}
+ if(state->lighting && ((changed&LIGHTING_SHDATA) || shprog_changed))
+ {
+ state->lighting->get_shader_data().apply();
+ changed &= ~LIGHTING_SHDATA;
+ }
+
+ if(state->clipping && ((changed&CLIPPING_SHDATA) || shprog_changed))
+ {
+ state->clipping->get_shader_data().apply();
+ changed &= ~CLIPPING_SHDATA;
+ }
+
if((changed&STANDARD_SHDATA) || shprog_changed)
{
standard_shdata.apply();
MATRIX = 2,
SHADER_DATA = 16,
MATERIAL_SHDATA = 32,
- STANDARD_SHDATA = 64
+ STANDARD_SHDATA = 64,
+ CAMERA_SHDATA = 128,
+ LIGHTING_SHDATA = 256,
+ CLIPPING_SHDATA = 512
};
const Camera *default_camera;
{
add_type<Animation>().suffix(".anim").keyword("animation");
add_type<Armature>().suffix(".arma").keyword("armature");
- add_type<Camera>().keyword("camera");
+ add_type<Camera>().keyword("camera")
+ .notify(&Resources::set_debug_name<Camera>);
add_type<Font>().keyword("font");
add_type<KeyFrame>().suffix(".kframe").keyword("keyframe");
add_type<Light>().keyword("light");
- add_type<Lighting>().suffix(".lightn").keyword("lighting");
+ add_type<Lighting>().suffix(".lightn").keyword("lighting")
+ .notify(&Resources::set_debug_name<Lighting>);
add_type<Material>().suffix(".mat")
.creator(&Resources::create_material).notify(&Resources::set_debug_name<Material>);
add_type<Mesh>().keyword("mesh")