From 126161d1d44ab9503bc747d24a07b7b9d15e527a Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 28 Nov 2013 14:14:56 +0200 Subject: [PATCH] Better state tracking for bound objects --- source/light.cpp | 52 ++++++++++++++++++++++++++++++++++--------- source/light.h | 15 +++++++++++++ source/lighting.cpp | 4 ++++ source/lightunit.cpp | 8 +++++++ source/lightunit.h | 1 + source/material.cpp | 30 +++++++++++++++++++------ source/material.h | 14 ++++++++++++ source/pixelstore.cpp | 32 +++++++++++++++++++------- source/pixelstore.h | 11 +++++++++ source/texenv.cpp | 26 +++++++++++++++++----- source/texenv.h | 10 +++++++++ source/texture.cpp | 49 +++++++++++++++++++++++----------------- source/texunit.cpp | 16 +++++++++++++ source/texunit.h | 2 ++ 14 files changed, 217 insertions(+), 53 deletions(-) diff --git a/source/light.cpp b/source/light.cpp index f9b45c87..d4b45aaf 100644 --- a/source/light.cpp +++ b/source/light.cpp @@ -21,34 +21,72 @@ Light::Light(): attenuation[2] = 0; } +void Light::update_parameter(int mask, int index) const +{ + if(index<0) + { + LightUnit *unit = LightUnit::find_unit(this); + if(!unit) + return; + + index = unit->get_index(); + } + + GLenum l = GL_LIGHT0+index; + if(mask&DIFFUSE) + glLightfv(l, GL_DIFFUSE, &diffuse.r); + if(mask&SPECULAR) + glLightfv(l, GL_SPECULAR, &specular.r); + if(mask&POSITION) + glLightfv(l, GL_POSITION, &position.x); + if(mask&SPOT_DIR) + glLightfv(l, GL_SPOT_DIRECTION, &spot_dir.x); + if(mask&SPOT_EXP) + glLightf(l, GL_SPOT_EXPONENT, spot_exp); + if(mask&SPOT_CUTOFF) + glLightf(l, GL_SPOT_CUTOFF, spot_cutoff); + if(mask&ATTENUATION) + { + glLightf(l, GL_CONSTANT_ATTENUATION, attenuation[0]); + glLightf(l, GL_LINEAR_ATTENUATION, attenuation[1]); + glLightf(l, GL_QUADRATIC_ATTENUATION, attenuation[2]); + } +} + void Light::set_diffuse(const Color &c) { diffuse = c; + update_parameter(DIFFUSE); } void Light::set_specular(const Color &c) { specular = c; + update_parameter(SPECULAR); } void Light::set_position(const Vector4 &p) { position = p; + update_parameter(POSITION); } void Light::set_spot_direction(const Vector3 &d) { spot_dir = d; + update_parameter(SPOT_DIR); } void Light::set_spot_exponent(float e) { spot_exp = e; + update_parameter(SPOT_EXP); } void Light::set_spot_cutoff(float c) { spot_cutoff = c; + update_parameter(SPOT_CUTOFF); } void Light::set_attenuation(float c, float l, float q) @@ -56,6 +94,7 @@ void Light::set_attenuation(float c, float l, float q) attenuation[0] = c; attenuation[1] = l; attenuation[2] = q; + update_parameter(ATTENUATION); } void Light::bind_to(unsigned i) const @@ -63,17 +102,8 @@ void Light::bind_to(unsigned i) const LightUnit &unit = LightUnit::get_unit(i); if(unit.set_light(this)) { - GLenum l = GL_LIGHT0+unit.get_index(); - enable(l); - glLightfv(l, GL_DIFFUSE, &diffuse.r); - glLightfv(l, GL_SPECULAR, &specular.r); - glLightfv(l, GL_POSITION, &position.x); - glLightfv(l, GL_SPOT_DIRECTION, &spot_dir.x); - glLightf(l, GL_SPOT_EXPONENT, spot_exp); - glLightf(l, GL_SPOT_CUTOFF, spot_cutoff); - glLightf(l, GL_CONSTANT_ATTENUATION, attenuation[0]); - glLightf(l, GL_LINEAR_ATTENUATION, attenuation[1]); - glLightf(l, GL_QUADRATIC_ATTENUATION, attenuation[2]); + enable(GL_LIGHT0+unit.get_index()); + update_parameter(-1, unit.get_index()); } } diff --git a/source/light.h b/source/light.h index cf9ab8a1..1c6a5227 100644 --- a/source/light.h +++ b/source/light.h @@ -11,6 +11,17 @@ namespace GL { class Light { private: + enum ParameterMask + { + DIFFUSE = 1, + SPECULAR = 2, + POSITION = 4, + SPOT_DIR = 8, + SPOT_EXP = 16, + SPOT_CUTOFF = 32, + ATTENUATION = 64 + }; + Color diffuse; Color specular; Vector4 position; @@ -22,6 +33,10 @@ private: public: Light(); +private: + void update_parameter(int, int = -1) const; + +public: void set_diffuse(const Color &c); void set_specular(const Color &c); const Color &get_diffuse() const { return diffuse; } diff --git a/source/lighting.cpp b/source/lighting.cpp index 0af2416c..aae5d331 100644 --- a/source/lighting.cpp +++ b/source/lighting.cpp @@ -20,6 +20,8 @@ void Lighting::attach(unsigned i, const Light &l) lights.resize(i+1); lights[i] = &l; + if(current()==this) + l.bind_to(i); } void Lighting::detach(unsigned i) @@ -28,6 +30,8 @@ void Lighting::detach(unsigned i) return; lights[i] = 0; + if(current()==this) + Light::unbind_from(i); } void Lighting::bind() const diff --git a/source/lightunit.cpp b/source/lightunit.cpp index 58d42e6d..d33c9b25 100644 --- a/source/lightunit.cpp +++ b/source/lightunit.cpp @@ -44,5 +44,13 @@ LightUnit &LightUnit::get_unit(unsigned n) return units[n]; } +LightUnit *LightUnit::find_unit(const Light *l) +{ + for(vector::iterator i=units.begin(); i!=units.end(); ++i) + if(i->light==l) + return &*i; + return 0; +} + } // namespace GL } // namespace Msp diff --git a/source/lightunit.h b/source/lightunit.h index 3f65d770..658712df 100644 --- a/source/lightunit.h +++ b/source/lightunit.h @@ -26,6 +26,7 @@ public: static unsigned get_n_units(); static LightUnit &get_unit(unsigned i); + static LightUnit *find_unit(const Light *); }; } // namespace GL diff --git a/source/material.cpp b/source/material.cpp index 12d15010..d6e21683 100644 --- a/source/material.cpp +++ b/source/material.cpp @@ -12,41 +12,57 @@ Material::Material(): shininess(0) { } +void Material::update_parameter(int mask) const +{ + if(cur_obj!=this) + return; + + if(mask&AMBIENT) + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r); + if(mask&DIFFUSE) + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r); + if(mask&SPECULAR) + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r); + if(mask&EMISSION) + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &emission.r); + if(mask&SHININESS) + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); +} + void Material::set_ambient(const Color &a) { ambient = a; + update_parameter(AMBIENT); } void Material::set_diffuse(const Color &d) { diffuse = d; + update_parameter(DIFFUSE); } void Material::set_specular(const Color &s) { specular = s; + update_parameter(SPECULAR); } void Material::set_emission(const Color &e) { emission = e; + update_parameter(EMISSION); } void Material::set_shininess(float s) { shininess = s; + update_parameter(SHININESS); } void Material::bind() const { if(set_current(this)) - { - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r); - glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &emission.r); - glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); - } + update_parameter(-1); } diff --git a/source/material.h b/source/material.h index 3a65f339..a787a6d3 100644 --- a/source/material.h +++ b/source/material.h @@ -28,6 +28,15 @@ public: }; private: + enum ParameterMask + { + AMBIENT = 1, + DIFFUSE = 2, + SPECULAR = 4, + EMISSION = 8, + SHININESS = 16 + }; + Color ambient; Color diffuse; Color specular; @@ -36,6 +45,11 @@ private: public: Material(); + +private: + void update_parameter(int) const; + +public: void set_ambient(const Color &a); void set_diffuse(const Color &d); void set_specular(const Color &s); diff --git a/source/pixelstore.cpp b/source/pixelstore.cpp index c32cf609..011866e3 100644 --- a/source/pixelstore.cpp +++ b/source/pixelstore.cpp @@ -27,10 +27,31 @@ PixelStore PixelStore::from_image(const Graphics::Image &img) return pstore; } +void PixelStore::update_parameter(int mask) const +{ + if(cur_obj!=this) + return; + + if(mask&SIZE) + { + glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, image_height); + } + if(mask&ORIGIN) + { + glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels); + glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows); + glPixelStorei(GL_UNPACK_SKIP_IMAGES, skip_images); + } + if(mask&ALIGNMENT) + glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); +} + void PixelStore::set_canvas_size(unsigned w, unsigned h) { row_length = w; image_height = h; + update_parameter(SIZE); } void PixelStore::set_origin(unsigned x, unsigned y, unsigned z) @@ -38,24 +59,19 @@ void PixelStore::set_origin(unsigned x, unsigned y, unsigned z) skip_pixels = x; skip_rows = y; skip_images = z; + update_parameter(ORIGIN); } void PixelStore::set_alignment(unsigned a) { alignment = a; + update_parameter(ALIGNMENT); } void PixelStore::bind() const { if(set_current(this)) - { - glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length); - glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, image_height); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels); - glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows); - glPixelStorei(GL_UNPACK_SKIP_IMAGES, skip_images); - glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); - } + update_parameter(-1); } } // namespace GL diff --git a/source/pixelstore.h b/source/pixelstore.h index 0c430300..52295567 100644 --- a/source/pixelstore.h +++ b/source/pixelstore.h @@ -10,6 +10,13 @@ namespace GL { class PixelStore: public BindableWithDefault { private: + enum ParameterMask + { + SIZE, + ORIGIN, + ALIGNMENT + }; + unsigned row_length; unsigned image_height; unsigned skip_pixels; @@ -22,6 +29,10 @@ public: static PixelStore from_image(const Graphics::Image &); +private: + void update_parameter(int) const; + +public: void set_canvas_size(unsigned, unsigned); void set_origin(unsigned, unsigned, unsigned); void set_alignment(unsigned); diff --git a/source/texenv.cpp b/source/texenv.cpp index ff9ea197..51adf9fb 100644 --- a/source/texenv.cpp +++ b/source/texenv.cpp @@ -15,18 +15,33 @@ const TexEnv &TexEnv::default_object() return obj; } +void TexEnv::update_parameter(int mask) const +{ + if(TexUnit::current().get_texenv()!=this) + { + TexUnit *unit = TexUnit::find_unit(this); + if(!unit) + return; + + unit->bind(); + } + + if(mask&MODE) + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode); + if(mask&COLOR) + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &color.r); +} + void TexEnv::set_mode(TexEnvMode m) { mode = m; - if(TexUnit::current().get_texenv()==this) - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode); + update_parameter(MODE); } void TexEnv::set_color(const Color &c) { color = c; - if(TexUnit::current().get_texenv()==this) - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &color.r); + update_parameter(COLOR); } void TexEnv::bind_to(unsigned i) const @@ -35,8 +50,7 @@ void TexEnv::bind_to(unsigned i) const if(unit.set_texenv(this)) { unit.bind(); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode); - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &color.r); + update_parameter(-1); } } diff --git a/source/texenv.h b/source/texenv.h index 55a12f30..61f70085 100644 --- a/source/texenv.h +++ b/source/texenv.h @@ -20,6 +20,12 @@ enum TexEnvMode class TexEnv { private: + enum ParameterMask + { + MODE = 1, + COLOR = 2 + }; + TexEnvMode mode; Color color; @@ -28,6 +34,10 @@ public: static const TexEnv &default_object(); +private: + void update_parameter(int) const; + +public: void set_mode(TexEnvMode); void set_color(const Color &); TexEnvMode get_mode() const { return mode; } diff --git a/source/texture.cpp b/source/texture.cpp index f6b5f8e4..fe8b7be9 100644 --- a/source/texture.cpp +++ b/source/texture.cpp @@ -64,29 +64,36 @@ Texture::~Texture() void Texture::update_parameter(int mask) const { - if(TexUnit::current().get_texture()==this) + if(TexUnit::current().get_texture()!=this) { - if(mask&MIN_FILTER) - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filter); - if(mask&MAG_FILTER) - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filter); - if(mask&MAX_ANISOTROPY) - glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy); - if(mask&WRAP_S) - glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap_s); - if(mask&WRAP_T) - glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap_t); - if(mask&WRAP_R) - glTexParameteri(target, GL_TEXTURE_WRAP_R, wrap_r); - if(mask&GENERATE_MIPMAP) - glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, gen_mipmap); - if(mask&COMPARE) - glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, (compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE)); - if(mask&COMPARE_FUNC) - glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, cmp_func); + TexUnit *unit = TexUnit::find_unit(this); + if(!unit) + { + dirty_params |= mask; + return; + } + + unit->bind(); } - else - dirty_params |= mask; + + if(mask&MIN_FILTER) + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filter); + if(mask&MAG_FILTER) + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filter); + if(mask&MAX_ANISOTROPY) + glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy); + if(mask&WRAP_S) + glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap_s); + if(mask&WRAP_T) + glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap_t); + if(mask&WRAP_R) + glTexParameteri(target, GL_TEXTURE_WRAP_R, wrap_r); + if(mask&GENERATE_MIPMAP) + glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, gen_mipmap); + if(mask&COMPARE) + glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, (compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE)); + if(mask&COMPARE_FUNC) + glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, cmp_func); } void Texture::set_min_filter(TextureFilter f) diff --git a/source/texunit.cpp b/source/texunit.cpp index 982e524e..1129a036 100644 --- a/source/texunit.cpp +++ b/source/texunit.cpp @@ -96,5 +96,21 @@ TexUnit &TexUnit::current() return *cur_unit; } +TexUnit *TexUnit::find_unit(const Texture *tex) +{ + for(vector::iterator i=units.begin(); i!=units.end(); ++i) + if(i->texture==tex) + return &*i; + return 0; +} + +TexUnit *TexUnit::find_unit(const TexEnv *env) +{ + for(vector::iterator i=units.begin(); i!=units.end(); ++i) + if(i->texenv==env) + return &*i; + return 0; +} + } // namespace GL } // namespace Msp diff --git a/source/texunit.h b/source/texunit.h index 8bcb5f02..05952a22 100644 --- a/source/texunit.h +++ b/source/texunit.h @@ -36,6 +36,8 @@ public: static unsigned get_n_units(); static TexUnit &get_unit(unsigned); static TexUnit ¤t(); + static TexUnit *find_unit(const Texture *); + static TexUnit *find_unit(const TexEnv *); }; } // namespace GL -- 2.43.0