2
0
Эх сурвалжийг харах

Fixes for this circular dependency mess

rdb 16 жил өмнө
parent
commit
557abfae5e

+ 1 - 1
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();

+ 59 - 0
panda/src/display/graphicsStateGuardian.cxx

@@ -47,6 +47,7 @@
 #include "lightAttrib.h"
 #include "texGenAttrib.h"
 #include "shaderGenerator.h"
+#include "lightLensNode.h"
 
 #include <algorithm>
 #include <limits.h>
@@ -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;
+}
+

+ 2 - 0
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

+ 3 - 0
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() {

+ 5 - 0
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);

+ 2 - 0
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;
 };
 

+ 6 - 42
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;
 }