From 557abfae5ed12a73c71b3431c8f4009f82dea5bc Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 2 Jun 2009 15:21:36 +0000 Subject: [PATCH] Fixes for this circular dependency mess --- panda/src/display/graphicsOutput.h | 2 +- panda/src/display/graphicsStateGuardian.cxx | 59 +++++++++++++++++++ panda/src/display/graphicsStateGuardian.h | 2 + panda/src/gsgbase/graphicsOutputBase.h | 3 + panda/src/gsgbase/graphicsStateGuardianBase.h | 5 ++ panda/src/pgraphnodes/lightLensNode.h | 2 + panda/src/pgraphnodes/shaderGenerator.cxx | 48 ++------------- 7 files changed, 78 insertions(+), 43 deletions(-) diff --git a/panda/src/display/graphicsOutput.h b/panda/src/display/graphicsOutput.h index 4936805256..77fc12147a 100644 --- a/panda/src/display/graphicsOutput.h +++ b/panda/src/display/graphicsOutput.h @@ -99,7 +99,7 @@ PUBLISHED: INLINE int count_textures() const; INLINE bool has_texture() const; - INLINE Texture *get_texture(int i=0) const; + virtual INLINE Texture *get_texture(int i=0) const; INLINE RenderTexturePlane get_texture_plane(int i=0) const; INLINE RenderTextureMode get_rtm_mode(int i=0) const; void clear_render_textures(); diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 2cb936caff..3de5f18e54 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -47,6 +47,7 @@ #include "lightAttrib.h" #include "texGenAttrib.h" #include "shaderGenerator.h" +#include "lightLensNode.h" #include #include @@ -2541,3 +2542,61 @@ async_reload_texture(TextureContext *tc) { request->set_priority(priority); _loader->load_async(request); } + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::make_shadow_buffer +// Access: Protected +// Description: Creates a depth buffer for shadow mapping. This +// is a convenience function for the ShaderGenerator; +// putting this directly in the ShaderGenerator would +// cause circular dependency issues. +// Returns the depth texture. +//////////////////////////////////////////////////////////////////// +PT(Texture) GraphicsStateGuardian:: +make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) { + // Make sure everything is valid. + nassertr(light_np.node()->is_of_type(DirectionalLight::get_class_type()) || + light_np.node()->is_of_type(Spotlight::get_class_type()), NULL); + PT(LightLensNode) light = DCAST(LightLensNode, light_np.node()); + if (light == NULL || !light->_shadow_caster) { + return NULL; + } + + nassertr(light->_sbuffers.count(this) == 0, NULL); + + display_cat.debug() << "Constructing shadow buffer for light '" << light->get_name() + << "', size=" << light->_sb_xsize << "x" << light->_sb_ysize + << ", sort=" << light->_sb_sort << "\n"; + FrameBufferProperties fbp; + fbp.set_depth_bits(1); // We only need depth + PT(GraphicsOutput) sbuffer = get_engine()->make_output(get_pipe(), light->get_name(), + light->_sb_sort, fbp, WindowProperties::size(light->_sb_xsize, light->_sb_ysize), + GraphicsPipe::BF_refuse_window, this, DCAST(GraphicsOutput, host)); + nassertr(sbuffer != NULL, NULL); + + // Create a texture and fill it in with some data to workaround an OpenGL error + PT(Texture) tex = new Texture(light->get_name()); + tex->setup_2d_texture(light->_sb_xsize, light->_sb_ysize, Texture::T_float, Texture::F_depth_stencil); + tex->make_ram_image(); + sbuffer->add_render_texture(tex, GraphicsOutput::RTM_bind_or_copy, + GraphicsOutput::RTP_depth_stencil); + // Set the wrap mode to BORDER_COLOR + tex->set_wrap_u(Texture::WM_border_color); + tex->set_wrap_v(Texture::WM_border_color); + tex->set_border_color(LVecBase4f(1, 1, 1, 1)); + + if (get_supports_shadow_filter()) { + // If we have the ARB_shadow extension, enable shadow filtering. + tex->set_minfilter(Texture::FT_shadow); + tex->set_magfilter(Texture::FT_shadow); + } else { + // We only accept linear - this tells the GPU to use hardware PCF. + tex->set_minfilter(Texture::FT_linear); + tex->set_magfilter(Texture::FT_linear); + } + sbuffer->make_display_region(0, 1, 0, 1)->set_camera(light_np); + light->_sbuffers[this] = sbuffer; + + return tex; +} + diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index ca70ec4798..77445bedbc 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -302,6 +302,8 @@ public: static void create_gamma_table (float gamma, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table); + virtual PT(Texture) make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host); + #ifdef DO_PSTATS static void init_frame_pstats(); #endif diff --git a/panda/src/gsgbase/graphicsOutputBase.h b/panda/src/gsgbase/graphicsOutputBase.h index 40ade50dcc..968b17d5a6 100644 --- a/panda/src/gsgbase/graphicsOutputBase.h +++ b/panda/src/gsgbase/graphicsOutputBase.h @@ -18,6 +18,8 @@ #include "pandabase.h" #include "typedWritableReferenceCount.h" +class Texture; + //////////////////////////////////////////////////////////////////// // Class : GraphicsOutputBase // Description : An abstract base class for GraphicsOutput, for all @@ -26,6 +28,7 @@ class EXPCL_PANDA_GSGBASE GraphicsOutputBase : public TypedWritableReferenceCount { PUBLISHED: virtual void set_sort(int sort)=0; + virtual Texture *get_texture(int i=0) const=0; public: static TypeHandle get_class_type() { diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index fd45d86ffd..83b66ff658 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -87,6 +87,7 @@ class PointLight; class DirectionalLight; class Spotlight; class AmbientLight; +class LightLensNode; class DisplayRegion; class Lens; @@ -219,6 +220,10 @@ public: virtual void bind_light(Spotlight *light_obj, const NodePath &light, int light_id) { } + // This function creates a shadow mapping buffer. This is not put in ShaderGenerator + // because that would cause circular dependencies. + virtual PT(Texture) make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host)=0; + PUBLISHED: static GraphicsStateGuardianBase *get_default_gsg(); static void set_default_gsg(GraphicsStateGuardianBase *default_gsg); diff --git a/panda/src/pgraphnodes/lightLensNode.h b/panda/src/pgraphnodes/lightLensNode.h index 0951422dac..6b787cce77 100644 --- a/panda/src/pgraphnodes/lightLensNode.h +++ b/panda/src/pgraphnodes/lightLensNode.h @@ -23,6 +23,7 @@ #include "graphicsOutputBase.h" class ShaderGenerator; +class GraphicsStateGuardian; //////////////////////////////////////////////////////////////////// // Class : LightLensNode @@ -88,6 +89,7 @@ public: private: static TypeHandle _type_handle; + friend class GraphicsStateGuardian; friend class ShaderGenerator; }; diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index 27d9529bbc..3b9590c232 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/panda/src/pgraphnodes/shaderGenerator.cxx @@ -475,53 +475,17 @@ update_shadow_buffer(NodePath light_np) { if (light == NULL || !light->_shadow_caster) { return NULL; } - + // See if we already have a buffer. If not, create one. - PT(GraphicsOutput) sbuffer; PT(Texture) tex; - if (light->_sbuffers.count(DCAST(GraphicsStateGuardianBase, _gsg)) == 0) { - - // Nope, the light doesn't have a buffer for our GSG. - FrameBufferProperties fbp; - fbp.set_depth_bits(1); // We only need depth - pgraph_cat.debug() << "Constructing shadow buffer for light '" << light->get_name() - << "', size=" << light->_sb_xsize << "x" << light->_sb_ysize - << ", sort=" << light->_sb_sort << "\n"; - sbuffer = _gsg->get_engine()->make_output(_gsg->get_pipe(), light->get_name(), - light->_sb_sort, fbp, WindowProperties::size(light->_sb_xsize, light->_sb_ysize), - GraphicsPipe::BF_refuse_window, _gsg, _host); - nassertr(sbuffer != NULL, NULL); - - // Create a texture and fill it in with some data to workaround an OpenGL error - tex = new Texture(light->get_name()); - tex->setup_2d_texture(light->_sb_xsize, light->_sb_ysize, Texture::T_float, Texture::F_depth_stencil); - tex->make_ram_image(); - sbuffer->add_render_texture(tex, GraphicsOutput::RTM_bind_or_copy, - DrawableRegion::RTP_depth_stencil); - // Set the wrap mode to BORDER_COLOR - tex->set_wrap_u(Texture::WM_border_color); - tex->set_wrap_v(Texture::WM_border_color); - tex->set_border_color(LVecBase4f(1, 1, 1, 1)); - - if (_use_shadow_filter) { - // If we have the ARB_shadow extension, enable shadow filtering. - tex->set_minfilter(Texture::FT_shadow); - tex->set_magfilter(Texture::FT_shadow); - } else { - // We only accept linear - this tells the GPU to use hardware PCF. - tex->set_minfilter(Texture::FT_linear); - tex->set_magfilter(Texture::FT_linear); - } - sbuffer->make_display_region(0, 1, 0, 1)->set_camera(light_np); - light->_sbuffers[DCAST(GraphicsStateGuardianBase, _gsg)] = DCAST(GraphicsOutputBase, sbuffer); - + if (light->_sbuffers.count(_gsg) == 0) { + // Nope, the light doesn't have a buffer for our GSG. Make one. + tex = _gsg->make_shadow_buffer(light_np, _host); } else { - // There's already a buffer - use that. - sbuffer = DCAST(GraphicsOutput, light->_sbuffers[DCAST(GraphicsStateGuardianBase, _gsg)]); - tex = sbuffer->get_texture(); - nassertr(tex != NULL, NULL); + tex = light->_sbuffers[_gsg]->get_texture(); } + nassertr(tex != NULL, NULL); return tex; }