From f79fbf25c3370554cf57451b12097a12356f7270 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 10 Jul 2017 21:54:43 +0200 Subject: [PATCH] ShaderGenerator: big overhaul, don't generate more shaders than needed --- panda/src/display/graphicsStateGuardian.cxx | 91 +- panda/src/display/standardMunger.cxx | 11 +- panda/src/gobj/material.I | 8 + panda/src/gobj/material.h | 4 +- panda/src/gobj/shader.cxx | 117 +- panda/src/gobj/shader.h | 11 + panda/src/pgraph/alphaTestAttrib.cxx | 16 - panda/src/pgraph/alphaTestAttrib.h | 1 - panda/src/pgraph/auxBitplaneAttrib.cxx | 8 - panda/src/pgraph/auxBitplaneAttrib.h | 1 - panda/src/pgraph/clipPlaneAttrib.cxx | 8 - panda/src/pgraph/clipPlaneAttrib.h | 1 - panda/src/pgraph/colorAttrib.cxx | 13 - panda/src/pgraph/colorAttrib.h | 1 - panda/src/pgraph/colorBlendAttrib.cxx | 8 - panda/src/pgraph/colorBlendAttrib.h | 1 - panda/src/pgraph/colorScaleAttrib.cxx | 11 - panda/src/pgraph/colorScaleAttrib.h | 1 - panda/src/pgraph/cullableObject.cxx | 10 +- panda/src/pgraph/cullableObject.h | 1 + panda/src/pgraph/fogAttrib.cxx | 8 - panda/src/pgraph/fogAttrib.h | 1 - panda/src/pgraph/lightAttrib.cxx | 8 - panda/src/pgraph/lightAttrib.h | 1 - panda/src/pgraph/lightRampAttrib.cxx | 8 - panda/src/pgraph/lightRampAttrib.h | 1 - panda/src/pgraph/logicOpAttrib.cxx | 8 - panda/src/pgraph/logicOpAttrib.h | 1 - panda/src/pgraph/materialAttrib.I | 12 +- panda/src/pgraph/materialAttrib.cxx | 57 +- panda/src/pgraph/materialAttrib.h | 5 - panda/src/pgraph/renderAttrib.I | 19 - panda/src/pgraph/renderAttrib.cxx | 8 - panda/src/pgraph/renderAttrib.h | 2 - panda/src/pgraph/renderState.cxx | 84 -- panda/src/pgraph/renderState.h | 6 - panda/src/pgraph/rescaleNormalAttrib.cxx | 16 - panda/src/pgraph/rescaleNormalAttrib.h | 1 - panda/src/pgraph/shaderAttrib.cxx | 20 - panda/src/pgraph/shaderAttrib.h | 1 - panda/src/pgraph/texGenAttrib.cxx | 8 - panda/src/pgraph/texGenAttrib.h | 1 - panda/src/pgraph/texMatrixAttrib.cxx | 22 - panda/src/pgraph/texMatrixAttrib.h | 1 - panda/src/pgraph/textureAttrib.I | 42 +- panda/src/pgraph/textureAttrib.cxx | 80 +- panda/src/pgraph/textureAttrib.h | 9 - panda/src/pgraph/transparencyAttrib.cxx | 15 - panda/src/pgraph/transparencyAttrib.h | 1 - panda/src/pgraphnodes/directionalLight.cxx | 5 +- panda/src/pgraphnodes/directionalLight.h | 2 - panda/src/pgraphnodes/lightLensNode.I | 9 + panda/src/pgraphnodes/lightLensNode.cxx | 2 + panda/src/pgraphnodes/lightLensNode.h | 3 + panda/src/pgraphnodes/pointLight.cxx | 5 +- panda/src/pgraphnodes/pointLight.h | 2 - panda/src/pgraphnodes/shaderGenerator.cxx | 1370 +++++++++++-------- panda/src/pgraphnodes/shaderGenerator.h | 106 +- panda/src/pgraphnodes/spotlight.cxx | 5 +- panda/src/pgraphnodes/spotlight.h | 2 - panda/src/pstatclient/pStatProperties.cxx | 2 +- 61 files changed, 1092 insertions(+), 1190 deletions(-) diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 05126797a1..0d337a803e 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -44,6 +44,7 @@ #include "ambientLight.h" #include "directionalLight.h" #include "pointLight.h" +#include "sphereLight.h" #include "spotlight.h" #include "textureReloadRequest.h" #include "shaderAttrib.h" @@ -1122,6 +1123,28 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, return &LMatrix4::ident_mat(); } } + case Shader::SMO_texscale_i: { + const TexMatrixAttrib *tma; + const TextureAttrib *ta; + if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma) && + index < ta->get_num_on_stages()) { + LVecBase3 scale = tma->get_transform(ta->get_on_stage(index))->get_scale(); + t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,scale[0],scale[1],scale[2],0); + return &t; + } else { + return &LMatrix4::ident_mat(); + } + } + case Shader::SMO_texcolor_i: { + const TextureAttrib *ta; + if (_target_rs->get_attrib(ta) && index < ta->get_num_on_stages()) { + TextureStage *ts = ta->get_on_stage(index); + t.set_row(3, ts->get_color()); + return &t; + } else { + return &LMatrix4::zeros_mat(); + } + } case Shader::SMO_tex_is_alpha_i: { // This is a hack so we can support both F_alpha and other formats in the // default shader, to fix font rendering in GLES2 @@ -1156,9 +1179,14 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, nassertr(!np.is_empty(), &LMatrix4::zeros_mat()); const PlaneNode *plane_node; DCAST_INTO_R(plane_node, np.node(), &LMatrix4::zeros_mat()); - LPlane p (plane_node->get_plane()); - p.xform(np.get_net_transform()->get_mat()); // World-space - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,p[0],p[1],p[2],p[3]); + + // Transform plane to world space + CPT(TransformState) transform = np.get_net_transform(); + LPlane plane = plane_node->get_plane(); + if (!transform->is_identity()) { + plane.xform(transform->get_mat()); + } + t.set_row(3, plane); return &t; } case Shader::SMO_apiview_clipplane_i: { @@ -1195,7 +1223,6 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, } case Shader::SMO_world_to_view: { return &(_scene_setup->get_world_transform()->get_mat()); - break; } case Shader::SMO_view_to_world: { return &(_scene_setup->get_camera_transform()->get_mat()); @@ -1387,6 +1414,62 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, } return fetch_specified_member(NodePath(), name, t); } + case Shader::SMO_light_source_i_packed: { + // The light matrix contains COLOR, ATTENUATION, POSITION, VIEWVECTOR + const LightAttrib *target_light; + _target_rs->get_attrib_def(target_light); + + // We don't count ambient lights, which would be pretty silly to handle + // via this mechanism. + size_t num_lights = target_light->get_num_non_ambient_lights(); + if (index >= 0 && (size_t)index < num_lights) { + NodePath np = target_light->get_on_light((size_t)index); + nassertr(!np.is_empty(), &LMatrix4::ident_mat()); + PandaNode *node = np.node(); + Light *light = node->as_light(); + nassertr(light != nullptr, &LMatrix4::zeros_mat()); + t.set_row(0, light->get_color()); + t.set_row(1, light->get_attenuation()); + + LMatrix4 mat = np.get_net_transform()->get_mat() * + _scene_setup->get_world_transform()->get_mat(); + + if (node->is_of_type(DirectionalLight::get_class_type())) { + LVecBase3 d = mat.xform_vec(((const DirectionalLight *)node)->get_direction()); + d.normalize(); + t.set_row(2, LVecBase4(d, 0)); + t.set_row(3, LVecBase4(-d, 0)); + + } else if (node->is_of_type(LightLensNode::get_class_type())) { + const Lens *lens = ((const LightLensNode *)node)->get_lens(); + + LPoint3 p = mat.xform_point(lens->get_nodal_point()); + t.set_row(3, LVecBase4(p)); + + // For shadowed point light we need to store near/far. + // For spotlight we need to store cutoff angle. + if (node->is_of_type(Spotlight::get_class_type())) { + PN_stdfloat cutoff = ccos(deg_2_rad(lens->get_hfov() * 0.5f)); + LVecBase3 d = -(mat.xform_vec(lens->get_view_vector())); + t.set_cell(1, 3, ((const Spotlight *)node)->get_exponent()); + t.set_row(2, LVecBase4(d, cutoff)); + + } else if (node->is_of_type(PointLight::get_class_type())) { + t.set_cell(1, 3, lens->get_near()); + t.set_cell(3, 3, lens->get_far()); + + if (node->is_of_type(SphereLight::get_class_type())) { + t.set_cell(2, 3, ((const SphereLight *)node)->get_radius()); + } + } + } + } else if (index == 0) { + // Apply the default OpenGL lights otherwise. + // Special exception for light 0, which defaults to white. + t.set_row(0, _light_color_scale); + } + return &t; + } default: nassertr(false /*should never get here*/, &LMatrix4::ident_mat()); return &LMatrix4::ident_mat(); diff --git a/panda/src/display/standardMunger.cxx b/panda/src/display/standardMunger.cxx index 4b6aa01f67..1cb64189da 100644 --- a/panda/src/display/standardMunger.cxx +++ b/panda/src/display/standardMunger.cxx @@ -343,28 +343,29 @@ munge_state_impl(const RenderState *state) { #ifdef HAVE_CG if (_auto_shader) { - CPT(RenderState) shader_state = munged_state->get_auto_shader_state(); GraphicsStateGuardian *gsg = get_gsg(); ShaderGenerator *shader_generator = gsg->get_shader_generator(); if (shader_generator == nullptr) { shader_generator = new ShaderGenerator(gsg); gsg->set_shader_generator(shader_generator); } - if (shader_state->_generated_shader == NULL) { + if (munged_state->_generated_shader == nullptr) { // Cache the generated ShaderAttrib on the shader state. GeomVertexAnimationSpec spec; // Currently we overload this flag to request vertex animation for the // shader generator. const ShaderAttrib *sattr; - shader_state->get_attrib_def(sattr); + munged_state->get_attrib_def(sattr); if (sattr->get_flag(ShaderAttrib::F_hardware_skinning)) { spec.set_hardware(4, true); } - shader_state->_generated_shader = shader_generator->synthesize_shader(shader_state, spec); + munged_state->_generated_shader = shader_generator->synthesize_shader(munged_state, spec); + } + if (munged_state->_generated_shader != nullptr) { + munged_state = munged_state->set_attrib(munged_state->_generated_shader); } - munged_state = munged_state->set_attrib(shader_state->_generated_shader); } #endif diff --git a/panda/src/gobj/material.I b/panda/src/gobj/material.I index a408f2a0e4..777a555200 100644 --- a/panda/src/gobj/material.I +++ b/panda/src/gobj/material.I @@ -327,3 +327,11 @@ INLINE void Material:: set_attrib_lock() { _flags |= F_attrib_lock; } + +/** + * + */ +INLINE int Material:: +get_flags() const { + return _flags; +} diff --git a/panda/src/gobj/material.h b/panda/src/gobj/material.h index eb1a36747e..17344df46a 100644 --- a/panda/src/gobj/material.h +++ b/panda/src/gobj/material.h @@ -128,6 +128,8 @@ PUBLISHED: MAKE_PROPERTY(twoside, get_twoside, set_twoside); public: + INLINE int get_flags() const; + enum Flags { F_ambient = 0x001, F_diffuse = 0x002, @@ -157,8 +159,6 @@ private: int _flags; - friend class MaterialAttrib; - public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &me); diff --git a/panda/src/gobj/shader.cxx b/panda/src/gobj/shader.cxx index 7147a108c0..d60e51838f 100644 --- a/panda/src/gobj/shader.cxx +++ b/panda/src/gobj/shader.cxx @@ -450,9 +450,11 @@ cp_dependency(ShaderMatInput inp) { } } if ((inp == SMO_light_ambient) || - (inp == SMO_light_source_i_attrib)) { - dep |= SSD_light; - if (inp == SMO_light_source_i_attrib) { + (inp == SMO_light_source_i_attrib) || + (inp == SMO_light_source_i_packed)) { + dep |= SSD_light | SSD_frame; + if (inp == SMO_light_source_i_attrib || + inp == SMO_light_source_i_packed) { dep |= SSD_view_transform; } } @@ -465,7 +467,7 @@ cp_dependency(ShaderMatInput inp) { (inp == SMO_apiview_clipplane_i)) { dep |= SSD_clip_planes; } - if (inp == SMO_texmat_i || inp == SMO_inv_texmat_i) { + if (inp == SMO_texmat_i || inp == SMO_inv_texmat_i || inp == SMO_texscale_i) { dep |= SSD_tex_matrix; } if ((inp == SMO_window_size) || @@ -483,7 +485,7 @@ cp_dependency(ShaderMatInput inp) { (inp == SMO_apiclip_to_apiview)) { dep |= SSD_projection; } - if (inp == SMO_tex_is_alpha_i) { + if (inp == SMO_tex_is_alpha_i || inp == SMO_texcolor_i) { dep |= SSD_texture | SSD_frame; } @@ -734,6 +736,29 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { return true; } + if (pieces[0] == "mat" && pieces[1] == "shadow") { + if ((!cp_errchk_parameter_words(p,3))|| + (!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_uniform(p))|| + (!cp_errchk_parameter_float(p,16,16))) { + return false; + } + ShaderMatSpec bind; + bind._id = p._id; + bind._piece = SMP_whole; + bind._func = SMF_compose; + bind._part[1] = SMO_light_source_i_attrib; + bind._arg[1] = InternalName::make("shadowViewMatrix"); + bind._part[0] = SMO_view_to_apiview; + bind._arg[0] = NULL; + bind._index = atoi(pieces[2].c_str()); + + cp_optimize_mat_spec(bind); + _mat_spec.push_back(bind); + _mat_deps |= bind._dep[0] | bind._dep[1]; + return true; + } + // Implement some macros. Macros work by altering the contents of the // 'pieces' array, and then falling through. @@ -833,7 +858,13 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { ShaderMatSpec bind; bind._id = p._id; + bind._piece = SMP_whole; bind._func = SMF_compose; + bind._part[1] = SMO_light_source_i_attrib; + bind._arg[1] = InternalName::make("shadowViewMatrix"); + bind._part[0] = SMO_view_to_apiview; + bind._arg[0] = NULL; + bind._index = atoi(pieces[2].c_str()); int next = 1; pieces.push_back(""); @@ -958,6 +989,30 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._arg[0] = NULL; bind._part[1] = SMO_identity; bind._arg[1] = NULL; + } else if (pieces[1].compare(0, 5, "light") == 0) { + if (!cp_errchk_parameter_float(p,16,16)) { + return false; + } + bind._id = p._id; + bind._piece = SMP_transpose; + bind._func = SMF_first; + bind._part[0] = SMO_light_source_i_packed; + bind._arg[0] = NULL; + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + bind._index = atoi(pieces[1].c_str() + 5); + } else if (pieces[1].compare(0, 5, "lspec") == 0) { + if (!cp_errchk_parameter_float(p,3,4)) { + return false; + } + bind._id = p._id; + bind._piece = SMP_row3; + bind._func = SMF_first; + bind._part[0] = SMO_light_source_i_attrib; + bind._arg[0] = InternalName::make("specular"); + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + bind._index = atoi(pieces[1].c_str() + 5); } else { cp_report_error(p,"Unknown attr parameter."); return false; @@ -1094,6 +1149,52 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { return true; } + if (pieces[0] == "texscale") { + if ((!cp_errchk_parameter_words(p,2))|| + (!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_uniform(p))|| + (!cp_errchk_parameter_float(p,3,4))) { + return false; + } + ShaderMatSpec bind; + bind._id = p._id; + bind._piece = SMP_row3; + bind._func = SMF_first; + bind._part[0] = SMO_texscale_i; + bind._arg[0] = NULL; + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + bind._index = atoi(pieces[1].c_str()); + + cp_optimize_mat_spec(bind); + _mat_spec.push_back(bind); + _mat_deps |= bind._dep[0] | bind._dep[1]; + return true; + } + + if (pieces[0] == "texcolor") { + if ((!cp_errchk_parameter_words(p,2))|| + (!cp_errchk_parameter_in(p)) || + (!cp_errchk_parameter_uniform(p))|| + (!cp_errchk_parameter_float(p,3,4))) { + return false; + } + ShaderMatSpec bind; + bind._id = p._id; + bind._piece = SMP_row3; + bind._func = SMF_first; + bind._part[0] = SMO_texcolor_i; + bind._arg[0] = NULL; + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + bind._index = atoi(pieces[1].c_str()); + + cp_optimize_mat_spec(bind); + _mat_spec.push_back(bind); + _mat_deps |= bind._dep[0] | bind._dep[1]; + return true; + } + if (pieces[0] == "plane") { if ((!cp_errchk_parameter_words(p,2))|| (!cp_errchk_parameter_in(p)) || @@ -1233,9 +1334,9 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { } ShaderTexSpec bind; bind._id = p._id; - bind._name = InternalName::make(pieces[1])->append("shadowMap"); - bind._stage = -1; - bind._part = STO_named_input; + bind._name = nullptr; + bind._stage = atoi(pieces[1].c_str()); + bind._part = STO_light_i_shadow_map; switch (p._type) { case SAT_sampler2d: bind._desired_type = Texture::TT_2d_texture; break; case SAT_sampler_cube: bind._desired_type = Texture::TT_cube_map; break; diff --git a/panda/src/gobj/shader.h b/panda/src/gobj/shader.h index 2eb0bc910a..6226b02960 100644 --- a/panda/src/gobj/shader.h +++ b/panda/src/gobj/shader.h @@ -202,6 +202,17 @@ public: // Hack for text rendering. Don't use in user shaders. SMO_tex_is_alpha_i, + SMO_transform_i, + SMO_slider_i, + + SMO_light_source_i_packed, + + // Texture scale component of texture matrix. + SMO_texscale_i, + + // Color of an M_blend texture stage. + SMO_texcolor_i, + SMO_INVALID }; diff --git a/panda/src/pgraph/alphaTestAttrib.cxx b/panda/src/pgraph/alphaTestAttrib.cxx index 8d31c57b12..a302026623 100644 --- a/panda/src/pgraph/alphaTestAttrib.cxx +++ b/panda/src/pgraph/alphaTestAttrib.cxx @@ -94,22 +94,6 @@ get_hash_impl() const { return hash; } -/** - * - */ -CPT(RenderAttrib) AlphaTestAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - // This is only important if the shader subsumes the alpha test, which only - // happens if there is an AuxBitplaneAttrib with ABO_glow. - const AuxBitplaneAttrib *aux; - if (!state->get_attrib(aux) || - (aux->get_outputs() & AuxBitplaneAttrib::ABO_glow) == 0) { - return nullptr; - } else { - return this; - } -} - /** * Tells the BamReader how to create objects of type AlphaTestAttrib. */ diff --git a/panda/src/pgraph/alphaTestAttrib.h b/panda/src/pgraph/alphaTestAttrib.h index 5c38727347..9b547ad2a7 100644 --- a/panda/src/pgraph/alphaTestAttrib.h +++ b/panda/src/pgraph/alphaTestAttrib.h @@ -46,7 +46,6 @@ public: protected: virtual int compare_to_impl(const RenderAttrib *other) const; virtual size_t get_hash_impl() const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: PandaCompareFunc _mode; diff --git a/panda/src/pgraph/auxBitplaneAttrib.cxx b/panda/src/pgraph/auxBitplaneAttrib.cxx index 1d8a5b3095..8f8e2d8a9f 100644 --- a/panda/src/pgraph/auxBitplaneAttrib.cxx +++ b/panda/src/pgraph/auxBitplaneAttrib.cxx @@ -97,14 +97,6 @@ get_hash_impl() const { return hash; } -/** - * - */ -CPT(RenderAttrib) AuxBitplaneAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - return this; -} - /** * Tells the BamReader how to create objects of type AuxBitplaneAttrib. */ diff --git a/panda/src/pgraph/auxBitplaneAttrib.h b/panda/src/pgraph/auxBitplaneAttrib.h index 4c5866c49c..56658f0aa2 100644 --- a/panda/src/pgraph/auxBitplaneAttrib.h +++ b/panda/src/pgraph/auxBitplaneAttrib.h @@ -72,7 +72,6 @@ public: protected: virtual int compare_to_impl(const RenderAttrib *other) const; virtual size_t get_hash_impl() const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: int _outputs; diff --git a/panda/src/pgraph/clipPlaneAttrib.cxx b/panda/src/pgraph/clipPlaneAttrib.cxx index c95f9437c4..102ddf6ad3 100644 --- a/panda/src/pgraph/clipPlaneAttrib.cxx +++ b/panda/src/pgraph/clipPlaneAttrib.cxx @@ -833,14 +833,6 @@ invert_compose_impl(const RenderAttrib *other) const { return other; } -/** - * - */ -CPT(RenderAttrib) ClipPlaneAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - return this; -} - /** * This is patterned after TextureAttrib::sort_on_stages(), but since * planeNodes don't actually require sorting, this only empties the _filtered diff --git a/panda/src/pgraph/clipPlaneAttrib.h b/panda/src/pgraph/clipPlaneAttrib.h index c695e0391d..e62c57857a 100644 --- a/panda/src/pgraph/clipPlaneAttrib.h +++ b/panda/src/pgraph/clipPlaneAttrib.h @@ -98,7 +98,6 @@ protected: virtual size_t get_hash_impl() const; virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const; virtual CPT(RenderAttrib) invert_compose_impl(const RenderAttrib *other) const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: INLINE void check_filtered() const; diff --git a/panda/src/pgraph/colorAttrib.cxx b/panda/src/pgraph/colorAttrib.cxx index 7e007851fb..42e7c5578d 100644 --- a/panda/src/pgraph/colorAttrib.cxx +++ b/panda/src/pgraph/colorAttrib.cxx @@ -132,19 +132,6 @@ get_hash_impl() const { return hash; } -/** - * - */ -CPT(RenderAttrib) ColorAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - // For a ColorAttrib, the only relevant information is the type: is it flat- - // shaded or vertex-shaded? The actual color value is read by the shader - // from the graphics state. - - ColorAttrib *attrib = new ColorAttrib(_type, LColor(1.0f, 1.0f, 1.0f, 1.0f)); - return return_new(attrib); -} - /** * Quantizes the color color to the nearest multiple of 1000, just to prevent * runaway accumulation of only slightly-different ColorAttribs. diff --git a/panda/src/pgraph/colorAttrib.h b/panda/src/pgraph/colorAttrib.h index 54b57b8abb..9df0878559 100644 --- a/panda/src/pgraph/colorAttrib.h +++ b/panda/src/pgraph/colorAttrib.h @@ -52,7 +52,6 @@ public: protected: virtual int compare_to_impl(const RenderAttrib *other) const; virtual size_t get_hash_impl() const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: void quantize_color(); diff --git a/panda/src/pgraph/colorBlendAttrib.cxx b/panda/src/pgraph/colorBlendAttrib.cxx index 92fe98ab79..9341f2d808 100644 --- a/panda/src/pgraph/colorBlendAttrib.cxx +++ b/panda/src/pgraph/colorBlendAttrib.cxx @@ -148,14 +148,6 @@ get_hash_impl() const { return hash; } -/** - * - */ -CPT(RenderAttrib) ColorBlendAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - return this; -} - /** * Tells the BamReader how to create objects of type ColorBlendAttrib. */ diff --git a/panda/src/pgraph/colorBlendAttrib.h b/panda/src/pgraph/colorBlendAttrib.h index 6d66747218..0530d077ce 100644 --- a/panda/src/pgraph/colorBlendAttrib.h +++ b/panda/src/pgraph/colorBlendAttrib.h @@ -121,7 +121,6 @@ public: protected: virtual int compare_to_impl(const RenderAttrib *other) const; virtual size_t get_hash_impl() const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: Mode _mode; diff --git a/panda/src/pgraph/colorScaleAttrib.cxx b/panda/src/pgraph/colorScaleAttrib.cxx index 0975757604..79394a51f1 100644 --- a/panda/src/pgraph/colorScaleAttrib.cxx +++ b/panda/src/pgraph/colorScaleAttrib.cxx @@ -229,17 +229,6 @@ invert_compose_impl(const RenderAttrib *other) const { return return_new(attrib); } -/** - * - */ -CPT(RenderAttrib) ColorScaleAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - // A ColorScaleAttrib doesn't directly contribute to the auto-shader - // contents--instead, the shader is always written to query attr_colorscale - // at runtime. So the attrib itself means nothing to the shader. - return NULL; -} - /** * Quantizes the color scale to the nearest multiple of 1000, just to prevent * runaway accumulation of only slightly-different ColorScaleAttribs. diff --git a/panda/src/pgraph/colorScaleAttrib.h b/panda/src/pgraph/colorScaleAttrib.h index aa3ace8738..b5e986e239 100644 --- a/panda/src/pgraph/colorScaleAttrib.h +++ b/panda/src/pgraph/colorScaleAttrib.h @@ -55,7 +55,6 @@ protected: virtual size_t get_hash_impl() const; virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const; virtual CPT(RenderAttrib) invert_compose_impl(const RenderAttrib *other) const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: void quantize_scale(); diff --git a/panda/src/pgraph/cullableObject.cxx b/panda/src/pgraph/cullableObject.cxx index 3d18dc6748..0630513696 100644 --- a/panda/src/pgraph/cullableObject.cxx +++ b/panda/src/pgraph/cullableObject.cxx @@ -34,6 +34,7 @@ CullableObject::FormatMap CullableObject::_format_map; LightMutex CullableObject::_format_lock; +PStatCollector CullableObject::_munge_pcollector("*:Munge"); PStatCollector CullableObject::_munge_geom_pcollector("*:Munge:Geom"); PStatCollector CullableObject::_munge_sprites_pcollector("*:Munge:Sprites"); PStatCollector CullableObject::_munge_sprites_verts_pcollector("*:Munge:Sprites:Verts"); @@ -55,7 +56,7 @@ munge_geom(GraphicsStateGuardianBase *gsg, GeomMunger *munger, nassertr(munger != nullptr, false); Thread *current_thread = traverser->get_current_thread(); - PStatTimer timer(_munge_geom_pcollector, current_thread); + PStatTimer timer(_munge_pcollector, current_thread); if (_geom != nullptr) { GraphicsStateGuardianBase *gsg = traverser->get_gsg(); int gsg_bits = gsg->get_supported_geom_rendering(); @@ -123,8 +124,11 @@ munge_geom(GraphicsStateGuardianBase *gsg, GeomMunger *munger, // Now invoke the munger to ensure the resulting geometry is in a GSG- // friendly form. - if (!munger->munge_geom(_geom, _munged_data, force, current_thread)) { - return false; + { + PStatTimer timer(_munge_geom_pcollector, current_thread); + if (!munger->munge_geom(_geom, _munged_data, force, current_thread)) { + return false; + } } // If we have prepared it for skinning via the shader generator, mark a diff --git a/panda/src/pgraph/cullableObject.h b/panda/src/pgraph/cullableObject.h index a8595da9f5..b02d7c79be 100644 --- a/panda/src/pgraph/cullableObject.h +++ b/panda/src/pgraph/cullableObject.h @@ -108,6 +108,7 @@ private: static FormatMap _format_map; static LightMutex _format_lock; + static PStatCollector _munge_pcollector; static PStatCollector _munge_geom_pcollector; static PStatCollector _munge_sprites_pcollector; static PStatCollector _munge_sprites_verts_pcollector; diff --git a/panda/src/pgraph/fogAttrib.cxx b/panda/src/pgraph/fogAttrib.cxx index 0606298fa4..87e12086d4 100644 --- a/panda/src/pgraph/fogAttrib.cxx +++ b/panda/src/pgraph/fogAttrib.cxx @@ -100,14 +100,6 @@ get_hash_impl() const { return hash; } -/** - * - */ -CPT(RenderAttrib) FogAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - return this; -} - /** * Tells the BamReader how to create objects of type FogAttrib. */ diff --git a/panda/src/pgraph/fogAttrib.h b/panda/src/pgraph/fogAttrib.h index 28a84600e0..0076ccfc82 100644 --- a/panda/src/pgraph/fogAttrib.h +++ b/panda/src/pgraph/fogAttrib.h @@ -43,7 +43,6 @@ public: protected: virtual int compare_to_impl(const RenderAttrib *other) const; virtual size_t get_hash_impl() const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: PT(Fog) _fog; diff --git a/panda/src/pgraph/lightAttrib.cxx b/panda/src/pgraph/lightAttrib.cxx index 2fb58c106d..21b5150dcc 100644 --- a/panda/src/pgraph/lightAttrib.cxx +++ b/panda/src/pgraph/lightAttrib.cxx @@ -850,14 +850,6 @@ invert_compose_impl(const RenderAttrib *other) const { return other; } -/** - * - */ -CPT(RenderAttrib) LightAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - return this; -} - /** * Makes sure the lights are sorted in order of priority. Also counts the * number of non-ambient lights. diff --git a/panda/src/pgraph/lightAttrib.h b/panda/src/pgraph/lightAttrib.h index eaa86ff895..25fc1fa68a 100644 --- a/panda/src/pgraph/lightAttrib.h +++ b/panda/src/pgraph/lightAttrib.h @@ -103,7 +103,6 @@ protected: virtual size_t get_hash_impl() const; virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const; virtual CPT(RenderAttrib) invert_compose_impl(const RenderAttrib *other) const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: INLINE void check_sorted() const; diff --git a/panda/src/pgraph/lightRampAttrib.cxx b/panda/src/pgraph/lightRampAttrib.cxx index 38ed81affe..7a7637a35f 100644 --- a/panda/src/pgraph/lightRampAttrib.cxx +++ b/panda/src/pgraph/lightRampAttrib.cxx @@ -254,14 +254,6 @@ get_hash_impl() const { return hash; } -/** - * - */ -CPT(RenderAttrib) LightRampAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - return this; -} - /** * Tells the BamReader how to create objects of type LightRampAttrib. */ diff --git a/panda/src/pgraph/lightRampAttrib.h b/panda/src/pgraph/lightRampAttrib.h index b1ac147376..ccba3501cd 100644 --- a/panda/src/pgraph/lightRampAttrib.h +++ b/panda/src/pgraph/lightRampAttrib.h @@ -61,7 +61,6 @@ public: protected: virtual int compare_to_impl(const RenderAttrib *other) const; virtual size_t get_hash_impl() const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: LightRampMode _mode; diff --git a/panda/src/pgraph/logicOpAttrib.cxx b/panda/src/pgraph/logicOpAttrib.cxx index b632bb1b45..28381dfc5b 100644 --- a/panda/src/pgraph/logicOpAttrib.cxx +++ b/panda/src/pgraph/logicOpAttrib.cxx @@ -88,14 +88,6 @@ get_hash_impl() const { return hash; } -/** - * - */ -CPT(RenderAttrib) LogicOpAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - return RenderAttribRegistry::quick_get_global_ptr()->get_slot_default(_attrib_slot); -} - /** * Tells the BamReader how to create objects of type LogicOpAttrib. */ diff --git a/panda/src/pgraph/logicOpAttrib.h b/panda/src/pgraph/logicOpAttrib.h index 988836f8d1..81621b51dc 100644 --- a/panda/src/pgraph/logicOpAttrib.h +++ b/panda/src/pgraph/logicOpAttrib.h @@ -64,7 +64,6 @@ public: protected: virtual int compare_to_impl(const RenderAttrib *other) const; virtual size_t get_hash_impl() const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: Operation _op; diff --git a/panda/src/pgraph/materialAttrib.I b/panda/src/pgraph/materialAttrib.I index 3cb7f9e6be..d0cfc1ad14 100644 --- a/panda/src/pgraph/materialAttrib.I +++ b/panda/src/pgraph/materialAttrib.I @@ -15,7 +15,7 @@ * Use MaterialAttrib::make() to construct a new MaterialAttrib object. */ INLINE MaterialAttrib:: -MaterialAttrib() : _flags(0) { +MaterialAttrib() { } /** @@ -24,7 +24,7 @@ MaterialAttrib() : _flags(0) { */ INLINE bool MaterialAttrib:: is_off() const { - return _flags == 0; + return _material == nullptr; } /** @@ -35,11 +35,3 @@ INLINE Material *MaterialAttrib:: get_material() const { return _material; } - -/** - * Equivalent to get_material()->get_flags(). - */ -INLINE int MaterialAttrib:: -get_material_flags() const { - return _flags; -} diff --git a/panda/src/pgraph/materialAttrib.cxx b/panda/src/pgraph/materialAttrib.cxx index d8eee605d7..baeac4dc38 100644 --- a/panda/src/pgraph/materialAttrib.cxx +++ b/panda/src/pgraph/materialAttrib.cxx @@ -30,8 +30,6 @@ make(Material *material) { MaterialAttrib *attrib = new MaterialAttrib; attrib->_material = material; material->set_attrib_lock(); - attrib->_flags = material->_flags; - nassertr(attrib->_flags & Material::F_attrib_lock, nullptr); return return_new(attrib); } @@ -64,30 +62,6 @@ output(ostream &out) const { out << *_material; } else if (is_off()) { out << "(off)"; - } else { - // This is a state returned from get_auto_shader_attrib(). - out << "(on"; -#ifndef NDEBUG - if (_flags & Material::F_ambient) { - out << " amb"; - } - if (_flags & Material::F_diffuse) { - out << " diff"; - } - if (_flags & Material::F_specular) { - out << " spec"; - } - if (_flags & Material::F_emission) { - out << " emit"; - } - if (_flags & Material::F_local) { - out << " local"; - } - if (_flags & Material::F_twoside) { - out << " twoside"; - } -#endif - out << ")"; } } @@ -113,7 +87,7 @@ compare_to_impl(const RenderAttrib *other) const { if (_material != ta->_material) { return _material < ta->_material ? -1 : 1; } - return _flags < ta->_flags; + return 0; } /** @@ -124,26 +98,7 @@ compare_to_impl(const RenderAttrib *other) const { */ size_t MaterialAttrib:: get_hash_impl() const { - size_t hash = 0; - hash = pointer_hash::add_hash(hash, _material); - hash = int_hash::add_hash(hash, _flags); - return hash; -} - -/** - * - */ -CPT(RenderAttrib) MaterialAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - if (_material == nullptr) { - return this; - } else { - // Make a copy, but only with the flags, not with the material itself. - MaterialAttrib *attrib = new MaterialAttrib(); - attrib->_material = nullptr; - attrib->_flags = _flags; - return return_new(attrib); - } + return pointer_hash::add_hash(0, _material); } /** @@ -174,13 +129,7 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) { int pi = RenderAttrib::complete_pointers(p_list, manager); TypedWritable *material = p_list[pi++]; - if (material != nullptr) { - _material = DCAST(Material, material); - _flags = _material->_flags | Material::F_attrib_lock; - } else { - _material = nullptr; - _flags = 0; - } + _material = DCAST(Material, material); return pi; } diff --git a/panda/src/pgraph/materialAttrib.h b/panda/src/pgraph/materialAttrib.h index 28bd90f8bd..8da67c3ada 100644 --- a/panda/src/pgraph/materialAttrib.h +++ b/panda/src/pgraph/materialAttrib.h @@ -36,9 +36,6 @@ PUBLISHED: INLINE bool is_off() const; INLINE Material *get_material() const; -public: - INLINE int get_material_flags() const; - PUBLISHED: MAKE_PROPERTY(material, get_material); @@ -48,11 +45,9 @@ public: protected: virtual int compare_to_impl(const RenderAttrib *other) const; virtual size_t get_hash_impl() const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: PT(Material) _material; - int _flags; PUBLISHED: static int get_class_slot() { diff --git a/panda/src/pgraph/renderAttrib.I b/panda/src/pgraph/renderAttrib.I index 9e431d7d6a..5df0d0774e 100644 --- a/panda/src/pgraph/renderAttrib.I +++ b/panda/src/pgraph/renderAttrib.I @@ -82,25 +82,6 @@ get_unique() const { return return_unique((RenderAttrib *)this); } -/** - * Returns the variant of this RenderAttrib that's most relevant for - * associating with an auto-generated shader. This should be a new - * RenderAttrib of the same type as this one, with any superfluous data set to - * neutral. Only the parts of the attrib that contribute to the shader should - * be reflected in the returned attrib. The idea is to associate the auto- - * generated shader with the most neutral form of all states, to allow it to - * be shared across as many RenderState objects as possible. - * - * If this RenderAttrib is completely irrelevant to the auto-shader, this - * should return NULL to indicate that the attrib won't be assocaited with the - * shader at all. In this case the attrib does not contribute to the shader - * meaningfully. - */ -INLINE CPT(RenderAttrib) RenderAttrib:: -get_auto_shader_attrib(const RenderState *state) const { - return get_auto_shader_attrib_impl(state); -} - /** * Calculates a suitable hash value for phash_map. */ diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index 10db3de16d..37b65f3b2a 100644 --- a/panda/src/pgraph/renderAttrib.cxx +++ b/panda/src/pgraph/renderAttrib.cxx @@ -112,14 +112,6 @@ cull_callback(CullTraverser *, const CullTraverserData &) const { return true; } -/** - * - */ -CPT(RenderAttrib) RenderAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - return NULL; -} - /** * This method overrides ReferenceCount::unref() to clear the pointer from the * global object pool when its reference count goes to zero. diff --git a/panda/src/pgraph/renderAttrib.h b/panda/src/pgraph/renderAttrib.h index 9d6ed83a1a..1ffda64a16 100644 --- a/panda/src/pgraph/renderAttrib.h +++ b/panda/src/pgraph/renderAttrib.h @@ -71,7 +71,6 @@ PUBLISHED: INLINE int compare_to(const RenderAttrib &other) const; INLINE size_t get_hash() const; INLINE CPT(RenderAttrib) get_unique() const; - INLINE CPT(RenderAttrib) get_auto_shader_attrib(const RenderState *state) const; virtual bool unref() const FINAL; @@ -170,7 +169,6 @@ protected: virtual size_t get_hash_impl() const; virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const; virtual CPT(RenderAttrib) invert_compose_impl(const RenderAttrib *other) const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; void output_comparefunc(ostream &out, PandaCompareFunc fn) const; public: diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index 43a81bf83e..ee53a7d4a4 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -64,7 +64,6 @@ TypeHandle RenderState::_type_handle; RenderState:: RenderState() : _flags(0), - _auto_shader_state(NULL), _lock("RenderState") { if (_states == (States *)NULL) { @@ -88,7 +87,6 @@ RenderState:: RenderState(const RenderState ©) : _filled_slots(copy._filled_slots), _flags(0), - _auto_shader_state(NULL), _lock("RenderState") { // Copy over the attributes. @@ -131,14 +129,6 @@ RenderState:: nassertv(_saved_entry == -1); nassertv(_composition_cache.is_empty() && _invert_composition_cache.is_empty()); - // Make sure the _auto_shader_state cache pointer is cleared. - if (_auto_shader_state != (const RenderState *)NULL) { - if (_auto_shader_state != this) { - cache_unref_delete(_auto_shader_state); - } - _auto_shader_state = NULL; - } - // If this was true at the beginning of the destructor, but is no longer // true now, probably we've been double-deleted. nassertv(get_ref_count() == 0); @@ -665,24 +655,6 @@ unref() const { return false; } -/** - * Returns the base RenderState that should have the generated_shader stored - * within it, for generated shader states. The returned object might be the - * same as this object, or it might be a different RenderState with certain - * attributes removed, or set to their default values. - * - * The point is to avoid needless regeneration of the shader attrib by storing - * the generated shader on a common RenderState object, with all irrelevant - * attributes removed. - */ -const RenderState *RenderState:: -get_auto_shader_state() const { - if (_auto_shader_state == (const RenderState *)NULL) { - ((RenderState *)this)->assign_auto_shader_state(); - } - return _auto_shader_state; -} - /** * */ @@ -1259,54 +1231,6 @@ do_calc_hash() { _flags |= F_hash_known; } -/** - * Sets _auto_shader_state to the appropriate RenderState object pointer, - * either the same pointer as this object, or some other (simpler) - * RenderState. - */ -void RenderState:: -assign_auto_shader_state() { - CPT(RenderState) state = do_calc_auto_shader_state(); - - { - LightReMutexHolder holder(*_states_lock); - if (_auto_shader_state == (const RenderState *)NULL) { - _auto_shader_state = state; - if (_auto_shader_state != this) { - _auto_shader_state->cache_ref(); - } - } - } -} - -/** - * Returns the appropriate RenderState that should be used to store the auto - * shader pointer for nodes that shader this RenderState. - */ -CPT(RenderState) RenderState:: -do_calc_auto_shader_state() { - RenderState *state = new RenderState; - - SlotMask mask = _filled_slots; - int slot = mask.get_lowest_on_bit(); - while (slot >= 0) { - const Attribute &attrib = _attributes[slot]; - nassertr(attrib._attrib != (RenderAttrib *)NULL, this); - CPT(RenderAttrib) new_attrib = attrib._attrib->get_auto_shader_attrib(this); - if (new_attrib != NULL) { - nassertr(new_attrib->get_slot() == slot, this); - state->_attributes[slot].set(new_attrib, 0); - state->_filled_slots.set_bit(slot); - } - - mask.clear_bit(slot); - slot = mask.get_lowest_on_bit(); - } - - return return_new(state); -} - - /** * This function is used to share a common RenderState pointer for all * equivalent RenderState objects. @@ -1705,14 +1629,6 @@ void RenderState:: remove_cache_pointers() { nassertv(_states_lock->debug_is_locked()); - // First, make sure the _auto_shader_state cache pointer is cleared. - if (_auto_shader_state != (const RenderState *)NULL) { - if (_auto_shader_state != this) { - cache_unref_delete(_auto_shader_state); - } - _auto_shader_state = NULL; - } - // Fortunately, since we added CompositionCache records in pairs, we know // exactly the set of RenderState objects that have us in their cache: it's // the same set of RenderState objects that we have in our own cache. diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index a1b1813ea9..0cdcca07a1 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -130,8 +130,6 @@ PUBLISHED: EXTENSION(PyObject *get_composition_cache() const); EXTENSION(PyObject *get_invert_composition_cache() const); - const RenderState *get_auto_shader_state() const; - void output(ostream &out) const; void write(ostream &out, int indent_level) const; @@ -173,8 +171,6 @@ private: INLINE bool do_node_unref() const; INLINE void calc_hash(); void do_calc_hash(); - void assign_auto_shader_state(); - CPT(RenderState) do_calc_auto_shader_state(); class CompositionCycleDescEntry { public: @@ -317,8 +313,6 @@ private: int _draw_order; size_t _hash; - const RenderState *_auto_shader_state; - enum Flags { F_checked_bin_index = 0x000001, F_checked_cull_callback = 0x000002, diff --git a/panda/src/pgraph/rescaleNormalAttrib.cxx b/panda/src/pgraph/rescaleNormalAttrib.cxx index e9d081e43c..fbc4d59274 100644 --- a/panda/src/pgraph/rescaleNormalAttrib.cxx +++ b/panda/src/pgraph/rescaleNormalAttrib.cxx @@ -80,22 +80,6 @@ get_hash_impl() const { return hash; } -/** - * - */ -CPT(RenderAttrib) RescaleNormalAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - // We currently only support M_normalize in the ShaderGenerator. - /*if (_mode == M_none || _mode == M_normalize) { - return this; - } else { - return RescaleNormalAttrib::make(M_normalize); - }*/ - // Actually, we currently ignore this attribute in the shader generator, - // and always normalize the normals. It's too much of a bother. - return nullptr; -} - /** * Tells the BamReader how to create objects of type RescaleNormalAttrib. */ diff --git a/panda/src/pgraph/rescaleNormalAttrib.h b/panda/src/pgraph/rescaleNormalAttrib.h index d76d51e6de..746db42717 100644 --- a/panda/src/pgraph/rescaleNormalAttrib.h +++ b/panda/src/pgraph/rescaleNormalAttrib.h @@ -57,7 +57,6 @@ public: protected: virtual int compare_to_impl(const RenderAttrib *other) const; virtual size_t get_hash_impl() const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: Mode _mode; diff --git a/panda/src/pgraph/shaderAttrib.cxx b/panda/src/pgraph/shaderAttrib.cxx index 04d6196aa2..67bba2d196 100644 --- a/panda/src/pgraph/shaderAttrib.cxx +++ b/panda/src/pgraph/shaderAttrib.cxx @@ -695,26 +695,6 @@ compose_impl(const RenderAttrib *other) const { return return_new(attr); } -/** - * - */ -CPT(RenderAttrib) ShaderAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - // For a ShaderAttrib, we only need to preserve the auto-shader flags. - // Custom shaders, and custom shader inputs, aren't relevant to the shader - // generator. - ShaderAttrib *attrib = new ShaderAttrib; - attrib->_auto_shader = _auto_shader; - attrib->_has_shader = _has_shader; - attrib->_auto_normal_on = _auto_normal_on; - attrib->_auto_glow_on = _auto_glow_on; - attrib->_auto_gloss_on = _auto_gloss_on; - attrib->_auto_ramp_on = _auto_ramp_on; - attrib->_auto_shadow_on = _auto_shadow_on; - attrib->_flags = _flags; - return return_new(attrib); -} - /** * Factory method to generate a Shader object */ diff --git a/panda/src/pgraph/shaderAttrib.h b/panda/src/pgraph/shaderAttrib.h index 719106c0b6..c719ce1791 100644 --- a/panda/src/pgraph/shaderAttrib.h +++ b/panda/src/pgraph/shaderAttrib.h @@ -127,7 +127,6 @@ protected: virtual int compare_to_impl(const RenderAttrib *other) const; virtual size_t get_hash_impl() const; virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: diff --git a/panda/src/pgraph/texGenAttrib.cxx b/panda/src/pgraph/texGenAttrib.cxx index c7ace978c0..451eacab83 100644 --- a/panda/src/pgraph/texGenAttrib.cxx +++ b/panda/src/pgraph/texGenAttrib.cxx @@ -432,14 +432,6 @@ invert_compose_impl(const RenderAttrib *other) const { return return_new(attrib); } -/** - * - */ -CPT(RenderAttrib) TexGenAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - return this; -} - /** * This method is to be called after the _stages map has been built up * internally through some artificial means; it copies the appropriate diff --git a/panda/src/pgraph/texGenAttrib.h b/panda/src/pgraph/texGenAttrib.h index c2b0e87132..3cf0323edc 100644 --- a/panda/src/pgraph/texGenAttrib.h +++ b/panda/src/pgraph/texGenAttrib.h @@ -68,7 +68,6 @@ protected: virtual size_t get_hash_impl() const; virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const; virtual CPT(RenderAttrib) invert_compose_impl(const RenderAttrib *other) const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: class ModeDef; diff --git a/panda/src/pgraph/texMatrixAttrib.cxx b/panda/src/pgraph/texMatrixAttrib.cxx index 84538033fd..4e2e1adba8 100644 --- a/panda/src/pgraph/texMatrixAttrib.cxx +++ b/panda/src/pgraph/texMatrixAttrib.cxx @@ -415,28 +415,6 @@ invert_compose_impl(const RenderAttrib *other) const { return return_new(attrib); } -/** - * - */ -CPT(RenderAttrib) TexMatrixAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - // For a TexMatrixAttrib, the particular matrix per TextureStage isn't - // important, just whether there is a matrix at all. So we create a new - // state with an identity matrix everywhere there is a matrix at all in the - // original. - - TexMatrixAttrib *attrib = new TexMatrixAttrib; - - Stages::const_iterator ai; - for (ai = _stages.begin(); ai != _stages.end(); ++ai) { - StageNode sn((*ai)._stage); - sn._transform = TransformState::make_identity(); - attrib->_stages.insert(attrib->_stages.end(), sn); - } - - return return_new(attrib); -} - /** * Tells the BamReader how to create objects of type TexMatrixAttrib. */ diff --git a/panda/src/pgraph/texMatrixAttrib.h b/panda/src/pgraph/texMatrixAttrib.h index b0b7790851..36e06b1549 100644 --- a/panda/src/pgraph/texMatrixAttrib.h +++ b/panda/src/pgraph/texMatrixAttrib.h @@ -67,7 +67,6 @@ protected: virtual size_t get_hash_impl() const; virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const; virtual CPT(RenderAttrib) invert_compose_impl(const RenderAttrib *other) const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: INLINE void check_stage_list() const; diff --git a/panda/src/pgraph/textureAttrib.I b/panda/src/pgraph/textureAttrib.I index 6649c8d87a..da1feca0be 100644 --- a/panda/src/pgraph/textureAttrib.I +++ b/panda/src/pgraph/textureAttrib.I @@ -140,26 +140,6 @@ get_on_texture(TextureStage *stage) const { return NULL; } -/** - * Returns the type of the texture associated with the indicated stage. It is - * an error to call this if has_on_stage(stage) returns false. - * - * This method is no different than get_on_texture(stage)->get_texture_type(); - * it merely exists to address a corner case for the shader generator. - */ -INLINE Texture::TextureType TextureAttrib:: -get_on_texture_type(TextureStage *stage) const { - Stages::const_iterator si; - si = _on_stages.find(StageNode(stage)); - nassertr(si != _on_stages.end(), Texture::TT_2d_texture); - - if ((*si)._texture == nullptr) { - return (*si)._texture_type; - } else { - return (*si)._texture->get_texture_type(); - } -} - /** * Returns the sampler associated with the indicated stage, or the one * associated with its texture if no custom stage has been specified. It is @@ -235,26 +215,6 @@ is_identity() const { return _on_stages.empty() && _off_stages.empty() && !_off_all_stages; } -/** - * Call only on a state returned by get_auto_shader_attrib. - */ -bool TextureAttrib:: -on_stage_affects_rgb(size_t n) const { - nassertr(n < _render_stages.size(), false); - StageNode *stage = _render_stages[n]; - return stage->_texture_affects_rgb; -} - -/** - * Call only on a state returned by get_auto_shader_attrib. - */ -bool TextureAttrib:: -on_stage_affects_alpha(size_t n) const { - nassertr(n < _render_stages.size(), false); - StageNode *stage = _render_stages[n]; - return stage->_texture_affects_alpha; -} - /** * Confirms whether the _on_stages list is still sorted. It will become * unsorted if someone calls TextureStage::set_sort(). @@ -263,7 +223,7 @@ on_stage_affects_alpha(size_t n) const { */ INLINE void TextureAttrib:: check_sorted() const { - if (_sort_seq != TextureStage::get_sort_seq() && !_sort_seq.is_fresh()) { + if (_sort_seq != TextureStage::get_sort_seq()) { ((TextureAttrib *)this)->sort_on_stages(); } } diff --git a/panda/src/pgraph/textureAttrib.cxx b/panda/src/pgraph/textureAttrib.cxx index 8c1b4833ff..9b30906e1f 100644 --- a/panda/src/pgraph/textureAttrib.cxx +++ b/panda/src/pgraph/textureAttrib.cxx @@ -385,19 +385,9 @@ output(ostream &out) const { const StageNode &sn = *(*ri); TextureStage *stage = sn._stage; Texture *tex = sn._texture; + out << " " << stage->get_name(); if (tex != nullptr) { - out << " " << stage->get_name() << ":" << tex->get_name(); - } else { - out << " " << stage->get_name() << ":(" << sn._texture_type; - if (sn._texture_affects_rgb) { - out << " rgb"; - if (sn._texture_affects_alpha) { - out << "a"; - } - } else if (sn._texture_affects_alpha) { - out << " alpha"; - } - out << ")"; + out << ":" << tex->get_name(); } if (sn._override != 0) { out << "^" << sn._override; @@ -513,19 +503,6 @@ compare_to_impl(const RenderAttrib *other) const { } } - if (texture == nullptr) { - // This is an attribute returned by get_auto_shader_attrib_impl. - if ((*si)._texture_type != (*osi)._texture_type) { - return (*si)._texture_type < (*osi)._texture_type ? -1 : 1; - } - if ((*si)._texture_affects_rgb != (*osi)._texture_affects_rgb) { - return (*si)._texture_affects_rgb < (*osi)._texture_affects_rgb ? -1 : 1; - } - if ((*si)._texture_affects_alpha != (*osi)._texture_affects_alpha) { - return (*si)._texture_affects_alpha < (*osi)._texture_affects_alpha ? -1 : 1; - } - } - ++si; ++osi; } @@ -589,13 +566,6 @@ get_hash_impl() const { hash = pointer_hash::add_hash(hash, sn._texture); hash = int_hash::add_hash(hash, (int)sn._implicit_sort); hash = int_hash::add_hash(hash, sn._override); - - if (sn._texture == nullptr) { - // This is an attribute returned by get_auto_shader_attrib_impl. - hash = int_hash::add_hash(hash, (int)sn._texture_type); - hash = int_hash::add_hash(hash, (int)sn._texture_affects_rgb); - hash = int_hash::add_hash(hash, (int)sn._texture_affects_alpha); - } } // This bool value goes here, between the two lists, to differentiate @@ -767,52 +737,6 @@ invert_compose_impl(const RenderAttrib *other) const { return other; } -/** - * - */ -CPT(RenderAttrib) TextureAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - if (_on_stages.empty()) { - // Having no stages is the same as not applying a texture attribute. - return nullptr; - } - - // We make a texture attribute that does not store the texture and sampler, - // so that we don't have to generate a shader for every possible texture. - // We do have to store the few texture properties that do affect the - // generated shader. - PT(TextureAttrib) attrib = new TextureAttrib; - attrib->_on_stages = _on_stages; - attrib->sort_on_stages(); - - Stages::iterator si; - for (si = attrib->_on_stages.begin(); si != attrib->_on_stages.end(); ++si) { - Texture::Format format = (*si)._texture->get_format(); - (*si)._texture_type = (*si)._texture->get_texture_type(); - (*si)._texture_affects_rgb = (format != Texture::F_alpha); - (*si)._texture_affects_alpha = Texture::has_alpha(format); - (*si)._texture = nullptr; - (*si)._has_sampler = false; - - // We will no longer be composing or sorting this state so we can get rid - // of these values. - (*si)._override = 0; - (*si)._implicit_sort = 0; - - // Exception to optimize a common case: if the first texture is an RGB - // texture, we don't care about whether it affects the alpha channel. - if (attrib->_render_stages[0] == &(*si) && - (*si)._texture_affects_rgb && !(*si)._texture_affects_alpha) { - (*si)._texture_affects_alpha = true; - } - } - - // Prevent check_sorted() from being called on this state. - attrib->_sort_seq = UpdateSeq::fresh(); - - return return_new(attrib); -} - /** * Tells the BamReader how to create objects of type TextureAttrib. */ diff --git a/panda/src/pgraph/textureAttrib.h b/panda/src/pgraph/textureAttrib.h index 9f1c13e3c8..efb1ad786d 100644 --- a/panda/src/pgraph/textureAttrib.h +++ b/panda/src/pgraph/textureAttrib.h @@ -59,7 +59,6 @@ PUBLISHED: INLINE int get_ff_tc_index(int n) const; INLINE bool has_on_stage(TextureStage *stage) const; INLINE Texture *get_on_texture(TextureStage *stage) const; - INLINE Texture::TextureType get_on_texture_type(TextureStage *stage) const; INLINE const SamplerState &get_on_sampler(TextureStage *stage) const; INLINE int get_on_stage_override(TextureStage *stage) const; @@ -82,8 +81,6 @@ PUBLISHED: CPT(RenderAttrib) unify_texture_stages(TextureStage *stage) const; public: - INLINE bool on_stage_affects_rgb(size_t n) const; - INLINE bool on_stage_affects_alpha(size_t n) const; CPT(TextureAttrib) filter_to_max(int max_texture_stages) const; virtual bool lower_attrib_can_override() const; @@ -97,7 +94,6 @@ protected: virtual size_t get_hash_impl() const; virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const; virtual CPT(RenderAttrib) invert_compose_impl(const RenderAttrib *other) const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: INLINE void check_sorted() const; @@ -117,11 +113,6 @@ private: int _ff_tc_index; unsigned int _implicit_sort; int _override; - - // These fields are used by the shader generator. - Texture::TextureType _texture_type : 16; - bool _texture_affects_rgb : 8; - bool _texture_affects_alpha : 8; }; class CompareTextureStagePriorities { diff --git a/panda/src/pgraph/transparencyAttrib.cxx b/panda/src/pgraph/transparencyAttrib.cxx index d998004f09..ad105f3214 100644 --- a/panda/src/pgraph/transparencyAttrib.cxx +++ b/panda/src/pgraph/transparencyAttrib.cxx @@ -109,21 +109,6 @@ get_hash_impl() const { return hash; } -/** - * - */ -CPT(RenderAttrib) TransparencyAttrib:: -get_auto_shader_attrib_impl(const RenderState *state) const { - if (_mode == TransparencyAttrib::M_alpha) { - return this; - } else if (_mode == TransparencyAttrib::M_premultiplied_alpha || - _mode == TransparencyAttrib::M_dual) { - return return_new(new TransparencyAttrib(M_alpha)); - } else { - return nullptr; - } -} - /** * Tells the BamReader how to create objects of type TransparencyAttrib. */ diff --git a/panda/src/pgraph/transparencyAttrib.h b/panda/src/pgraph/transparencyAttrib.h index ebd7f4f157..ef890aa158 100644 --- a/panda/src/pgraph/transparencyAttrib.h +++ b/panda/src/pgraph/transparencyAttrib.h @@ -59,7 +59,6 @@ public: protected: virtual int compare_to_impl(const RenderAttrib *other) const; virtual size_t get_hash_impl() const; - virtual CPT(RenderAttrib) get_auto_shader_attrib_impl(const RenderState *state) const; private: Mode _mode; diff --git a/panda/src/pgraphnodes/directionalLight.cxx b/panda/src/pgraphnodes/directionalLight.cxx index f0d84ffb9a..9d198fac6f 100644 --- a/panda/src/pgraphnodes/directionalLight.cxx +++ b/panda/src/pgraphnodes/directionalLight.cxx @@ -56,9 +56,7 @@ fillin(DatagramIterator &scan, BamReader *) { */ DirectionalLight:: DirectionalLight(const string &name) : - LightLensNode(name, new OrthographicLens()), - _has_specular_color(false) -{ + LightLensNode(name, new OrthographicLens()) { _lenses[0]._lens->set_interocular_distance(0); } @@ -69,7 +67,6 @@ DirectionalLight(const string &name) : DirectionalLight:: DirectionalLight(const DirectionalLight ©) : LightLensNode(copy), - _has_specular_color(copy._has_specular_color), _cycler(copy._cycler) { } diff --git a/panda/src/pgraphnodes/directionalLight.h b/panda/src/pgraphnodes/directionalLight.h index 5f0404b9a8..ea09627bd7 100644 --- a/panda/src/pgraphnodes/directionalLight.h +++ b/panda/src/pgraphnodes/directionalLight.h @@ -59,8 +59,6 @@ public: int light_id); private: - bool _has_specular_color; - // This is the data that must be cycled between pipeline stages. class EXPCL_PANDA_PGRAPHNODES CData : public CycleData { public: diff --git a/panda/src/pgraphnodes/lightLensNode.I b/panda/src/pgraphnodes/lightLensNode.I index 8fff5b2533..eb2b192f97 100644 --- a/panda/src/pgraphnodes/lightLensNode.I +++ b/panda/src/pgraphnodes/lightLensNode.I @@ -11,6 +11,15 @@ * @date 2002-03-26 */ +/** + * Returns true if this light defines a specular color, false if the specular + * color is derived automatically from the light color. + */ +INLINE bool LightLensNode:: +has_specular_color() const { + return _has_specular_color; +} + /** * Returns whether this light is configured to cast shadows or not. */ diff --git a/panda/src/pgraphnodes/lightLensNode.cxx b/panda/src/pgraphnodes/lightLensNode.cxx index a843123cff..f68b7084ec 100644 --- a/panda/src/pgraphnodes/lightLensNode.cxx +++ b/panda/src/pgraphnodes/lightLensNode.cxx @@ -28,6 +28,7 @@ TypeHandle LightLensNode::_type_handle; LightLensNode:: LightLensNode(const string &name, Lens *lens) : Camera(name, lens), + _has_specular_color(false), _attrib_count(0) { set_active(false); @@ -63,6 +64,7 @@ LightLensNode(const LightLensNode ©) : _shadow_caster(copy._shadow_caster), _sb_size(copy._sb_size), _sb_sort(-10), + _has_specular_color(copy._has_specular_color), _attrib_count(0) { } diff --git a/panda/src/pgraphnodes/lightLensNode.h b/panda/src/pgraphnodes/lightLensNode.h index 11c259e5e5..02dcd9bbff 100644 --- a/panda/src/pgraphnodes/lightLensNode.h +++ b/panda/src/pgraphnodes/lightLensNode.h @@ -35,6 +35,8 @@ PUBLISHED: LightLensNode(const string &name, Lens *lens = new PerspectiveLens()); virtual ~LightLensNode(); + INLINE bool has_specular_color() const; + INLINE bool is_shadow_caster() const; INLINE void set_shadow_caster(bool caster); INLINE void set_shadow_caster(bool caster, int buffer_xsize, int buffer_ysize, int sort = -10); @@ -54,6 +56,7 @@ protected: LVecBase2i _sb_size; bool _shadow_caster; + bool _has_specular_color; int _sb_sort; // This is really a map of GSG -> GraphicsOutput. diff --git a/panda/src/pgraphnodes/pointLight.cxx b/panda/src/pgraphnodes/pointLight.cxx index d3f7192248..caa8d86261 100644 --- a/panda/src/pgraphnodes/pointLight.cxx +++ b/panda/src/pgraphnodes/pointLight.cxx @@ -61,9 +61,7 @@ fillin(DatagramIterator &scan, BamReader *manager) { */ PointLight:: PointLight(const string &name) : - LightLensNode(name), - _has_specular_color(false) -{ + LightLensNode(name) { PT(Lens) lens; lens = new PerspectiveLens(90, 90); lens->set_interocular_distance(0); @@ -98,7 +96,6 @@ PointLight(const string &name) : PointLight:: PointLight(const PointLight ©) : LightLensNode(copy), - _has_specular_color(copy._has_specular_color), _cycler(copy._cycler) { } diff --git a/panda/src/pgraphnodes/pointLight.h b/panda/src/pgraphnodes/pointLight.h index c0907dba01..1029e1d41d 100644 --- a/panda/src/pgraphnodes/pointLight.h +++ b/panda/src/pgraphnodes/pointLight.h @@ -63,8 +63,6 @@ public: int light_id); private: - bool _has_specular_color; - // This is the data that must be cycled between pipeline stages. class EXPCL_PANDA_PGRAPHNODES CData : public CycleData { public: diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index e78ac65f3a..62206f1d69 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/panda/src/pgraphnodes/shaderGenerator.cxx @@ -40,24 +40,27 @@ #include "directionalLight.h" #include "rescaleNormalAttrib.h" #include "pointLight.h" +#include "sphereLight.h" #include "spotlight.h" #include "lightLensNode.h" #include "lvector4.h" #include "config_pgraphnodes.h" +#include "pStatTimer.h" TypeHandle ShaderGenerator::_type_handle; #ifdef HAVE_CG +static PStatCollector lookup_collector("*:Munge:ShaderGen:Lookup"); +static PStatCollector synthesize_collector("*:Munge:ShaderGen:Synthesize"); + /** * Create a ShaderGenerator. This has no state, except possibly to cache * certain results. The parameter that must be passed is the GSG to which the * shader generator belongs. */ ShaderGenerator:: -ShaderGenerator(GraphicsStateGuardianBase *gsg) : - _gsg(gsg) { - +ShaderGenerator(GraphicsStateGuardianBase *gsg) { // The ATTR# input semantics seem to map to generic vertex attributes in // both arbvp1 and glslv, which behave more consistently. However, they // don't exist in Direct3D 9. Use this silly little check for now. @@ -66,6 +69,10 @@ ShaderGenerator(GraphicsStateGuardianBase *gsg) : #else _use_generic_attr = false; #endif + + // Do we want to use the ARB_shadow extension? This also allows us to use + // hardware shadows PCF. + _use_shadow_filter = gsg->get_supports_shadow_filter(); } /** @@ -159,13 +166,8 @@ alloc_freg() { case 6: _ftregs_used += 1; return "TEXCOORD6"; case 7: _ftregs_used += 1; return "TEXCOORD7"; } -/* - * We really shouldn't rely on COLOR fregs, since the clamping can have - * unexpected side-effects. switch (_fcregs_used) { case 0: _fcregs_used += - * 1; return "COLOR0"; case 1: _fcregs_used += 1; return "COLOR1"; } These - * don't exist in arbvp1arbfp1, though they're reportedly supported by other - * profiles. - */ + // NB. We really shouldn't use the COLOR fregs, since the clamping can have + // unexpected side-effects. switch (_ftregs_used) { case 8: _ftregs_used += 1; return "TEXCOORD8"; case 9: _ftregs_used += 1; return "TEXCOORD9"; @@ -184,340 +186,334 @@ alloc_freg() { * analysis are stored in instance variables of the Shader Generator. */ void ShaderGenerator:: -analyze_renderstate(const RenderState *rs) { - clear_analysis(); +analyze_renderstate(ShaderKey &key, const RenderState *rs) { + const ShaderAttrib *shader_attrib; + rs->get_attrib_def(shader_attrib); + nassertv(shader_attrib->auto_shader()); // verify_enforce_attrib_lock(); - _state = rs; const AuxBitplaneAttrib *aux_bitplane; rs->get_attrib_def(aux_bitplane); - int outputs = aux_bitplane->get_outputs(); + key._outputs = aux_bitplane->get_outputs(); // Decide whether or not we need alpha testing or alpha blending. - + bool have_alpha_test = false; + bool have_alpha_blend = false; const AlphaTestAttrib *alpha_test; rs->get_attrib_def(alpha_test); - if ((alpha_test->get_mode() != RenderAttrib::M_none)&& - (alpha_test->get_mode() != RenderAttrib::M_always)) { - _have_alpha_test = true; + if (alpha_test->get_mode() != RenderAttrib::M_none && + alpha_test->get_mode() != RenderAttrib::M_always) { + have_alpha_test = true; } const ColorBlendAttrib *color_blend; rs->get_attrib_def(color_blend); if (color_blend->get_mode() != ColorBlendAttrib::M_none) { - _have_alpha_blend = true; + have_alpha_blend = true; } const TransparencyAttrib *transparency; rs->get_attrib_def(transparency); - if ((transparency->get_mode() == TransparencyAttrib::M_alpha)|| - (transparency->get_mode() == TransparencyAttrib::M_premultiplied_alpha)|| - (transparency->get_mode() == TransparencyAttrib::M_dual)) { - _have_alpha_blend = true; + if (transparency->get_mode() == TransparencyAttrib::M_alpha || + transparency->get_mode() == TransparencyAttrib::M_premultiplied_alpha || + transparency->get_mode() == TransparencyAttrib::M_dual) { + have_alpha_blend = true; } // Decide what to send to the framebuffer alpha, if anything. - - if (outputs & AuxBitplaneAttrib::ABO_glow) { - if (_have_alpha_blend) { - _calc_primary_alpha = true; - _out_primary_glow = false; - _disable_alpha_write = true; - } else if (_have_alpha_test) { - _calc_primary_alpha = true; - _out_primary_glow = true; - _subsume_alpha_test = true; - } else { - _calc_primary_alpha = false; - _out_primary_glow = true; - } - } else { - if (_have_alpha_blend || _have_alpha_test) { - _calc_primary_alpha = true; + if (key._outputs & AuxBitplaneAttrib::ABO_glow) { + if (have_alpha_blend) { + key._outputs &= ~AuxBitplaneAttrib::ABO_glow; + key._disable_alpha_write = true; + } else if (have_alpha_test) { + // Subsume the alpha test in our shader. + key._alpha_test_mode = alpha_test->get_mode(); + key._alpha_test_ref = alpha_test->get_reference_alpha(); } } - // Determine what to put into the aux bitplane. - - _out_aux_normal = (outputs & AuxBitplaneAttrib::ABO_aux_normal) ? true:false; - _out_aux_glow = (outputs & AuxBitplaneAttrib::ABO_aux_glow) ? true:false; - _out_aux_any = (_out_aux_normal || _out_aux_glow); - - if (_out_aux_normal) { - _need_eye_normal = true; + if (have_alpha_blend || have_alpha_test) { + key._calc_primary_alpha = true; } - // Count number of textures. - - const TextureAttrib *texture; - rs->get_attrib_def(texture); - _num_textures = texture->get_num_on_stages(); - // Determine whether or not vertex colors or flat colors are present. - const ColorAttrib *color; rs->get_attrib_def(color); - if (color->get_color_type() == ColorAttrib::T_vertex) { - _vertex_colors = true; - } else if (color->get_color_type() == ColorAttrib::T_flat) { - _flat_colors = true; - } - - // Find the material. + key._color_type = color->get_color_type(); + // Store the material flags (not the material values itself). const MaterialAttrib *material; rs->get_attrib_def(material); - _material_flags = material->get_material_flags(); + if (material->get_material() != nullptr) { + key._material_flags = material->get_material()->get_flags(); + } // Break out the lights by type. - - _shadows = false; const LightAttrib *la; rs->get_attrib_def(la); + bool have_ambient = false; for (int i = 0; i < la->get_num_on_lights(); ++i) { - NodePath light = la->get_on_light(i); - nassertv(!light.is_empty()); - PandaNode *light_obj = light.node(); - nassertv(light_obj != (PandaNode *)NULL); + NodePath np = la->get_on_light(i); + nassertv(!np.is_empty()); + PandaNode *node = np.node(); + nassertv(node != nullptr); - if (light_obj->is_ambient_light()) { - _have_ambient = true; - _lighting = true; + if (node->is_ambient_light()) { + have_ambient = true; + key._lighting = true; + } else { + ShaderKey::LightInfo info; + info._type = node->get_type(); + info._flags = 0; - } else if (light_obj->is_of_type(LightLensNode::get_class_type())) { - _lights_np.push_back(light); - _lights.push_back((LightLensNode *)light_obj); - if (((const LightLensNode *)light_obj)->is_shadow_caster()) { - _shadows = true; + if (node->is_of_type(LightLensNode::get_class_type())) { + const LightLensNode *llnode = (const LightLensNode *)node; + if (shader_attrib->auto_shadow_on() && llnode->is_shadow_caster()) { + info._flags |= ShaderKey::LF_has_shadows; + } + if (llnode->has_specular_color()) { + info._flags |= ShaderKey::LF_has_specular_color; + } } - _lighting = true; - _need_eye_normal = true; + + key._lights.push_back(info); + key._lighting = true; } } + bool normal_mapping = key._lighting && shader_attrib->auto_normal_on(); + // See if there is a normal map, height map, gloss map, or glow map. Also // check if anything has TexGen. + const TextureAttrib *texture; + rs->get_attrib_def(texture); const TexGenAttrib *tex_gen; rs->get_attrib_def(tex_gen); - for (int i = 0; i < _num_textures; ++i) { + const TexMatrixAttrib *tex_matrix; + rs->get_attrib_def(tex_matrix); + + size_t num_textures = texture->get_num_on_stages(); + for (size_t i = 0; i < num_textures; ++i) { TextureStage *stage = texture->get_on_stage(i); - TextureStage::Mode mode = stage->get_mode(); - if ((mode == TextureStage::M_normal)|| - (mode == TextureStage::M_normal_height)|| - (mode == TextureStage::M_normal_gloss)) { - _map_index_normal = i; + Texture *tex = texture->get_on_texture(stage); + nassertd(tex != nullptr) continue; + + ShaderKey::TextureInfo info; + info._type = tex->get_texture_type(); + info._mode = stage->get_mode(); + info._flags = 0; + + // While we look at the mode, determine whether we need to change the mode + // in order to reflect disabled features. + switch (info._mode) { + case TextureStage::M_modulate: + { + Texture::Format format = tex->get_format(); + if (format != Texture::F_alpha) { + info._flags |= ShaderKey::TF_has_rgb; + } + if (Texture::has_alpha(format)) { + info._flags |= ShaderKey::TF_has_alpha; + } + } + break; + + case TextureStage::M_modulate_glow: + if (shader_attrib->auto_glow_on()) { + info._flags = ShaderKey::TF_map_glow; + } else { + info._mode = TextureStage::M_modulate; + info._flags = ShaderKey::TF_has_rgb; + } + break; + + case TextureStage::M_modulate_gloss: + if (shader_attrib->auto_gloss_on()) { + info._flags = ShaderKey::TF_map_glow; + } else { + info._mode = TextureStage::M_modulate; + info._flags = ShaderKey::TF_has_rgb; + } + break; + + case TextureStage::M_normal_height: + if (parallax_mapping_samples == 0) { + info._mode = TextureStage::M_normal; + } else if (!shader_attrib->auto_normal_on() || + (!key._lighting && (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) == 0)) { + info._mode = TextureStage::M_height; + info._flags = ShaderKey::TF_has_alpha; + } else { + info._flags = ShaderKey::TF_map_normal | ShaderKey::TF_map_height; + } + break; + + case TextureStage::M_normal_gloss: + if (!shader_attrib->auto_gloss_on() || !key._lighting) { + info._mode = TextureStage::M_normal; + } else if (!shader_attrib->auto_normal_on()) { + info._mode = TextureStage::M_gloss; + } else { + info._flags = ShaderKey::TF_map_normal | ShaderKey::TF_map_gloss; + } + break; } - if ((mode == TextureStage::M_height)||(mode == TextureStage::M_normal_height)) { - _map_index_height = i; + + // In fact, perhaps this stage should be disabled altogether? + switch (info._mode) { + case TextureStage::M_normal: + if (!shader_attrib->auto_normal_on() || + (!key._lighting && (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) == 0)) { + continue; + } else { + info._flags = ShaderKey::TF_map_normal; + } + break; + case TextureStage::M_glow: + if (shader_attrib->auto_glow_on()) { + info._flags = ShaderKey::TF_map_glow; + } else { + continue; + } + break; + case TextureStage::M_gloss: + if (key._lighting && shader_attrib->auto_gloss_on()) { + info._flags = ShaderKey::TF_map_gloss; + } else { + continue; + } + break; + case TextureStage::M_height: + if (parallax_mapping_samples > 0) { + info._flags = ShaderKey::TF_map_height; + } else { + continue; + } + break; } - if ((mode == TextureStage::M_glow)||(mode == TextureStage::M_modulate_glow)) { - _map_index_glow = i; - } - if ((mode == TextureStage::M_gloss)|| - (mode == TextureStage::M_modulate_gloss)|| - (mode == TextureStage::M_normal_gloss)) { - _map_index_gloss = i; - } - if (mode == TextureStage::M_height) { - _map_height_in_alpha = false; - } - if (mode == TextureStage::M_normal_height) { - _map_height_in_alpha = true; - } - if (tex_gen->has_stage(stage)) { - switch (tex_gen->get_mode(stage)) { - case TexGenAttrib::M_world_position: - _need_world_position = true; - break; - case TexGenAttrib::M_world_normal: - _need_world_normal = true; - break; - case TexGenAttrib::M_eye_position: - _need_eye_position = true; - break; - case TexGenAttrib::M_eye_normal: - _need_eye_normal = true; - break; - default: - break; + + // Check if this state has a texture matrix to transform the texture + // coordinates. + if (tex_matrix->has_stage(stage)) { + CPT(TransformState) transform = tex_matrix->get_transform(stage); + if (!transform->is_identity()) { + // Optimize for common case: if we only have a scale component, we + // can get away with fewer shader inputs and operations. + if (transform->has_components() && !transform->has_nonzero_shear() && + transform->get_pos() == LPoint3::zero() && + transform->get_hpr() == LVecBase3::zero()) { + info._flags |= ShaderKey::TF_has_texscale; + } else { + info._flags |= ShaderKey::TF_has_texmat; + } } } - } - // Determine whether we should normalize the normals. - /*const RescaleNormalAttrib *rescale; - rs->get_attrib_def(rescale); - - _normalize_normals = (rescale->get_mode() != RescaleNormalAttrib::M_none); - */ - // Actually, let's always normalize the normals for now. This helps to - // reduce combinatoric explosion of shaders. - _normalize_normals = true; - - // Decide which material modes need to be calculated. - - if (_lighting) { - _have_diffuse = true; - } - - if (_lighting && (_material_flags & Material::F_emission) != 0) { - _have_emission = true; - } - - if (_lighting) { - if (_material_flags & Material::F_specular) { - _have_specular = true; - } else if (_map_index_gloss >= 0) { - _have_specular = true; + if (tex_gen->has_stage(stage)) { + info._texcoord_name = nullptr; + info._gen_mode = tex_gen->get_mode(stage); + } else { + info._texcoord_name = stage->get_texcoord_name(); + info._gen_mode = TexGenAttrib::M_off; } - _need_eye_position = true; + // If we have this rare, special mode, just include a pointer to the + // TextureStage object, because I can't be bothered to bloat the shader + // key with all these extra relevant properties. + if (stage->get_mode() == TextureStage::M_combine) { + info._stage = stage; + } + + key._textures.push_back(info); + key._texture_flags |= info._flags; } // Decide whether to separate ambient and diffuse calculations. - - if (_have_ambient && _have_diffuse) { - if (_material_flags & Material::F_ambient) { - _separate_ambient_diffuse = true; + if (have_ambient) { + if (key._material_flags & Material::F_ambient) { + key._have_separate_ambient = true; } else { - if (_material_flags & Material::F_diffuse) { - _separate_ambient_diffuse = true; + if (key._material_flags & Material::F_diffuse) { + key._have_separate_ambient = true; } else { - _separate_ambient_diffuse = false; + key._have_separate_ambient = false; } } } - const LightRampAttrib *light_ramp; - if (_lighting && rs->get_attrib(light_ramp) && - (light_ramp->get_mode() != LightRampAttrib::LRT_identity)) { - _separate_ambient_diffuse = true; + if (shader_attrib->auto_ramp_on()) { + const LightRampAttrib *light_ramp; + if (rs->get_attrib(light_ramp)) { + key._light_ramp = light_ramp; + if (key._lighting) { + key._have_separate_ambient = true; + } + } } - // Do we want to use the ARB_shadow extension? This also allows us to use - // hardware shadows PCF. - - _use_shadow_filter = _gsg->get_supports_shadow_filter(); - - // Does the shader need material properties as input? - - _need_material_props = - (_have_ambient && (_material_flags & Material::F_ambient) != 0) || - (_have_diffuse && (_material_flags & Material::F_diffuse) != 0) || - (_have_emission && (_material_flags & Material::F_emission) != 0) || - (_have_specular && (_material_flags & Material::F_specular) != 0); - // Check for clip planes. - const ClipPlaneAttrib *clip_plane; rs->get_attrib_def(clip_plane); - _num_clip_planes = clip_plane->get_num_on_planes(); - if (_num_clip_planes > 0) { - _need_world_position = true; - } - - const ShaderAttrib *shader_attrib; - rs->get_attrib_def(shader_attrib); - if (shader_attrib->auto_shader()) { - _auto_normal_on = shader_attrib->auto_normal_on(); - _auto_glow_on = shader_attrib->auto_glow_on(); - _auto_gloss_on = shader_attrib->auto_gloss_on(); - _auto_ramp_on = shader_attrib->auto_ramp_on(); - _auto_shadow_on = shader_attrib->auto_shadow_on(); - } + key._num_clip_planes = clip_plane->get_num_on_planes(); // Check for fog. const FogAttrib *fog; if (rs->get_attrib(fog) && !fog->is_off()) { - _fog = true; + key._fog_mode = (int)fog->get_fog()->get_mode() + 1; } } -/** - * Called after analyze_renderstate to discard all the results of the - * analysis. This is generally done after shader generation is complete. - */ -void ShaderGenerator:: -clear_analysis() { - _vertex_colors = false; - _flat_colors = false; - _lighting = false; - _shadows = false; - _fog = false; - _have_ambient = false; - _have_diffuse = false; - _have_emission = false; - _have_specular = false; - _separate_ambient_diffuse = false; - _map_index_normal = -1; - _map_index_glow = -1; - _map_index_gloss = -1; - _map_index_height = -1; - _map_height_in_alpha = false; - _calc_primary_alpha = false; - _have_alpha_test = false; - _have_alpha_blend = false; - _subsume_alpha_test = false; - _disable_alpha_write = false; - _num_clip_planes = 0; - _use_shadow_filter = false; - _out_primary_glow = false; - _out_aux_normal = false; - _out_aux_glow = false; - _out_aux_any = false; - _material_flags = 0; - _need_material_props = false; - _need_world_position = false; - _need_world_normal = false; - _need_eye_position = false; - _need_eye_normal = false; - _normalize_normals = false; - _auto_normal_on = false; - _auto_glow_on = false; - _auto_gloss_on = false; - _auto_ramp_on = false; - _auto_shadow_on = false; - - _lights.clear(); - _lights_np.clear(); -} - -/** - * Creates a ShaderAttrib given a generated shader's body. Also inserts the - * lights into the shader attrib. - */ -CPT(RenderAttrib) ShaderGenerator:: -create_shader_attrib(const string &txt) { - PT(Shader) shader = Shader::make(txt, Shader::SL_Cg); - CPT(RenderAttrib) shattr = ShaderAttrib::make(shader); - - for (size_t i = 0; i < _lights.size(); ++i) { - shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("light", i), _lights_np[i]); - } - return shattr; -} - /** * This is the routine that implements the next-gen fixed function pipeline by * synthesizing a shader. It also takes care of setting up any buffers needed * to produce the requested effects. * - * Currently supports: - flat colors - vertex colors - lighting - normal maps, - * but not multiple - gloss maps, but not multiple - glow maps, but not - * multiple - materials, but not updates to materials - 2D textures - all - * texture stage modes, including combine modes - color scale attrib - light - * ramps (for cartoon shading) - shadow mapping - most texgen modes - - * texmatrix - 1D/2D/3D textures, cube textures, 2D tex arrays - - * linear/exp/exp2 fog - animation + * Currently supports: + * - flat colors + * - vertex colors + * - lighting + * - normal maps, but not multiple + * - gloss maps, but not multiple + * - glow maps, but not multiple + * - materials, but not updates to materials + * - 2D textures + * - all texture stage modes, including combine modes + * - color scale attrib + * - light ramps (for cartoon shading) + * - shadow mapping + * - most texgen modes + * - texmatrix + * - 1D/2D/3D textures, cube textures, 2D tex arrays + * - linear/exp/exp2 fog + * - animation * - * Not yet supported: - dot3_rgb and dot3_rgba combine modes + * Not yet supported: + * - dot3_rgb and dot3_rgba combine modes * - * Potential optimizations - omit attenuation calculations if attenuation off + * Potential optimizations + * - omit attenuation calculations if attenuation off * */ CPT(ShaderAttrib) ShaderGenerator:: synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { - analyze_renderstate(rs); + ShaderKey key; + + // First look up the state key in the table of already generated shaders. + { + PStatTimer timer(lookup_collector); + key._anim_spec = anim; + analyze_renderstate(key, rs); + + GeneratedShaders::const_iterator si; + si = _generated_shaders.find(key); + if (si != _generated_shaders.end()) { + // We've already generated a shader for this state. + return si->second; + } + } + + PStatTimer timer(synthesize_collector); + reset_register_allocator(); if (pgraphnodes_cat.is_debug()) { @@ -556,7 +552,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { normal_vreg = "NORMAL"; } - if (_vertex_colors) { + if (key._color_type == ColorAttrib::T_vertex) { // Reserve COLOR0 color_vreg = _use_generic_attr ? "ATTR3" : "COLOR0"; _vcregs_used = 1; @@ -573,32 +569,65 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { rs->write(text, 2); text << "*/\n"; + int map_index_normal = -1; + int map_index_glow = -1; + int map_index_gloss = -1; + + // Figure out whether we need to calculate any of these variables. + bool need_world_position = (key._num_clip_planes > 0); + bool need_world_normal = false; + bool need_eye_position = key._lighting; + bool need_eye_normal = !key._lights.empty() || ((key._outputs & AuxBitplaneAttrib::ABO_aux_normal) != 0); + + bool have_specular = false; + if (key._lighting) { + if (key._material_flags & Material::F_specular) { + have_specular = true; + } else if ((key._texture_flags & ShaderKey::TF_map_gloss) != 0) { + have_specular = true; + } + } + text << "void vshader(\n"; - const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot())); - const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, rs->get_attrib_def(TexGenAttrib::get_class_slot())); - for (int i = 0; i < _num_textures; ++i) { - TextureStage *stage = texture->get_on_stage(i); - if (!tex_gen->has_stage(stage)) { - const InternalName *texcoord_name = stage->get_texcoord_name(); + for (size_t i = 0; i < key._textures.size(); ++i) { + const ShaderKey::TextureInfo &tex = key._textures[i]; - if (texcoord_fregs.count(texcoord_name) == 0) { + switch (tex._gen_mode) { + case TexGenAttrib::M_world_position: + need_world_position = true; + break; + case TexGenAttrib::M_world_normal: + need_world_normal = true; + break; + case TexGenAttrib::M_eye_position: + need_eye_position = true; + break; + case TexGenAttrib::M_eye_normal: + need_eye_normal = true; + break; + default: + break; + } + + if (tex._texcoord_name != nullptr) { + if (texcoord_fregs.count(tex._texcoord_name) == 0) { const char *freg = alloc_freg(); - string tcname = texcoord_name->join("_"); - texcoord_fregs[texcoord_name] = freg; + texcoord_fregs[tex._texcoord_name] = freg; + string tcname = tex._texcoord_name->join("_"); text << "\t in float4 vtx_" << tcname << " : " << alloc_vreg() << ",\n"; text << "\t out float4 l_" << tcname << " : " << freg << ",\n"; } } - if ((_map_index_normal == i && (_lighting || _out_aux_normal) && _auto_normal_on) || _map_index_height == i) { - const InternalName *texcoord_name = stage->get_texcoord_name(); + if (tex._flags & (ShaderKey::TF_map_normal | ShaderKey::TF_map_height)) { PT(InternalName) tangent_name = InternalName::get_tangent(); PT(InternalName) binormal_name = InternalName::get_binormal(); - if (texcoord_name != InternalName::get_texcoord()) { - tangent_name = tangent_name->append(texcoord_name->get_basename()); - binormal_name = binormal_name->append(texcoord_name->get_basename()); + if (tex._texcoord_name != nullptr && + tex._texcoord_name != InternalName::get_texcoord()) { + tangent_name = tangent_name->append(tex._texcoord_name->get_basename()); + binormal_name = binormal_name->append(tex._texcoord_name->get_basename()); } tangent_input = tangent_name->join("_"); binormal_input = binormal_name->join("_"); @@ -606,84 +635,87 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << "\t in float4 vtx_" << tangent_input << " : " << alloc_vreg() << ",\n"; text << "\t in float4 vtx_" << binormal_input << " : " << alloc_vreg() << ",\n"; - if (_map_index_normal == i && (_lighting || _out_aux_normal) && _auto_normal_on) { + if (tex._flags & ShaderKey::TF_map_normal) { + map_index_normal = i; tangent_freg = alloc_freg(); binormal_freg = alloc_freg(); text << "\t out float4 l_tangent : " << tangent_freg << ",\n"; text << "\t out float4 l_binormal : " << binormal_freg << ",\n"; } } + + if (tex._flags & ShaderKey::TF_map_glow) { + map_index_glow = i; + } + if (tex._flags & ShaderKey::TF_map_gloss) { + map_index_gloss = i; + } } - if (_vertex_colors) { + if (key._color_type == ColorAttrib::T_vertex) { text << "\t in float4 vtx_color : " << color_vreg << ",\n"; text << "\t out float4 l_color : COLOR0,\n"; } - if (_need_world_position || _need_world_normal) { + if (need_world_position || need_world_normal) { text << "\t uniform float4x4 trans_model_to_world,\n"; } - if (_need_world_position) { + if (need_world_position) { world_position_freg = alloc_freg(); text << "\t out float4 l_world_position : " << world_position_freg << ",\n"; } - if (_need_world_normal) { + if (need_world_normal) { world_normal_freg = alloc_freg(); text << "\t out float4 l_world_normal : " << world_normal_freg << ",\n"; } - if (_need_eye_position) { + if (need_eye_position) { text << "\t uniform float4x4 trans_model_to_view,\n"; eye_position_freg = alloc_freg(); text << "\t out float4 l_eye_position : " << eye_position_freg << ",\n"; - } else if ((_lighting || _out_aux_normal) && (_map_index_normal >= 0 && _auto_normal_on)) { + } else if (key._texture_flags & ShaderKey::TF_map_normal) { text << "\t uniform float4x4 trans_model_to_view,\n"; } - if (_need_eye_normal) { + if (need_eye_normal) { eye_normal_freg = alloc_freg(); text << "\t uniform float4x4 tpose_view_to_model,\n"; text << "\t out float4 l_eye_normal : " << eye_normal_freg << ",\n"; } - if (_map_index_height >= 0 || _need_world_normal || _need_eye_normal) { + if ((key._texture_flags & ShaderKey::TF_map_height) != 0 || need_world_normal || need_eye_normal) { text << "\t in float3 vtx_normal : " << normal_vreg << ",\n"; } - if (_map_index_height >= 0) { + if (key._texture_flags & ShaderKey::TF_map_height) { text << "\t uniform float4 mspos_view,\n"; text << "\t out float3 l_eyevec,\n"; } - if (_lighting && _shadows && _auto_shadow_on) { - for (size_t i = 0; i < _lights.size(); ++i) { - if (_lights[i]->_shadow_caster) { - lightcoord_fregs.push_back(alloc_freg()); - if (_lights[i]->is_of_type(PointLight::get_class_type())) { - text << "\t uniform float4x4 trans_model_to_light" << i << ",\n"; - } else { - text << "\t uniform float4x4 trans_model_to_clip_of_light" << i << ",\n"; - } - text << "\t out float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n"; - } else { - lightcoord_fregs.push_back(NULL); - } + for (size_t i = 0; i < key._lights.size(); ++i) { + const ShaderKey::LightInfo &light = key._lights[i]; + if (light._flags & ShaderKey::LF_has_shadows) { + lightcoord_fregs.push_back(alloc_freg()); + text << "\t uniform float4x4 mat_shadow_" << i << ",\n"; + text << "\t out float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n"; + } else { + lightcoord_fregs.push_back(nullptr); } } - if (_fog) { + if (key._fog_mode != 0) { hpos_freg = alloc_freg(); text << "\t out float4 l_hpos : " << hpos_freg << ",\n"; } - if (anim.get_animation_type() == GeomEnums::AT_hardware && - anim.get_num_transforms() > 0) { + if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware && + key._anim_spec.get_num_transforms() > 0) { int num_transforms; - if (anim.get_indexed_transforms()) { + if (key._anim_spec.get_indexed_transforms()) { num_transforms = 120; } else { - num_transforms = anim.get_num_transforms(); + num_transforms = key._anim_spec.get_num_transforms(); } - if (transform_weight_vreg == NULL) { + if (transform_weight_vreg == nullptr) { transform_weight_vreg = alloc_vreg(); } - if (transform_index_vreg == NULL) { + if (transform_index_vreg == nullptr) { transform_index_vreg = alloc_vreg(); } text << "\t uniform float4x4 tbl_transforms[" << num_transforms << "],\n"; text << "\t in float4 vtx_transform_weight : " << transform_weight_vreg << ",\n"; - if (anim.get_indexed_transforms()) { + if (key._anim_spec.get_indexed_transforms()) { text << "\t in uint4 vtx_transform_index : " << transform_index_vreg << ",\n"; } } @@ -692,50 +724,46 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << "\t uniform float4x4 mat_modelproj\n"; text << ") {\n"; - if (anim.get_animation_type() == GeomEnums::AT_hardware && - anim.get_num_transforms() > 0) { + if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware && + key._anim_spec.get_num_transforms() > 0) { - if (!anim.get_indexed_transforms()) { + if (!key._anim_spec.get_indexed_transforms()) { text << "\t const uint4 vtx_transform_index = uint4(0, 1, 2, 3);\n"; } text << "\t float4x4 matrix = tbl_transforms[vtx_transform_index.x] * vtx_transform_weight.x"; - if (anim.get_num_transforms() > 1) { + if (key._anim_spec.get_num_transforms() > 1) { text << "\n\t + tbl_transforms[vtx_transform_index.y] * vtx_transform_weight.y"; } - if (anim.get_num_transforms() > 2) { + if (key._anim_spec.get_num_transforms() > 2) { text << "\n\t + tbl_transforms[vtx_transform_index.z] * vtx_transform_weight.z"; } - if (anim.get_num_transforms() > 3) { + if (key._anim_spec.get_num_transforms() > 3) { text << "\n\t + tbl_transforms[vtx_transform_index.w] * vtx_transform_weight.w"; } text << ";\n"; text << "\t vtx_position = mul(matrix, vtx_position);\n"; - if (_need_world_normal || _need_eye_normal) { + if (need_world_normal || need_eye_normal) { text << "\t vtx_normal = mul((float3x3)matrix, vtx_normal);\n"; } } text << "\t l_position = mul(mat_modelproj, vtx_position);\n"; - if (_fog) { + if (key._fog_mode != 0) { text << "\t l_hpos = l_position;\n"; } - if (_need_world_position) { + if (need_world_position) { text << "\t l_world_position = mul(trans_model_to_world, vtx_position);\n"; } - if (_need_world_normal) { + if (need_world_normal) { text << "\t l_world_normal = mul(trans_model_to_world, float4(vtx_normal, 0));\n"; } - if (_need_eye_position) { + if (need_eye_position) { text << "\t l_eye_position = mul(trans_model_to_view, vtx_position);\n"; } - if (_need_eye_normal) { - if (_normalize_normals) { - text << "\t l_eye_normal.xyz = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n"; - } else { - text << "\t l_eye_normal.xyz = mul((float3x3)tpose_view_to_model, vtx_normal);\n"; - } + if (need_eye_normal) { + text << "\t l_eye_normal.xyz = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n"; text << "\t l_eye_normal.w = 0;\n"; } pmap::const_iterator it; @@ -744,28 +772,21 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { string tcname = it->first->join("_"); text << "\t l_" << tcname << " = vtx_" << tcname << ";\n"; } - if (_vertex_colors) { + if (key._color_type == ColorAttrib::T_vertex) { text << "\t l_color = vtx_color;\n"; } - if ((_lighting || _out_aux_normal) && (_map_index_normal >= 0 && _auto_normal_on)) { + if (key._texture_flags & ShaderKey::TF_map_normal) { text << "\t l_tangent.xyz = normalize(mul((float3x3)trans_model_to_view, vtx_" << tangent_input << ".xyz));\n"; text << "\t l_tangent.w = 0;\n"; text << "\t l_binormal.xyz = normalize(mul((float3x3)trans_model_to_view, -vtx_" << binormal_input << ".xyz));\n"; text << "\t l_binormal.w = 0;\n"; } - if (_shadows && _auto_shadow_on) { - text << "\t float4x4 biasmat = {0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f};\n"; - for (size_t i = 0; i < _lights.size(); ++i) { - if (_lights[i]->_shadow_caster) { - if (_lights[i]->is_of_type(PointLight::get_class_type())) { - text << "\t l_lightcoord" << i << " = mul(trans_model_to_light" << i << ", vtx_position);\n"; - } else { - text << "\t l_lightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_light" << i << ", vtx_position));\n"; - } - } + for (size_t i = 0; i < key._lights.size(); ++i) { + if (key._lights[i]._flags & ShaderKey::LF_has_shadows) { + text << "\t l_lightcoord" << i << " = mul(mat_shadow_" << i << ", l_eye_position);\n"; } } - if (_map_index_height >= 0) { + if (key._texture_flags & ShaderKey::TF_map_height) { text << "\t float3 eyedir = mspos_view.xyz - vtx_position.xyz;\n"; text << "\t l_eyevec.x = dot(vtx_" << tangent_input << ".xyz, eyedir);\n"; text << "\t l_eyevec.y = dot(vtx_" << binormal_input << ".xyz, eyedir);\n"; @@ -777,142 +798,144 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { // Fragment shader text << "void fshader(\n"; - if (_fog) { + if (key._fog_mode != 0) { text << "\t in float4 l_hpos : " << hpos_freg << ",\n"; text << "\t in uniform float4 attr_fog,\n"; text << "\t in uniform float4 attr_fogcolor,\n"; } - if (_need_world_position) { + if (need_world_position) { text << "\t in float4 l_world_position : " << world_position_freg << ",\n"; } - if (_need_world_normal) { + if (need_world_normal) { text << "\t in float4 l_world_normal : " << world_normal_freg << ",\n"; } - if (_need_eye_position) { + if (need_eye_position) { text << "\t in float4 l_eye_position : " << eye_position_freg << ",\n"; } - if (_need_eye_normal) { + if (need_eye_normal) { text << "\t in float4 l_eye_normal : " << eye_normal_freg << ",\n"; } for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) { text << "\t in float4 l_" << it->first->join("_") << " : " << it->second << ",\n"; } - const TexMatrixAttrib *tex_matrix = DCAST(TexMatrixAttrib, rs->get_attrib_def(TexMatrixAttrib::get_class_slot())); - for (int i = 0; i < _num_textures; ++i) { - TextureStage *stage = texture->get_on_stage(i); - Texture::TextureType type = texture->get_on_texture_type(stage); - text << "\t uniform sampler" << texture_type_as_string(type) << " tex_" << i << ",\n"; - if (tex_matrix->has_stage(stage)) { + for (size_t i = 0; i < key._textures.size(); ++i) { + const ShaderKey::TextureInfo &tex = key._textures[i]; + text << "\t uniform sampler" << texture_type_as_string(tex._type) << " tex_" << i << ",\n"; + + if (tex._flags & ShaderKey::TF_has_texscale) { + text << "\t uniform float3 texscale_" << i << ",\n"; + } else if (tex._flags & ShaderKey::TF_has_texmat) { text << "\t uniform float4x4 texmat_" << i << ",\n"; } + + if (tex._mode == TextureStage::M_blend) { + text << "\t uniform float4 texcolor_" << i << ",\n"; + } } - if ((_lighting || _out_aux_normal) && (_map_index_normal >= 0 && _auto_normal_on)) { + if (key._texture_flags & ShaderKey::TF_map_normal) { text << "\t in float3 l_tangent : " << tangent_freg << ",\n"; text << "\t in float3 l_binormal : " << binormal_freg << ",\n"; } - if (_lighting) { - for (size_t i = 0; i < _lights.size(); ++i) { - if (_lights[i]->is_of_type(DirectionalLight::get_class_type())) { - text << "\t uniform float4x4 dlight_light" << i << "_rel_view,\n"; + for (size_t i = 0; i < key._lights.size(); ++i) { + text << "\t uniform float4x4 attr_light" << i << ",\n"; - } else if (_lights[i]->is_of_type(PointLight::get_class_type())) { - text << "\t uniform float4x4 plight_light" << i << "_rel_view,\n"; - - } else if (_lights[i]->is_of_type(Spotlight::get_class_type())) { - text << "\t uniform float4x4 slight_light" << i << "_rel_view,\n"; - text << "\t uniform float4 satten_light" << i << ",\n"; - } - - if (_shadows && _lights[i]->_shadow_caster && _auto_shadow_on) { - if (_lights[i]->is_of_type(PointLight::get_class_type())) { - text << "\t uniform samplerCUBE shadow_light" << i << ",\n"; - } else if (_use_shadow_filter) { - text << "\t uniform sampler2DShadow shadow_light" << i << ",\n"; - } else { - text << "\t uniform sampler2D shadow_light" << i << ",\n"; - } - text << "\t in float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n"; - } - } - if (_need_material_props) { - text << "\t uniform float4x4 attr_material,\n"; - } - if (_have_specular) { - if (_material_flags & Material::F_local) { - text << "\t uniform float4 mspos_view,\n"; + const ShaderKey::LightInfo &light = key._lights[i]; + if (light._flags & ShaderKey::LF_has_shadows) { + if (light._type.is_derived_from(PointLight::get_class_type())) { + text << "\t uniform samplerCUBE shadow_" << i << ",\n"; + } else if (_use_shadow_filter) { + text << "\t uniform sampler2DShadow shadow_" << i << ",\n"; } else { - text << "\t uniform float4 row1_view_to_model,\n"; + text << "\t uniform sampler2D shadow_" << i << ",\n"; } + text << "\t in float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n"; + } + if (light._flags & ShaderKey::LF_has_specular_color) { + text << "\t uniform float4 attr_lspec" << i << ",\n"; } } - if (_map_index_height >= 0) { + + // Does the shader need material properties as input? + if (key._material_flags & (Material::F_ambient | Material::F_diffuse | Material::F_emission | Material::F_specular)) { + text << "\t uniform float4x4 attr_material,\n"; + } + if (key._texture_flags & ShaderKey::TF_map_height) { text << "\t float3 l_eyevec,\n"; } - if (_out_aux_any) { + if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) { text << "\t out float4 o_aux : COLOR1,\n"; } text << "\t out float4 o_color : COLOR0,\n"; - if (_vertex_colors) { + + if (key._color_type == ColorAttrib::T_vertex) { text << "\t in float4 l_color : COLOR0,\n"; - } else { + } else if (key._color_type == ColorAttrib::T_flat) { text << "\t uniform float4 attr_color,\n"; } - for (int i=0; i<_num_clip_planes; ++i) { + + for (int i = 0; i < key._num_clip_planes; ++i) { text << "\t uniform float4 clipplane_" << i << ",\n"; } + text << "\t uniform float4 attr_ambient,\n"; text << "\t uniform float4 attr_colorscale\n"; text << ") {\n"; + // Clipping first! - for (int i=0; i<_num_clip_planes; ++i) { + for (int i = 0; i < key._num_clip_planes; ++i) { text << "\t if (l_world_position.x * clipplane_" << i << ".x + l_world_position.y "; text << "* clipplane_" << i << ".y + l_world_position.z * clipplane_" << i << ".z + clipplane_" << i << ".w <= 0) {\n"; text << "\t discard;\n"; text << "\t }\n"; } text << "\t float4 result;\n"; - if (_out_aux_any) { + if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) { text << "\t o_aux = float4(0, 0, 0, 0);\n"; } // Now generate any texture coordinates according to TexGenAttrib. If it // has a TexMatrixAttrib, also transform them. - for (int i=0; i<_num_textures; i++) { - TextureStage *stage = texture->get_on_stage(i); - if (tex_gen != NULL && tex_gen->has_stage(stage)) { - switch (tex_gen->get_mode(stage)) { - case TexGenAttrib::M_world_position: - text << "\t float4 texcoord" << i << " = l_world_position;\n"; - break; - case TexGenAttrib::M_world_normal: - text << "\t float4 texcoord" << i << " = l_world_normal;\n"; - break; - case TexGenAttrib::M_eye_position: - text << "\t float4 texcoord" << i << " = l_eye_position;\n"; - break; - case TexGenAttrib::M_eye_normal: - text << "\t float4 texcoord" << i << " = l_eye_normal;\n"; - text << "\t texcoord" << i << ".w = 1.0f;\n"; - break; - default: - pgraphnodes_cat.error() << "Unsupported TexGenAttrib mode\n"; - text << "\t float4 texcoord" << i << " = float4(0, 0, 0, 0);\n"; - } - } else { + for (size_t i = 0; i < key._textures.size(); ++i) { + const ShaderKey::TextureInfo &tex = key._textures[i]; + switch (tex._gen_mode) { + case TexGenAttrib::M_off: // Cg seems to be able to optimize this temporary away when appropriate. - const InternalName *texcoord_name = stage->get_texcoord_name(); - text << "\t float4 texcoord" << i << " = l_" << texcoord_name->join("_") << ";\n"; + text << "\t float4 texcoord" << i << " = l_" << tex._texcoord_name->join("_") << ";\n"; + break; + case TexGenAttrib::M_world_position: + text << "\t float4 texcoord" << i << " = l_world_position;\n"; + break; + case TexGenAttrib::M_world_normal: + text << "\t float4 texcoord" << i << " = l_world_normal;\n"; + break; + case TexGenAttrib::M_eye_position: + text << "\t float4 texcoord" << i << " = l_eye_position;\n"; + break; + case TexGenAttrib::M_eye_normal: + text << "\t float4 texcoord" << i << " = l_eye_normal;\n"; + text << "\t texcoord" << i << ".w = 1.0f;\n"; + break; + default: + text << "\t float4 texcoord" << i << " = float4(0, 0, 0, 0);\n"; + pgraphnodes_cat.error() + << "Unsupported TexGenAttrib mode: " << tex._gen_mode << "\n"; } - if (tex_matrix != NULL && tex_matrix->has_stage(stage)) { + if (tex._flags & ShaderKey::TF_has_texscale) { + text << "\t texcoord" << i << ".xyz *= texscale_" << i << ";\n"; + } else if (tex._flags & ShaderKey::TF_has_texmat) { text << "\t texcoord" << i << " = mul(texmat_" << i << ", texcoord" << i << ");\n"; text << "\t texcoord" << i << ".xyz /= texcoord" << i << ".w;\n"; } } text << "\t // Fetch all textures.\n"; - if (_map_index_height >= 0 && parallax_mapping_samples > 0) { - Texture::TextureType type = texture->get_on_texture_type(texture->get_on_stage(_map_index_height)); - text << "\t float4 tex" << _map_index_height << " = tex" << texture_type_as_string(type); - text << "(tex_" << _map_index_height << ", texcoord" << _map_index_height << "."; - switch (type) { + for (size_t i = 0; i < key._textures.size(); ++i) { + const ShaderKey::TextureInfo &tex = key._textures[i]; + if ((tex._flags & ShaderKey::TF_map_height) == 0) { + continue; + } + + text << "\t float4 tex" << i << " = tex" << texture_type_as_string(tex._type); + text << "(tex_" << i << ", texcoord" << i << "."; + switch (tex._type) { case Texture::TT_cube_map: case Texture::TT_3d_texture: case Texture::TT_2d_texture_array: @@ -927,17 +950,19 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { default: break; } - text << ");\n\t float3 parallax_offset = l_eyevec.xyz * (tex" << _map_index_height; - if (_map_height_in_alpha) { + text << ");\n\t float3 parallax_offset = l_eyevec.xyz * (tex" << i; + if (tex._mode == TextureStage::M_normal_height || + (tex._flags & ShaderKey::TF_has_alpha) != 0) { text << ".aaa"; } else { text << ".rgb"; } text << " * 2.0 - 1.0) * " << parallax_mapping_scale << ";\n"; // Additional samples - for (int i=0; iget_on_texture_type(texture->get_on_stage(i)); + for (size_t i = 0; i < key._textures.size(); ++i) { + ShaderKey::TextureInfo &tex = key._textures[i]; + if ((tex._flags & ShaderKey::TF_map_height) == 0) { // Parallax mapping pushes the texture coordinates of the other textures // away from the camera. - if (_map_index_height >= 0 && parallax_mapping_samples > 0) { + if (key._texture_flags & ShaderKey::TF_map_height) { text << "\t texcoord" << i << ".xyz -= parallax_offset;\n"; } - text << "\t float4 tex" << i << " = tex" << texture_type_as_string(type); + text << "\t float4 tex" << i << " = tex" << texture_type_as_string(tex._type); text << "(tex_" << i << ", texcoord" << i << "."; - switch (type) { + switch (tex._type) { case Texture::TT_cube_map: case Texture::TT_3d_texture: case Texture::TT_2d_texture_array: @@ -973,108 +998,103 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << ");\n"; } } - if (_lighting || _out_aux_normal) { - if (_map_index_normal >= 0 && _auto_normal_on) { - text << "\t // Translate tangent-space normal in map to view-space.\n"; - text << "\t float3 tsnormal = ((float3)tex" << _map_index_normal << " * 2) - 1;\n"; - text << "\t l_eye_normal.xyz *= tsnormal.z;\n"; - text << "\t l_eye_normal.xyz += l_tangent * tsnormal.x;\n"; - text << "\t l_eye_normal.xyz += l_binormal * tsnormal.y;\n"; - } + if (key._texture_flags & ShaderKey::TF_map_normal) { + text << "\t // Translate tangent-space normal in map to view-space.\n"; + text << "\t float3 tsnormal = ((float3)tex" << map_index_normal << " * 2) - 1;\n"; + text << "\t l_eye_normal.xyz *= tsnormal.z;\n"; + text << "\t l_eye_normal.xyz += l_tangent * tsnormal.x;\n"; + text << "\t l_eye_normal.xyz += l_binormal * tsnormal.y;\n"; } - if (_need_eye_normal) { + if (need_eye_normal) { text << "\t // Correct the surface normal for interpolation effects\n"; text << "\t l_eye_normal.xyz = normalize(l_eye_normal.xyz);\n"; } - if (_out_aux_normal) { + if (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) { text << "\t // Output the camera-space surface normal\n"; text << "\t o_aux.rgb = (l_eye_normal.xyz*0.5) + float3(0.5,0.5,0.5);\n"; } - if (_lighting) { + if (key._lighting) { text << "\t // Begin view-space light calculations\n"; - text << "\t float ldist,lattenv,langle;\n"; + text << "\t float ldist,lattenv,langle,lshad;\n"; text << "\t float4 lcolor,lspec,lpoint,latten,ldir,leye;\n"; text << "\t float3 lvec,lhalf;\n"; - if (_shadows && _auto_shadow_on) { - text << "\t float lshad;\n"; + if (key._have_separate_ambient) { + text << "\t float4 tot_ambient = float4(0,0,0,0);\n"; } - if (_separate_ambient_diffuse) { - if (_have_ambient) { - text << "\t float4 tot_ambient = float4(0,0,0,0);\n"; - } - if (_have_diffuse) { - text << "\t float4 tot_diffuse = float4(0,0,0,0);\n"; - } - } else { - if (_have_ambient || _have_diffuse) { - text << "\t float4 tot_diffuse = float4(0,0,0,0);\n"; - } - } - if (_have_specular) { + text << "\t float4 tot_diffuse = float4(0,0,0,0);\n"; + if (have_specular) { text << "\t float4 tot_specular = float4(0,0,0,0);\n"; - if (_material_flags & Material::F_specular) { + if (key._material_flags & Material::F_specular) { text << "\t float shininess = attr_material[3].w;\n"; } else { text << "\t float shininess = 50; // no shininess specified, using default\n"; } } - if (_separate_ambient_diffuse && _have_ambient) { + if (key._have_separate_ambient) { text << "\t tot_ambient += attr_ambient;\n"; - } else if(_have_diffuse) { + } else { text << "\t tot_diffuse += attr_ambient;\n"; } } - for (size_t i = 0; i < _lights.size(); ++i) { - if (_lights[i]->is_of_type(DirectionalLight::get_class_type())) { + for (size_t i = 0; i < key._lights.size(); ++i) { + const ShaderKey::LightInfo &light = key._lights[i]; + if (light._type.is_derived_from(DirectionalLight::get_class_type())) { text << "\t // Directional Light " << i << "\n"; - text << "\t lcolor = dlight_light" << i << "_rel_view[0];\n"; - text << "\t lspec = dlight_light" << i << "_rel_view[1];\n"; - text << "\t lvec = dlight_light" << i << "_rel_view[2].xyz;\n"; + text << "\t lcolor = attr_light" << i << "[0];\n"; + if (light._flags & ShaderKey::LF_has_specular_color) { + text << "\t lspec = attr_lspec" << i << ";\n"; + } else { + text << "\t lspec = lcolor;\n"; + } + text << "\t lvec = attr_light" << i << "[3].xyz;\n"; text << "\t lcolor *= saturate(dot(l_eye_normal.xyz, lvec.xyz));\n"; - if (_shadows && _lights[i]->_shadow_caster && _auto_shadow_on) { + if (light._flags & ShaderKey::LF_has_shadows) { if (_use_shadow_filter) { - text << "\t lshad = shadow2DProj(shadow_light" << i << ", l_lightcoord" << i << ").r;\n"; + text << "\t lshad = shadow2DProj(shadow_" << i << ", l_lightcoord" << i << ").r;\n"; } else { - text << "\t lshad = tex2Dproj(shadow_light" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n"; + text << "\t lshad = tex2Dproj(shadow_" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n"; } text << "\t lcolor *= lshad;\n"; text << "\t lspec *= lshad;\n"; } - if (_have_diffuse) { - text << "\t tot_diffuse += lcolor;\n"; - } - if (_have_specular) { - if (_material_flags & Material::F_local) { + text << "\t tot_diffuse += lcolor;\n"; + if (have_specular) { + if (key._material_flags & Material::F_local) { text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n"; } else { - text << "\t lhalf = dlight_light" << i << "_rel_view[3].xyz;\n"; + text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n"; } text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf)), shininess);\n"; text << "\t tot_specular += lspec;\n"; } - } else if (_lights[i]->is_of_type(PointLight::get_class_type())) { + } else if (light._type.is_derived_from(PointLight::get_class_type())) { text << "\t // Point Light " << i << "\n"; - text << "\t lcolor = plight_light" << i << "_rel_view[0];\n"; - text << "\t lspec = plight_light" << i << "_rel_view[1];\n"; - text << "\t lpoint = plight_light" << i << "_rel_view[2];\n"; - text << "\t latten = plight_light" << i << "_rel_view[3];\n"; + text << "\t lcolor = attr_light" << i << "[0];\n"; + if (light._flags & ShaderKey::LF_has_specular_color) { + text << "\t lspec = attr_lspec" << i << ";\n"; + } else { + text << "\t lspec = lcolor;\n"; + } + text << "\t latten = attr_light" << i << "[1];\n"; + text << "\t lpoint = attr_light" << i << "[3];\n"; text << "\t lvec = lpoint.xyz - l_eye_position.xyz;\n"; text << "\t ldist = length(lvec);\n"; text << "\t lvec /= ldist;\n"; + if (light._type.is_derived_from(SphereLight::get_class_type())) { + text << "\t ldist = max(ldist, attr_light" << i << "[2].w);\n"; + } text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n"; text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec));\n"; - if (_shadows && _lights[i]->_shadow_caster && _auto_shadow_on) { + if (light._flags & ShaderKey::LF_has_shadows) { text << "\t ldist = max(abs(l_lightcoord" << i << ".x), max(abs(l_lightcoord" << i << ".y), abs(l_lightcoord" << i << ".z)));\n"; text << "\t ldist = ((latten.w+lpoint.w)/(latten.w-lpoint.w))+((-2*latten.w*lpoint.w)/(ldist * (latten.w-lpoint.w)));\n"; - text << "\t lshad = texCUBE(shadow_light" << i << ", l_lightcoord" << i << ".xyz).r >= ldist * 0.5 + 0.5;\n"; + text << "\t lshad = texCUBE(shadow_" << i << ", l_lightcoord" << i << ".xyz).r >= ldist * 0.5 + 0.5;\n"; text << "\t lcolor *= lshad;\n"; text << "\t lspec *= lshad;\n"; } - if (_have_diffuse) { - text << "\t tot_diffuse += lcolor;\n"; - } - if (_have_specular) { - if (_material_flags & Material::F_local) { + text << "\t tot_diffuse += lcolor;\n"; + if (have_specular) { + if (key._material_flags & Material::F_local) { text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n"; } else { text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n"; @@ -1083,13 +1103,17 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf)), shininess);\n"; text << "\t tot_specular += lspec;\n"; } - } else if (_lights[i]->is_of_type(Spotlight::get_class_type())) { + } else if (light._type.is_derived_from(Spotlight::get_class_type())) { text << "\t // Spot Light " << i << "\n"; - text << "\t lcolor = slight_light" << i << "_rel_view[0];\n"; - text << "\t lspec = slight_light" << i << "_rel_view[1];\n"; - text << "\t lpoint = slight_light" << i << "_rel_view[2];\n"; - text << "\t ldir = slight_light" << i << "_rel_view[3];\n"; - text << "\t latten = satten_light" << i << ";\n"; + text << "\t lcolor = attr_light" << i << "[0];\n"; + if (light._flags & ShaderKey::LF_has_specular_color) { + text << "\t lspec = attr_lspec" << i << ";\n"; + } else { + text << "\t lspec = lcolor;\n"; + } + text << "\t latten = attr_light" << i << "[1];\n"; + text << "\t ldir = attr_light" << i << "[2];\n"; + text << "\t lpoint = attr_light" << i << "[3];\n"; text << "\t lvec = lpoint.xyz - l_eye_position.xyz;\n"; text << "\t ldist = length(lvec);\n"; text << "\t lvec /= ldist;\n"; @@ -1098,21 +1122,19 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << "\t lattenv *= pow(langle, latten.w);\n"; text << "\t if (langle < ldir.w) lattenv = 0;\n"; text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec));\n"; - if (_shadows && _lights[i]->_shadow_caster && _auto_shadow_on) { + if (light._flags & ShaderKey::LF_has_shadows) { if (_use_shadow_filter) { - text << "\t lshad = shadow2DProj(shadow_light" << i << ", l_lightcoord" << i << ").r;\n"; + text << "\t lshad = shadow2DProj(shadow_" << i << ", l_lightcoord" << i << ").r;\n"; } else { - text << "\t lshad = tex2Dproj(shadow_light" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n"; + text << "\t lshad = tex2Dproj(shadow_" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n"; } text << "\t lcolor *= lshad;\n"; text << "\t lspec *= lshad;\n"; } - if (_have_diffuse) { - text << "\t tot_diffuse += lcolor;\n"; - } - if (_have_specular) { - if (_material_flags & Material::F_local) { + text << "\t tot_diffuse += lcolor;\n"; + if (have_specular) { + if (key._material_flags & Material::F_local) { text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n"; } else { text << "\t lhalf = normalize(lvec - float3(0,1,0));\n"; @@ -1123,14 +1145,13 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } } } - if (_lighting) { - const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot())); - if (_auto_ramp_on && _have_diffuse) { - switch (light_ramp->get_mode()) { + if (key._lighting) { + if (key._light_ramp != nullptr) { + switch (key._light_ramp->get_mode()) { case LightRampAttrib::LRT_single_threshold: { - PN_stdfloat t = light_ramp->get_threshold(0); - PN_stdfloat l0 = light_ramp->get_level(0); + PN_stdfloat t = key._light_ramp->get_threshold(0); + PN_stdfloat l0 = key._light_ramp->get_level(0); text << "\t // Single-threshold light ramp\n"; text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n"; text << "\t float lr_scale = (lr_in < " << t << ") ? 0.0 : (" << l0 << "/lr_in);\n"; @@ -1139,10 +1160,10 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } case LightRampAttrib::LRT_double_threshold: { - PN_stdfloat t0 = light_ramp->get_threshold(0); - PN_stdfloat t1 = light_ramp->get_threshold(1); - PN_stdfloat l0 = light_ramp->get_level(0); - PN_stdfloat l1 = light_ramp->get_level(1); + PN_stdfloat t0 = key._light_ramp->get_threshold(0); + PN_stdfloat t1 = key._light_ramp->get_threshold(1); + PN_stdfloat l0 = key._light_ramp->get_level(0); + PN_stdfloat l1 = key._light_ramp->get_level(1); text << "\t // Double-threshold light ramp\n"; text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n"; text << "\t float lr_out = 0.0;\n"; @@ -1156,61 +1177,60 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } } text << "\t // Begin view-space light summation\n"; - if (_have_emission) { - if (_map_index_glow >= 0 && _auto_glow_on) { - text << "\t result = attr_material[2] * saturate(2 * (tex" << _map_index_glow << ".a - 0.5));\n"; + if (key._material_flags & Material::F_emission) { + if (key._texture_flags & ShaderKey::TF_map_glow) { + text << "\t result = attr_material[2] * saturate(2 * (tex" << map_index_glow << ".a - 0.5));\n"; } else { text << "\t result = attr_material[2];\n"; } } else { - if (_map_index_glow >= 0 && _auto_glow_on) { - text << "\t result = saturate(2 * (tex" << _map_index_glow << ".a - 0.5));\n"; + if (key._texture_flags & ShaderKey::TF_map_glow) { + text << "\t result = saturate(2 * (tex" << map_index_glow << ".a - 0.5));\n"; } else { text << "\t result = float4(0,0,0,0);\n"; } } - if ((_have_ambient)&&(_separate_ambient_diffuse)) { - if (_material_flags & Material::F_ambient) { + if (key._have_separate_ambient) { + if (key._material_flags & Material::F_ambient) { text << "\t result += tot_ambient * attr_material[0];\n"; - } else if (_vertex_colors) { + } else if (key._color_type == ColorAttrib::T_vertex) { text << "\t result += tot_ambient * l_color;\n"; - } else if (_flat_colors) { + } else if (key._color_type == ColorAttrib::T_flat) { text << "\t result += tot_ambient * attr_color;\n"; } else { text << "\t result += tot_ambient;\n"; } } - if (_have_diffuse) { - if (_material_flags & Material::F_diffuse) { - text << "\t result += tot_diffuse * attr_material[1];\n"; - } else if (_vertex_colors) { - text << "\t result += tot_diffuse * l_color;\n"; - } else if (_flat_colors) { - text << "\t result += tot_diffuse * attr_color;\n"; - } else { - text << "\t result += tot_diffuse;\n"; - } + if (key._material_flags & Material::F_diffuse) { + text << "\t result += tot_diffuse * attr_material[1];\n"; + } else if (key._color_type == ColorAttrib::T_vertex) { + text << "\t result += tot_diffuse * l_color;\n"; + } else if (key._color_type == ColorAttrib::T_flat) { + text << "\t result += tot_diffuse * attr_color;\n"; + } else { + text << "\t result += tot_diffuse;\n"; } - if (light_ramp->get_mode() == LightRampAttrib::LRT_default) { + if (key._light_ramp == nullptr || + key._light_ramp->get_mode() == LightRampAttrib::LRT_default) { text << "\t result = saturate(result);\n"; } text << "\t // End view-space light calculations\n"; // Combine in alpha, which bypasses lighting calculations. Use of lerp // here is a workaround for a radeon driver bug. - if (_calc_primary_alpha) { - if (_vertex_colors) { + if (key._calc_primary_alpha) { + if (key._color_type == ColorAttrib::T_vertex) { text << "\t result.a = l_color.a;\n"; - } else if (_flat_colors) { + } else if (key._color_type == ColorAttrib::T_flat) { text << "\t result.a = attr_color.a;\n"; } else { text << "\t result.a = 1;\n"; } } } else { - if (_vertex_colors) { + if (key._color_type == ColorAttrib::T_vertex) { text << "\t result = l_color;\n"; - } else if (_flat_colors) { + } else if (key._color_type == ColorAttrib::T_flat) { text << "\t result = attr_color;\n"; } else { text << "\t result = float4(1, 1, 1, 1);\n"; @@ -1221,35 +1241,36 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { // last_saved_result. bool have_saved_result = false; bool have_primary_color = false; - for (int i=0; i<_num_textures; i++) { - TextureStage *stage = texture->get_on_stage(i); - if (stage->get_mode() != TextureStage::M_combine) continue; - if (stage->uses_primary_color() && !have_primary_color) { + for (size_t i = 0; i < key._textures.size(); ++i) { + const ShaderKey::TextureInfo &tex = key._textures[i]; + if (tex._stage == nullptr) { + continue; + } + + if (tex._stage->uses_primary_color() && !have_primary_color) { text << "\t float4 primary_color = result;\n"; have_primary_color = true; } - if (stage->uses_last_saved_result() && !have_saved_result) { + if (tex._stage->uses_last_saved_result() && !have_saved_result) { text << "\t float4 last_saved_result = result;\n"; have_saved_result = true; } } // Now loop through the textures to compose our magic blending formulas. - for (int i = 0; i < _num_textures; ++i) { - TextureStage *stage = texture->get_on_stage(i); - switch (stage->get_mode()) { - case TextureStage::M_modulate: { - bool affects_rgb = texture->on_stage_affects_rgb(i); - bool affects_alpha = texture->on_stage_affects_alpha(i); - - if (affects_rgb && affects_alpha) { + for (size_t i = 0; i < key._textures.size(); ++i) { + const ShaderKey::TextureInfo &tex = key._textures[i]; + switch (tex._mode) { + case TextureStage::M_modulate: + if ((tex._flags & ShaderKey::TF_has_rgb) != 0 && + (tex._flags & ShaderKey::TF_has_alpha) != 0) { text << "\t result.rgba *= tex" << i << ".rgba;\n"; - } else if (affects_alpha) { + } else if (tex._flags & ShaderKey::TF_has_alpha) { text << "\t result.a *= tex" << i << ".a;\n"; - } else if (affects_rgb) { + } else if (tex._flags & ShaderKey::TF_has_rgb) { text << "\t result.rgb *= tex" << i << ".rgb;\n"; } - break; } + break; case TextureStage::M_modulate_glow: case TextureStage::M_modulate_gloss: // in the case of glow or spec we currently see the specularity evenly @@ -1262,38 +1283,37 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { case TextureStage::M_decal: text << "\t result.rgb = lerp(result, tex" << i << ", tex" << i << ".a).rgb;\n"; break; - case TextureStage::M_blend: { - LVecBase4 c = stage->get_color(); - text << "\t result.rgb = lerp(result, tex" << i << " * float4(" - << c[0] << ", " << c[1] << ", " << c[2] << ", " << c[3] << "), tex" << i << ".r).rgb;\n"; - break; } + case TextureStage::M_blend: + text << "\t result.rgb = lerp(result, tex" << i << " * texcolor_" << i << ", tex" << i << ".r).rgb;\n"; + break; case TextureStage::M_replace: text << "\t result = tex" << i << ";\n"; break; case TextureStage::M_add: text << "\t result.rgb += tex" << i << ".rgb;\n"; - if (_calc_primary_alpha) { + if (key._calc_primary_alpha) { text << "\t result.a *= tex" << i << ".a;\n"; } break; case TextureStage::M_combine: + // Only in the case of M_combine have we filled in the _stage pointer. text << "\t result.rgb = "; - if (stage->get_combine_rgb_mode() != TextureStage::CM_undefined) { - text << combine_mode_as_string(stage, stage->get_combine_rgb_mode(), false, i); + if (tex._stage->get_combine_rgb_mode() != TextureStage::CM_undefined) { + text << combine_mode_as_string(tex._stage, tex._stage->get_combine_rgb_mode(), false, i); } else { text << "tex" << i << ".rgb"; } - if (stage->get_rgb_scale() != 1) { - text << " * " << stage->get_rgb_scale(); + if (tex._stage->get_rgb_scale() != 1) { + text << " * " << tex._stage->get_rgb_scale(); } text << ";\n\t result.a = "; - if (stage->get_combine_alpha_mode() != TextureStage::CM_undefined) { - text << combine_mode_as_string(stage, stage->get_combine_alpha_mode(), true, i); + if (tex._stage->get_combine_alpha_mode() != TextureStage::CM_undefined) { + text << combine_mode_as_string(tex._stage, tex._stage->get_combine_alpha_mode(), true, i); } else { text << "tex" << i << ".a"; } - if (stage->get_alpha_scale() != 1) { - text << " * " << stage->get_alpha_scale(); + if (tex._stage->get_alpha_scale() != 1) { + text << " * " << tex._stage->get_alpha_scale(); } text << ";\n"; break; @@ -1303,18 +1323,17 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { default: break; } - if (stage->get_saved_result() && have_saved_result) { + if ((tex._flags & ShaderKey::TF_saved_result) != 0 && have_saved_result) { text << "\t last_saved_result = result;\n"; } } // Apply the color scale. text << "\t result *= attr_colorscale;\n"; - if (_subsume_alpha_test) { - const AlphaTestAttrib *alpha_test = DCAST(AlphaTestAttrib, rs->get_attrib_def(AlphaTestAttrib::get_class_slot())); + if (key._alpha_test_mode != RenderAttrib::M_none) { text << "\t // Shader includes alpha test:\n"; - double ref = alpha_test->get_reference_alpha(); - switch (alpha_test->get_mode()) { + double ref = key._alpha_test_ref; + switch (key._alpha_test_mode) { case RenderAttrib::M_never: text << "\t discard;\n"; break; @@ -1338,40 +1357,36 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { break; case RenderAttrib::M_none: case RenderAttrib::M_always: - default: break; } } - if (_out_primary_glow) { - if (_map_index_glow >= 0 && _auto_glow_on) { - text << "\t result.a = tex" << _map_index_glow << ".a;\n"; + if (key._outputs & AuxBitplaneAttrib::ABO_glow) { + if (key._texture_flags & ShaderKey::TF_map_glow) { + text << "\t result.a = tex" << map_index_glow << ".a;\n"; } else { text << "\t result.a = 0.5;\n"; } } - if (_out_aux_glow) { - if (_map_index_glow >= 0 && _auto_glow_on) { - text << "\t o_aux.a = tex" << _map_index_glow << ".a;\n"; + if (key._outputs & AuxBitplaneAttrib::ABO_aux_glow) { + if (key._texture_flags & ShaderKey::TF_map_glow) { + text << "\t o_aux.a = tex" << map_index_glow << ".a;\n"; } else { text << "\t o_aux.a = 0.5;\n"; } } - if (_lighting) { - if (_have_specular) { - if (_material_flags & Material::F_specular) { - text << "\t tot_specular *= attr_material[3];\n"; - } - if (_map_index_gloss >= 0 && _auto_gloss_on) { - text << "\t tot_specular *= tex" << _map_index_gloss << ".a;\n"; - } - text << "\t result.rgb = result.rgb + tot_specular.rgb;\n"; + if (have_specular) { + if (key._material_flags & Material::F_specular) { + text << "\t tot_specular *= attr_material[3];\n"; } + if (key._texture_flags & ShaderKey::TF_map_gloss) { + text << "\t tot_specular *= tex" << map_index_gloss << ".a;\n"; + } + text << "\t result.rgb = result.rgb + tot_specular.rgb;\n"; } - if (_auto_ramp_on) { - const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot())); - switch (light_ramp->get_mode()) { + if (key._light_ramp != nullptr) { + switch (key._light_ramp->get_mode()) { case LightRampAttrib::LRT_hdr0: text << "\t result.rgb = (result*result*result + result*result + result) / (result*result*result + result*result + result + 1);\n"; break; @@ -1386,11 +1401,9 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } // Apply fog. - if (_fog) { - const FogAttrib *fog_attr = DCAST(FogAttrib, rs->get_attrib_def(FogAttrib::get_class_slot())); - Fog *fog = fog_attr->get_fog(); - - switch (fog->get_mode()) { + if (key._fog_mode != 0) { + Fog::Mode fog_mode = (Fog::Mode)(key._fog_mode - 1); + switch (fog_mode) { case Fog::M_linear: text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate((attr_fog.z - l_hpos.z) * attr_fog.w));\n"; break; @@ -1406,25 +1419,31 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { // The multiply is a workaround for a radeon driver bug. It's annoying as // heck, since it produces an extra instruction. text << "\t o_color = result * 1.000001;\n"; - if (_subsume_alpha_test) { + if (key._alpha_test_mode != RenderAttrib::M_none) { text << "\t // Shader subsumes normal alpha test.\n"; } - if (_disable_alpha_write) { + if (key._disable_alpha_write) { text << "\t // Shader disables alpha write.\n"; } text << "}\n"; // Insert the shader into the shader attrib. - CPT(RenderAttrib) shattr = create_shader_attrib(text.str()); - if (_subsume_alpha_test) { + PT(Shader) shader = Shader::make(text.str(), Shader::SL_Cg); + nassertr(shader != nullptr, nullptr); + + CPT(RenderAttrib) shattr = ShaderAttrib::make(shader); + if (key._alpha_test_mode != RenderAttrib::M_none) { shattr = DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_subsume_alpha_test, true); } - if (_disable_alpha_write) { + if (key._disable_alpha_write) { shattr = DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_disable_alpha_write, true); } - clear_analysis(); + reset_register_allocator(); - return DCAST(ShaderAttrib, shattr); + + CPT(ShaderAttrib) attr = DCAST(ShaderAttrib, shattr); + _generated_shaders[key] = attr; + return attr; } /** @@ -1592,4 +1611,165 @@ texture_type_as_string(Texture::TextureType ttype) { } } +/** + * Initializes the ShaderKey to the empty state. + */ +ShaderGenerator::ShaderKey:: +ShaderKey() : + _color_type(ColorAttrib::T_vertex), + _material_flags(0), + _texture_flags(0), + _lighting(false), + _have_separate_ambient(false), + _fog_mode(0), + _outputs(0), + _calc_primary_alpha(false), + _disable_alpha_write(false), + _alpha_test_mode(RenderAttrib::M_none), + _alpha_test_ref(0.0), + _num_clip_planes(0), + _light_ramp(nullptr) { +} + +/** + * Returns true if this ShaderKey sorts less than the other one. This is an + * arbitrary, but consistent ordering. + */ +bool ShaderGenerator::ShaderKey:: +operator < (const ShaderKey &other) const { + if (_anim_spec != other._anim_spec) { + return _anim_spec < other._anim_spec; + } + if (_color_type != other._color_type) { + return _color_type < other._color_type; + } + if (_material_flags != other._material_flags) { + return _material_flags < other._material_flags; + } + if (_texture_flags != other._texture_flags) { + return _texture_flags < other._texture_flags; + } + if (_textures.size() != other._textures.size()) { + return _textures.size() < other._textures.size(); + } + for (size_t i = 0; i < _textures.size(); ++i) { + const ShaderKey::TextureInfo &tex = _textures[i]; + const ShaderKey::TextureInfo &other_tex = other._textures[i]; + if (tex._texcoord_name != other_tex._texcoord_name) { + return tex._texcoord_name < other_tex._texcoord_name; + } + if (tex._type != other_tex._type) { + return tex._type < other_tex._type; + } + if (tex._mode != other_tex._mode) { + return tex._mode < other_tex._mode; + } + if (tex._gen_mode != other_tex._gen_mode) { + return tex._gen_mode < other_tex._gen_mode; + } + if (tex._flags != other_tex._flags) { + return tex._flags < other_tex._flags; + } + if (tex._stage != other_tex._stage) { + return tex._stage < other_tex._stage; + } + } + if (_lights.size() != other._lights.size()) { + return _lights.size() < other._lights.size(); + } + for (size_t i = 0; i < _lights.size(); ++i) { + const ShaderKey::LightInfo &light = _lights[i]; + const ShaderKey::LightInfo &other_light = other._lights[i]; + if (light._type != other_light._type) { + return light._type < other_light._type; + } + if (light._flags != other_light._flags) { + return light._flags < other_light._flags; + } + } + if (_lighting != other._lighting) { + return _lighting < other._lighting; + } + if (_have_separate_ambient != other._have_separate_ambient) { + return _have_separate_ambient < other._have_separate_ambient; + } + if (_fog_mode != other._fog_mode) { + return _fog_mode < other._fog_mode; + } + if (_outputs != other._outputs) { + return _outputs < other._outputs; + } + if (_calc_primary_alpha != other._calc_primary_alpha) { + return _calc_primary_alpha < other._calc_primary_alpha; + } + if (_disable_alpha_write != other._disable_alpha_write) { + return _disable_alpha_write < other._disable_alpha_write; + } + if (_alpha_test_mode != other._alpha_test_mode) { + return _alpha_test_mode < other._alpha_test_mode; + } + if (_alpha_test_ref != other._alpha_test_ref) { + return _alpha_test_ref < other._alpha_test_ref; + } + if (_num_clip_planes != other._num_clip_planes) { + return _num_clip_planes < other._num_clip_planes; + } + return _light_ramp < other._light_ramp; +} + +/** + * Returns true if this ShaderKey is equal to the other one. + */ +bool ShaderGenerator::ShaderKey:: +operator == (const ShaderKey &other) const { + if (_anim_spec != other._anim_spec) { + return false; + } + if (_color_type != other._color_type) { + return false; + } + if (_material_flags != other._material_flags) { + return false; + } + if (_texture_flags != other._texture_flags) { + return false; + } + if (_textures.size() != other._textures.size()) { + return false; + } + for (size_t i = 0; i < _textures.size(); ++i) { + const ShaderKey::TextureInfo &tex = _textures[i]; + const ShaderKey::TextureInfo &other_tex = other._textures[i]; + if (tex._texcoord_name != other_tex._texcoord_name || + tex._type != other_tex._type || + tex._mode != other_tex._mode || + tex._gen_mode != other_tex._gen_mode || + tex._flags != other_tex._flags || + tex._stage != other_tex._stage) { + return false; + } + } + if (_lights.size() != other._lights.size()) { + return false; + } + for (size_t i = 0; i < _lights.size(); ++i) { + const ShaderKey::LightInfo &light = _lights[i]; + const ShaderKey::LightInfo &other_light = other._lights[i]; + if (light._type != other_light._type || + light._flags != other_light._flags) { + return false; + } + } + return _lighting == other._lighting + && _have_separate_ambient == other._have_separate_ambient + && _fog_mode == other._fog_mode + && _outputs == other._outputs + && _calc_primary_alpha == other._calc_primary_alpha + && _disable_alpha_write == other._disable_alpha_write + && _alpha_test_mode == other._alpha_test_mode + && _alpha_test_ref == other._alpha_test_ref + && _num_clip_planes == other._num_clip_planes + && _light_ramp == other._light_ramp; +} + #endif // HAVE_CG diff --git a/panda/src/pgraphnodes/shaderGenerator.h b/panda/src/pgraphnodes/shaderGenerator.h index 9042291631..ba2619bef7 100644 --- a/panda/src/pgraphnodes/shaderGenerator.h +++ b/panda/src/pgraphnodes/shaderGenerator.h @@ -28,6 +28,11 @@ #include "renderState.h" #include "renderAttrib.h" +#include "colorAttrib.h" +#include "lightRampAttrib.h" +#include "texGenAttrib.h" +#include "textureAttrib.h" + class AmbientLight; class DirectionalLight; class PointLight; @@ -66,7 +71,6 @@ PUBLISHED: const GeomVertexAnimationSpec &anim); protected: - CPT(RenderAttrib) create_shader_attrib(const string &txt); static const string combine_mode_as_string(CPT(TextureStage) stage, TextureStage::CombineMode c_mode, bool alpha, short texindex); static const string combine_source_as_string(CPT(TextureStage) stage, @@ -84,66 +88,76 @@ protected: const char *alloc_vreg(); const char *alloc_freg(); + bool _use_shadow_filter; + // RenderState analysis information. Created by analyze_renderstate: CPT(RenderState) _state; - int _material_flags; - int _num_textures; + struct ShaderKey { + ShaderKey(); + bool operator < (const ShaderKey &other) const; + bool operator == (const ShaderKey &other) const; + bool operator != (const ShaderKey &other) const { return !operator ==(other); } - pvector _lights; - pvector _lights_np; + GeomVertexAnimationSpec _anim_spec; + enum TextureFlags { + TF_has_rgb = 1, + TF_has_alpha = 2, + TF_has_texscale = 4, + TF_has_texmat = 8, + TF_saved_result = 16, + TF_map_normal = 32, + TF_map_height = 64, + TF_map_glow = 128, + TF_map_gloss = 256, + }; - bool _vertex_colors; - bool _flat_colors; + ColorAttrib::Type _color_type; + int _material_flags; + int _texture_flags; - bool _lighting; - bool _shadows; - bool _fog; + struct TextureInfo { + CPT_InternalName _texcoord_name; + Texture::TextureType _type; + TextureStage::Mode _mode; + TexGenAttrib::Mode _gen_mode; + int _flags; - bool _have_ambient; - bool _have_diffuse; - bool _have_emission; - bool _have_specular; + // Stored only if combine modes / blend color is used + CPT(TextureStage) _stage; + }; + pvector _textures; - bool _separate_ambient_diffuse; + enum LightFlags { + LF_has_shadows = 1, + LF_has_specular_color = 2, + }; - int _map_index_normal; - int _map_index_height; - int _map_index_glow; - int _map_index_gloss; - bool _map_height_in_alpha; + struct LightInfo { + TypeHandle _type; + int _flags; + }; + pvector _lights; + bool _lighting; + bool _have_separate_ambient; - bool _out_primary_glow; - bool _out_aux_normal; - bool _out_aux_glow; - bool _out_aux_any; + int _fog_mode; - bool _have_alpha_test; - bool _have_alpha_blend; - bool _calc_primary_alpha; - bool _subsume_alpha_test; - bool _disable_alpha_write; + int _outputs; + bool _calc_primary_alpha; + bool _disable_alpha_write; + RenderAttrib::PandaCompareFunc _alpha_test_mode; + PN_stdfloat _alpha_test_ref; - int _num_clip_planes; - bool _use_shadow_filter; + int _num_clip_planes; - bool _need_material_props; - bool _need_world_position; - bool _need_world_normal; - bool _need_eye_position; - bool _need_eye_normal; - bool _normalize_normals; - bool _auto_normal_on; - bool _auto_glow_on; - bool _auto_gloss_on; - bool _auto_ramp_on; - bool _auto_shadow_on; + CPT(LightRampAttrib) _light_ramp; + }; - void analyze_renderstate(const RenderState *rs); - void clear_analysis(); + typedef phash_map GeneratedShaders; + GeneratedShaders _generated_shaders; - // This is not a PT() to prevent a circular reference. - GraphicsStateGuardianBase *_gsg; + void analyze_renderstate(ShaderKey &key, const RenderState *rs); public: static TypeHandle get_class_type() { diff --git a/panda/src/pgraphnodes/spotlight.cxx b/panda/src/pgraphnodes/spotlight.cxx index badf4544d9..99432a904b 100644 --- a/panda/src/pgraphnodes/spotlight.cxx +++ b/panda/src/pgraphnodes/spotlight.cxx @@ -65,9 +65,7 @@ fillin(DatagramIterator &scan, BamReader *manager) { */ Spotlight:: Spotlight(const string &name) : - LightLensNode(name), - _has_specular_color(false) -{ + LightLensNode(name) { _lenses[0]._lens->set_interocular_distance(0); } @@ -78,7 +76,6 @@ Spotlight(const string &name) : Spotlight:: Spotlight(const Spotlight ©) : LightLensNode(copy), - _has_specular_color(copy._has_specular_color), _cycler(copy._cycler) { } diff --git a/panda/src/pgraphnodes/spotlight.h b/panda/src/pgraphnodes/spotlight.h index 6cc175fe61..c9a6962b07 100644 --- a/panda/src/pgraphnodes/spotlight.h +++ b/panda/src/pgraphnodes/spotlight.h @@ -79,8 +79,6 @@ private: CPT(RenderState) get_viz_state(); private: - bool _has_specular_color; - // This is the data that must be cycled between pipeline stages. class EXPCL_PANDA_PGRAPHNODES CData : public CycleData { public: diff --git a/panda/src/pstatclient/pStatProperties.cxx b/panda/src/pstatclient/pStatProperties.cxx index 7b14891daa..25d2bfd591 100644 --- a/panda/src/pstatclient/pStatProperties.cxx +++ b/panda/src/pstatclient/pStatProperties.cxx @@ -119,7 +119,7 @@ static TimeCollectorProperties time_properties[] = { { 1, "Cull:Sort", { 0.3, 0.3, 0.6 } }, { 1, "*", { 0.1, 0.1, 0.5 } }, { 1, "*:Show fps", { 0.5, 0.8, 1.0 } }, - { 0, "*:Munge", { 0.3, 0.3, 0.9 } }, + { 1, "*:Munge", { 0.3, 0.3, 0.9 } }, { 1, "*:Munge:Geom", { 0.4, 0.2, 0.8 } }, { 1, "*:Munge:Sprites", { 0.2, 0.8, 0.4 } }, { 0, "*:Munge:Data", { 0.7, 0.5, 0.2 } },