From 0400248b3770a397c04cd67e6f9f310e777d6743 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Tue, 1 Nov 2005 04:30:22 +0000 Subject: [PATCH] Added support for shadow maps + shaders --- direct/src/showbase/ShowBase.py | 20 ++++- panda/src/display/graphicsOutput.cxx | 4 +- panda/src/display/graphicsStateGuardian.I | 22 ++++++ panda/src/display/graphicsStateGuardian.cxx | 3 +- panda/src/display/graphicsStateGuardian.h | 8 +- .../glstuff/glGraphicsStateGuardian_src.cxx | 33 +++++++- panda/src/glstuff/glShaderContext_src.cxx | 78 ++++++++++++++++++- panda/src/glstuff/glShaderContext_src.h | 7 +- panda/src/gobj/texture.cxx | 6 +- panda/src/gobj/texture.h | 3 + 10 files changed, 165 insertions(+), 19 deletions(-) diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index e40ebb8518..f140b6619e 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -64,7 +64,7 @@ class ShowBase(DirectObject.DirectObject): self.sfxActive = self.config.GetBool('audio-sfx-active', 1) self.musicActive = self.config.GetBool('audio-music-active', 1) self.wantFog = self.config.GetBool('want-fog', 1) - self.wantRender2dp = self.config.GetBool('want-render2dp', 0) + self.wantRender2dp = self.config.GetBool('want-render2dp', 1) self.screenshotExtension = self.config.GetString('screenshot-extension', 'jpg') self.musicManager = None @@ -117,12 +117,14 @@ class ShowBase(DirectObject.DirectObject): self.drive = None self.trackball = None self.cam = None - self.camList = [] - self.camNode = None - self.camLens = None + self.cam2d = None + self.cam2dp = None self.camera = None self.camera2d = None self.camera2dp = None + self.camList = [] + self.camNode = None + self.camLens = None self.camFrustumVis = None # This is used for syncing multiple PCs in a distributed cluster @@ -458,6 +460,10 @@ class ShowBase(DirectObject.DirectObject): # preserve it for reopening the window. if cam == self.cam: self.cam = None + if cam == self.cam2d: + self.cam2d = None + if cam == self.cam2dp: + self.cam2dp = None cam.removeNode() # Now we can actually close the window. @@ -813,6 +819,9 @@ class ShowBase(DirectObject.DirectObject): camera2d = self.camera2d.attachNewNode(cam2dNode) dr.setCamera(camera2d) + if self.cam2d == None: + self.cam2d = camera2d + return camera2d def makeCamera2dp(self, win, sort = 20, @@ -847,6 +856,9 @@ class ShowBase(DirectObject.DirectObject): camera2dp = self.camera2dp.attachNewNode(cam2dNode) dr.setCamera(camera2dp) + if self.cam2dp == None: + self.cam2dp = camera2dp + return camera2dp diff --git a/panda/src/display/graphicsOutput.cxx b/panda/src/display/graphicsOutput.cxx index 25d13d7500..93e4779798 100644 --- a/panda/src/display/graphicsOutput.cxx +++ b/panda/src/display/graphicsOutput.cxx @@ -520,7 +520,7 @@ create_texture_card_vdata(int x, int y) float xhi = (x * 1.0f) / xru; float yhi = (y * 1.0f) / yru; - CPT(GeomVertexFormat) format = GeomVertexFormat::get_v3n3cpt2(); + CPT(GeomVertexFormat) format = GeomVertexFormat::get_v3n3t2(); PT(GeomVertexData) vdata = new GeomVertexData ("card", format, Geom::UH_static); @@ -528,7 +528,7 @@ create_texture_card_vdata(int x, int y) GeomVertexWriter vertex(vdata, InternalName::get_vertex()); GeomVertexWriter texcoord(vdata, InternalName::get_texcoord()); GeomVertexWriter normal(vdata, InternalName::get_normal()); - + vertex.add_data3f(Vertexf::rfu(-1.0f, 0.0f, 1.0f)); vertex.add_data3f(Vertexf::rfu(-1.0f, 0.0f, -1.0f)); vertex.add_data3f(Vertexf::rfu( 1.0f, 0.0f, 1.0f)); diff --git a/panda/src/display/graphicsStateGuardian.I b/panda/src/display/graphicsStateGuardian.I index 6b27115f11..6f49f4d910 100644 --- a/panda/src/display/graphicsStateGuardian.I +++ b/panda/src/display/graphicsStateGuardian.I @@ -470,6 +470,28 @@ get_supports_render_texture() const { return _supports_render_texture; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::get_supports_depth_texture +// Access: Published +// Description: Returns true if this particular GSG supports +// textures whose format is F_depth_component. +//////////////////////////////////////////////////////////////////// +INLINE bool GraphicsStateGuardian:: +get_supports_depth_texture() const { + return _supports_depth_texture; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::get_supports_shadow_filter +// Access: Published +// Description: Returns true if this particular GSG supports +// the filter mode FT_shadow for depth textures. +//////////////////////////////////////////////////////////////////// +INLINE bool GraphicsStateGuardian:: +get_supports_shadow_filter() const { + return _supports_shadow_filter; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::get_color_scale_via_lighting // Access: Published diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index e1db4b6668..fa97c92930 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -145,7 +145,8 @@ GraphicsStateGuardian(const FrameBufferProperties &properties, _supports_multisample = false; _supports_generate_mipmap = false; _supports_render_texture = false; - + _supports_depth_texture = false; + _supports_shadow_filter = false; _supported_geom_rendering = 0; // If this is true, then we can apply a color and/or color scale by diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 2275e6e8e6..e9aff3d215 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -109,11 +109,13 @@ PUBLISHED: virtual bool get_supports_multisample() const; INLINE bool get_supports_generate_mipmap() const; INLINE bool get_supports_render_texture() const; + INLINE bool get_supports_depth_texture() const; + INLINE bool get_supports_shadow_filter() const; virtual int get_supported_geom_rendering() const; INLINE bool get_color_scale_via_lighting() const; - + void set_coordinate_system(CoordinateSystem cs); INLINE CoordinateSystem get_coordinate_system() const; virtual CoordinateSystem get_internal_coordinate_system() const; @@ -355,9 +357,11 @@ protected: bool _supports_multisample; bool _supports_generate_mipmap; bool _supports_render_texture; + bool _supports_depth_texture; + bool _supports_shadow_filter; int _supported_geom_rendering; bool _color_scale_via_lighting; - + public: // Statistics static PStatCollector _total_texusage_pcollector; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 7fe5972520..1c14c9446b 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -518,6 +518,16 @@ reset() { _glClientActiveTexture = null_glActiveTexture; } + if (has_extension("GL_ARB_depth_texture")) { + _supports_depth_texture = true; + } + + if (_supports_depth_texture && + has_extension("GL_ARB_shadow") && + has_extension("GL_ARB_fragment_program_shadow")) { + _supports_shadow_filter = true; + } + _supports_texture_combine = has_extension("GL_ARB_texture_env_combine") || is_at_least_version(1, 3); _supports_texture_saved_result = @@ -2041,7 +2051,7 @@ release_geom(GeomContext *gc) { //////////////////////////////////////////////////////////////////// ShaderContext *CLP(GraphicsStateGuardian):: prepare_shader(ShaderExpansion *se) { - CLP(ShaderContext) *result = new CLP(ShaderContext)(se); + CLP(ShaderContext) *result = new CLP(ShaderContext)(se, this); if (result->valid()) return result; delete result; return NULL; @@ -2452,7 +2462,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, } else { nassertv(tex->get_texture_type() == Texture::TT_2d_texture); } - + // Match framebuffer format if necessary. if (tex->get_match_framebuffer_format()) { const FrameBufferProperties &properties = get_properties(); @@ -3901,6 +3911,8 @@ get_texture_filter_type(Texture::FilterType ft, bool ignore_mipmaps) { case Texture::FT_nearest_mipmap_linear: case Texture::FT_linear_mipmap_linear: return GL_LINEAR; + case Texture::FT_shadow: + return GL_LINEAR; case Texture::FT_invalid: break; } @@ -3919,6 +3931,8 @@ get_texture_filter_type(Texture::FilterType ft, bool ignore_mipmaps) { return GL_NEAREST_MIPMAP_LINEAR; case Texture::FT_linear_mipmap_linear: return GL_LINEAR_MIPMAP_LINEAR; + case Texture::FT_shadow: + return GL_LINEAR; case Texture::FT_invalid: break; } @@ -5044,7 +5058,7 @@ update_standard_texture_bindings() GLP(MatrixMode)(GL_TEXTURE); if (_target._tex_matrix->has_stage(stage)) { - GLP(LoadMatrixf)(_state._tex_matrix->get_mat(stage).get_data()); + GLP(LoadMatrixf)(_target._tex_matrix->get_mat(stage).get_data()); } else { GLP(LoadIdentity)(); } @@ -5444,6 +5458,19 @@ specify_texture(Texture *tex) { GLP(TexParameteri)(target, GL_TEXTURE_MAG_FILTER, get_texture_filter_type(magfilter, true)); + if (_supports_shadow_filter) { + if (tex->get_format() == Texture::F_depth_component) { + if ((tex->get_magfilter() == Texture::FT_shadow) || + (tex->get_minfilter() == Texture::FT_shadow)) { + GLP(TexParameteri)(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + GLP(TexParameteri)(target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_GEQUAL); + } else { + GLP(TexParameteri)(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + GLP(TexParameteri)(target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + } + } + } + report_my_gl_errors(); } diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 5f4bbecd92..0fef3106f6 100755 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -24,7 +24,7 @@ TypeHandle CLP(ShaderContext)::_type_handle; // Description: xyz //////////////////////////////////////////////////////////////////// CLP(ShaderContext):: -CLP(ShaderContext)(ShaderExpansion *s) : ShaderContext(s) { +CLP(ShaderContext)(ShaderExpansion *s, GSG *gsg) : ShaderContext(s) { string header; s->parse_init(); s->parse_line(header, true, true); @@ -73,7 +73,7 @@ CLP(ShaderContext)(ShaderExpansion *s) : ShaderContext(s) { } // Compile the program. - try_cg_compile(s); + try_cg_compile(s, gsg); cerr << _cg_errors; return; } @@ -155,7 +155,7 @@ parse_cg_profile(const string &id, bool vertex) //////////////////////////////////////////////////////////////////// #ifdef HAVE_CGGL bool CLP(ShaderContext):: -try_cg_compile(ShaderExpansion *s) +try_cg_compile(ShaderExpansion *s, GSG *gsg) { _cg_errors = ""; @@ -176,6 +176,78 @@ try_cg_compile(ShaderExpansion *s) return false; } + // The following code is present to work around a bug in the Cg compiler. + // It does not generate correct code for shadow map lookups when using arbfp1. + // This is a particularly onerous limitation, given that arbfp1 is the only + // Cg target that works on radeons. I suspect this is an intentional + // omission on nvidia's part. The following code fetches the output listing, + // detects the error, repairs the code, and resumbits the repaired code to Cg. + if ((_cg_profile[1] == CG_PROFILE_ARBFP1) && (gsg->_supports_shadow_filter)) { + bool shadowunit[32]; + bool anyshadow = false; + memset(shadowunit, 0, sizeof(shadowunit)); + vector_string lines; + tokenize(cgGetProgramString(_cg_program[1], CG_COMPILED_PROGRAM), lines, "\n"); + // figure out which texture units contain shadow maps. + for (int lineno=0; lineno<(int)lines.size(); lineno++) { + if (lines[lineno].compare(0,21,"#var sampler2DSHADOW ")) { + continue; + } + vector_string fields; + tokenize(lines[lineno], fields, ":"); + if (fields.size()!=5) { + continue; + } + vector_string words; + tokenize(trim(fields[2]), words, " "); + if (words.size()!=2) { + continue; + } + int unit = atoi(words[1].c_str()); + if ((unit < 0)||(unit >= 32)) { + continue; + } + anyshadow = true; + shadowunit[unit] = true; + } + // modify all TEX statements that use the relevant texture units. + if (anyshadow) { + for (int lineno=0; lineno<(int)lines.size(); lineno++) { + if (lines[lineno].compare(0,4,"TEX ")) { + continue; + } + vector_string fields; + tokenize(lines[lineno], fields, ","); + if ((fields.size()!=4)||(trim(fields[3]) != "2D;")) { + continue; + } + vector_string texunitf; + tokenize(trim(fields[2]), texunitf, "[]"); + if ((texunitf.size()!=3)||(texunitf[0] != "texture")||(texunitf[2]!="")) { + continue; + } + int unit = atoi(texunitf[1].c_str()); + if ((unit < 0) || (unit >= 32) || (shadowunit[unit]==false)) { + continue; + } + lines[lineno] = fields[0]+","+fields[1]+","+fields[2]+", SHADOW2D;"; + } + string result = "!!ARBfp1.0\nOPTION ARB_fragment_program_shadow;\n"; + for (int lineno=1; lineno<(int)lines.size(); lineno++) { + result += (lines[lineno] + "\n"); + } + cgDestroyProgram(_cg_program[1]); + _cg_program[1] = + cgCreateProgram(_cg_context, CG_OBJECT, result.c_str(), + _cg_profile[1], "fshader", (const char**)NULL); + print_cg_compile_errors(s->get_name(), _cg_context); + if (_cg_program[SHADER_type_frag]==0) { + release_resources(); + return false; + } + } + } + bool success = true; CGparameter parameter; for (int progindex=0; progindex<2; progindex++) { diff --git a/panda/src/glstuff/glShaderContext_src.h b/panda/src/glstuff/glShaderContext_src.h index 7dafea4bca..029926a239 100755 --- a/panda/src/glstuff/glShaderContext_src.h +++ b/panda/src/glstuff/glShaderContext_src.h @@ -34,10 +34,11 @@ class CLP(GraphicsStateGuardian); class EXPCL_GL CLP(ShaderContext): public ShaderContext { public: - CLP(ShaderContext)(ShaderExpansion *s); - ~CLP(ShaderContext)(); typedef CLP(GraphicsStateGuardian) GSG; + CLP(ShaderContext)(ShaderExpansion *s, GSG *gsg); + ~CLP(ShaderContext)(); + INLINE bool valid(void); void bind(GSG *gsg); void unbind(); @@ -116,7 +117,7 @@ private: vector _cg_parameter_bind; vector _cg_varying; - bool try_cg_compile(ShaderExpansion *s); + bool try_cg_compile(ShaderExpansion *s, GSG *gsg); void bind_cg_transform(const ShaderTransBind &stb, CLP(GraphicsStateGuardian) *gsg); void suggest_cg_profile(const string &vpro, const string &fpro); diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index c6b753e8ea..21ea52d429 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -1367,7 +1367,8 @@ string_filter_type(const string &string) { return FT_linear_mipmap_linear; } else if (cmp_nocase_uh(string, "mipmap") == 0) { return FT_linear_mipmap_linear; - + } else if (cmp_nocase_uh(string, "shadow") == 0) { + return FT_shadow; } else { return FT_invalid; } @@ -1923,6 +1924,9 @@ operator << (ostream &out, Texture::FilterType ft) { case Texture::FT_linear_mipmap_linear: return out << "linear_mipmap_linear"; + case Texture::FT_shadow: + return out << "shadow"; + case Texture::FT_invalid: return out << "invalid"; } diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index 43bccb49d3..e5b83f0800 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -127,6 +127,9 @@ PUBLISHED: // two mipmap levels, and linearly blend the results. FT_linear_mipmap_linear, + // The OpenGL ARB_shadow extension can be thought of as a kind of filtering. + FT_shadow, + // Returned by string_filter_type() for an invalid match. FT_invalid };