فهرست منبع

Texture arrays added to Texture class, passed to shader through setShaderInput(name, texture). A new Cg type sampler2DArray has been added to the panda3d Shader Class.

Mike Christel 15 سال پیش
والد
کامیت
5dfa504370

+ 29 - 0
panda/src/display/graphicsStateGuardian.I

@@ -1,5 +1,7 @@
 // Filename: graphicsStateGuardian.I
 // Created by:  drose (24Sep99)
+// Updated by: fperazzi, PandaSE (29Apr10) (added 
+// get_max_2d_texture_array_layers and related)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -329,6 +331,22 @@ get_max_3d_texture_dimension() const {
   return _max_3d_texture_dimension;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_max_2d_texture_array_layers
+//       Access: Published
+//  Description: Returns the largest possible number of pages, or -1 
+//               if there is no particular limit. Returns 0 if 2-d
+//               texture arrays not supported.
+//               
+//               The value returned may not be meaningful until after
+//               the graphics context has been fully created (e.g. the
+//               window has been opened).
+////////////////////////////////////////////////////////////////////
+INLINE int GraphicsStateGuardian::
+get_max_2d_texture_array_layers() const {
+  return _max_2d_texture_array_layers;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_max_cube_map_dimension
 //       Access: Published
@@ -397,6 +415,17 @@ get_supports_3d_texture() const {
   return _supports_3d_texture;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_supports_2d_texture_array
+//       Access: Published
+//  Description: Returns true if this GSG can render 2-d textures
+//               array.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsStateGuardian::
+get_supports_2d_texture_array() const {
+  return _supports_2d_texture_array;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_supports_cube_map
 //       Access: Published

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

@@ -1,6 +1,8 @@
 // Filename: graphicsStateGuardian.cxx
 // Created by:  drose (02Feb99)
 // Updated by: fperazzi, PandaSE (06Apr10) (added fetch_ptr_parameter)
+// Updated by: fperazzi, PandaSE (29Apr10)  (added 
+// _max_2d_texture_array_layers, _supports_2d_texture_array)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -169,6 +171,7 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   // and that 3-d and cube-map textures are not supported.
   _max_texture_dimension = -1;
   _max_3d_texture_dimension = 0;
+  _max_2d_texture_array_layers = 0;
   _max_cube_map_dimension = 0;
 
   // Assume we don't support these fairly advanced texture combiner
@@ -178,6 +181,7 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   _supports_texture_dot3 = false;
 
   _supports_3d_texture = false;
+  _supports_2d_texture_array = false;
   _supports_cube_map = false;
   _supports_tex_non_pow2 = false;
   _supports_compressed_texture = false;

+ 6 - 0
panda/src/display/graphicsStateGuardian.h

@@ -1,6 +1,8 @@
 // Filename: graphicsStateGuardian.h
 // Created by:  drose (02Feb99)
 // Updated by: fperazzi, PandaSE (06Apr10) (added fetch_ptr_parameter)
+// Updated by: fperazzi, PandaSE (29Apr10) (added 
+// _max_2d_texture_array_layers on z axis)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -114,6 +116,7 @@ PUBLISHED:
   INLINE int get_max_texture_stages() const;
   virtual INLINE int get_max_texture_dimension() const;
   INLINE int get_max_3d_texture_dimension() const;
+  INLINE int get_max_2d_texture_array_layers() const; //z axis
   INLINE int get_max_cube_map_dimension() const;
 
   INLINE bool get_supports_texture_combine() const;
@@ -121,6 +124,7 @@ PUBLISHED:
   INLINE bool get_supports_texture_dot3() const;
 
   INLINE bool get_supports_3d_texture() const;
+  INLINE bool get_supports_2d_texture_array() const;
   INLINE bool get_supports_cube_map() const;
   INLINE bool get_supports_tex_non_pow2() const;
 
@@ -433,6 +437,7 @@ protected:
   int _max_texture_stages;
   int _max_texture_dimension;
   int _max_3d_texture_dimension;
+  int _max_2d_texture_array_layers; //on the z axis
   int _max_cube_map_dimension;
 
   bool _supports_texture_combine;
@@ -440,6 +445,7 @@ protected:
   bool _supports_texture_dot3;
 
   bool _supports_3d_texture;
+  bool _supports_2d_texture_array;
   bool _supports_cube_map;
   bool _supports_tex_non_pow2;
 

+ 103 - 18
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -584,6 +584,9 @@ reset() {
     }
   }
 
+#ifndef OPENGLES
+  _supports_2d_texture_array = has_extension("GL_EXT_texture_array");
+#endif
 #ifdef OPENGLES_2
   _supports_cube_map = true;
 #else
@@ -1306,6 +1309,7 @@ reset() {
 
   GLint max_texture_size = 0;
   GLint max_3d_texture_size = 0;
+  GLint max_2d_texture_array_layers = 0;
   GLint max_cube_map_size = 0;
 
   GLP(GetIntegerv)(GL_MAX_TEXTURE_SIZE, &max_texture_size);
@@ -1319,7 +1323,12 @@ reset() {
   } else {
     _max_3d_texture_dimension = 0;
   }
-
+#ifndef OPENGLES
+  if(_supports_2d_texture_array) {
+    GLP(GetIntegerv)(GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, &max_2d_texture_array_layers);
+    _max_2d_texture_array_layers = max_2d_texture_array_layers;
+  }
+#endif
   if (_supports_cube_map) {
     GLP(GetIntegerv)(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &max_cube_map_size);
     _max_cube_map_dimension = max_cube_map_size;
@@ -1343,6 +1352,7 @@ reset() {
     GLCAT.debug()
       << "max texture dimension = " << _max_texture_dimension
       << ", max 3d texture = " << _max_3d_texture_dimension
+      << ", max 2d texture array = " << max_2d_texture_array_layers
       << ", max cube map = " << _max_cube_map_dimension << "\n";
     GLCAT.debug()
       << "max_elements_vertices = " << max_elements_vertices
@@ -3203,6 +3213,14 @@ prepare_texture(Texture *tex) {
       return NULL;
     }
     break;
+  
+  case Texture::TT_2d_texture_array:
+    if (!_supports_2d_texture_array) {
+      GLCAT.warning()
+        << "2-D texture arrays are not supported by this OpenGL driver.\n";
+      return NULL;
+    }
+    break;
 
   case Texture::TT_cube_map:
     if (!_supports_cube_map) {
@@ -5638,7 +5656,14 @@ get_texture_target(Texture::TextureType texture_type) const {
     } else {
       return GL_NONE;
     }
-
+  case Texture::TT_2d_texture_array:
+    if (_supports_2d_texture_array) {
+#ifndef OPENGLES
+      return GL_TEXTURE_2D_ARRAY_EXT;
+#endif
+    } else {
+      return GL_NONE;
+    }
   case Texture::TT_cube_map:
     if (_supports_cube_map) {
       return GL_TEXTURE_CUBE_MAP;
@@ -5992,7 +6017,8 @@ get_internal_image_format(Texture *tex) const {
     // no compression for render targets
     compression = Texture::CM_off;
   }
-  bool is_3d = (tex->get_texture_type() == Texture::TT_3d_texture);
+  bool is_3d = (tex->get_texture_type() == Texture::TT_3d_texture ||
+                tex->get_texture_type() == Texture::TT_2d_texture_array);
 
 #ifndef OPENGLES
   if (get_supports_compressed_texture_format(compression)) {
@@ -8249,22 +8275,38 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
   GLenum component_type = get_component_type(tex->get_component_type());
 
   // Ensure that the texture fits within the GL's specified limits.
-  int max_dimension;
+  // Need to split dimensions because of texture arrays
+  int max_dimension_x;
+  int max_dimension_y;
+  int max_dimension_z;
+
   switch (tex->get_texture_type()) {
   case Texture::TT_3d_texture:
-    max_dimension = _max_3d_texture_dimension;
+    max_dimension_x = _max_3d_texture_dimension;
+    max_dimension_y = _max_3d_texture_dimension;
+    max_dimension_z = _max_3d_texture_dimension;
     break;
 
   case Texture::TT_cube_map:
-    max_dimension = _max_cube_map_dimension;
+    max_dimension_x = _max_cube_map_dimension;
+    max_dimension_y = _max_cube_map_dimension;
+    max_dimension_z = 6;
+    break;
+
+  case Texture::TT_2d_texture_array:
+    max_dimension_x = _max_texture_dimension;
+    max_dimension_y = _max_texture_dimension;
+    max_dimension_z = _max_2d_texture_array_layers;
     break;
 
   default:
-    max_dimension = _max_texture_dimension;
+    max_dimension_x = _max_texture_dimension;
+    max_dimension_y = _max_texture_dimension;
+    max_dimension_z = 1;
   }
 
-  if (max_dimension == 0) {
-    // Guess this GL doesn't support cube mapping/3d textures.
+  if (max_dimension_x == 0 || max_dimension_y == 0 || max_dimension_z == 0) {
+    // Guess this GL doesn't support cube mapping/3d textures/2d texture arrays.
     report_my_gl_errors();
     return false;
   }
@@ -8277,10 +8319,11 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
   // reduce the texture at load time instead; of course, the user
   // doesn't always know ahead of time what the hardware limits are.
 
-  if (max_dimension > 0 && image_compression == Texture::CM_off) {
-    while (tex->get_expected_mipmap_x_size(mipmap_bias) > max_dimension ||
-           tex->get_expected_mipmap_y_size(mipmap_bias) > max_dimension ||
-           tex->get_expected_mipmap_z_size(mipmap_bias) > max_dimension) {
+  if ((max_dimension_x > 0 && max_dimension_y > 0 && max_dimension_z > 0) && 
+      image_compression == Texture::CM_off) {
+    while (tex->get_expected_mipmap_x_size(mipmap_bias) > max_dimension_x ||
+           tex->get_expected_mipmap_y_size(mipmap_bias) > max_dimension_y ||
+           tex->get_expected_mipmap_z_size(mipmap_bias) > max_dimension_z) {
       ++mipmap_bias;
     }
 
@@ -8652,6 +8695,22 @@ upload_texture_image(CLP(TextureContext) *gtc,
           return false;
         }
         break;
+#endif
+#ifndef OPENGLES
+      case GL_TEXTURE_2D_ARRAY_EXT:
+        if (_supports_2d_texture_array) {
+          if (image_compression == Texture::CM_off) {
+            _glTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth,
+                             external_format, component_type, image_ptr);
+          } else {
+            _glCompressedTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth,
+                                       external_format, image_size, image_ptr);
+          }
+        } else {
+          report_my_gl_errors();
+          return false;
+        }
+        break;
 #endif
       default:
         if (image_compression == Texture::CM_off) {
@@ -8791,6 +8850,22 @@ upload_texture_image(CLP(TextureContext) *gtc,
         }
         break;
 #endif
+      case GL_TEXTURE_2D_ARRAY_EXT:
+        if (_supports_2d_texture_array) {
+          if (image_compression == Texture::CM_off) {
+            _glTexImage3D(page_target, n - mipmap_bias, internal_format,
+                          width, height, depth, 0,
+                          external_format, component_type, image_ptr);
+          } else {
+            _glCompressedTexImage3D(page_target, n - mipmap_bias, external_format, width,
+                                    height, depth,
+                                    0, image_size, image_ptr);
+          }
+        } else {
+          report_my_gl_errors();
+          return false;
+        }
+        break;
 #endif  // OPENGLES  // OpenGL ES will fall through.
 
       default:
@@ -8998,11 +9073,11 @@ get_texture_memory_size(Texture *tex) {
   GLint width = 1, height = 1, depth = 1;
   GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_WIDTH, &width);
   GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_HEIGHT, &height);
-  if (_supports_3d_texture) {
+  if (_supports_3d_texture || _supports_2d_texture_array) {
     GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_DEPTH, &depth);
   }
-
-  report_my_gl_errors();
+  
+    report_my_gl_errors();
 
   size_t num_bits = (red_size + green_size + blue_size + alpha_size + luminance_size + intensity_size + depth_size);
   size_t num_bytes = (num_bits + 7) / 8;
@@ -9084,6 +9159,11 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
 #ifdef OPENGLES_2
     GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_R_OES, &wrap_w);
 #endif
+#ifndef OPENGLES
+    GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_R, &wrap_w);
+#endif
+  }
+  if (_supports_2d_texture_array) {
 #ifndef OPENGLES
     GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_R, &wrap_w);
 #endif
@@ -9113,12 +9193,17 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
   
   if (_supports_3d_texture && target == GL_TEXTURE_3D) {
     GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_DEPTH, &depth);
-  } else if (target == GL_TEXTURE_CUBE_MAP) {
+  } 
+#ifndef OPENGLES
+  else if (_supports_2d_texture_array && target == GL_TEXTURE_2D_ARRAY_EXT) {
+    GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_DEPTH, &depth);
+  }
+#endif 
+  else if (target == GL_TEXTURE_CUBE_MAP) {
     depth = 6;
   }
 #endif
   clear_my_gl_errors();
-
   if (width <= 0 || height <= 0 || depth <= 0) {
     GLCAT.error()
       << "No texture data for " << tex->get_name() << "\n";

+ 14 - 15
panda/src/glstuff/glShaderContext_src.cxx

@@ -1,6 +1,6 @@
 // Filename: glShaderContext_src.cxx
 // Created by: jyelon (01Sep05)
-// Updated by: fperazzi, PandaSE (06Apr10) (updated CLP with note that some
+// Updated by: fperazzi, PandaSE (29Apr10) (updated CLP with note that some
 //   parameter types only supported under Cg)
 //
 ////////////////////////////////////////////////////////////////////
@@ -567,7 +567,7 @@ issue_parameters(GSG *gsg, int altered) {
                   case Shader::SAT_vec3: cgSetParameter3fv(p,(float*)_ptr_data->_ptr); continue;
                   case Shader::SAT_vec4: cgSetParameter4fv(p,(float*)_ptr_data->_ptr); continue;
                 }
-              case Shader::SAC_matrix: cgGLSetMatrixParameterfr(p,(float*)_ptr_data->_ptr); continue;
+              case Shader::SAC_matrix: cgGLSetMatrixParameterfc(p,(float*)_ptr_data->_ptr); continue;
               case Shader::SAC_array: {
                 switch(_ptr._info._subclass) {
                   case Shader::SAC_scalar: 
@@ -580,7 +580,7 @@ issue_parameters(GSG *gsg, int altered) {
                       case 4: cgGLSetParameterArray4f(p,0,_ptr._dim[0],(float*)_ptr_data->_ptr); continue;
                     }
                   case Shader::SAC_matrix:
-                    cgGLSetMatrixParameterArrayfr(p,0,_ptr._dim[0],(float*)_ptr_data->_ptr); continue;
+                    cgGLSetMatrixParameterArrayfc(p,0,_ptr._dim[0],(float*)_ptr_data->_ptr); continue;
                 }
               } 
             }
@@ -594,7 +594,7 @@ issue_parameters(GSG *gsg, int altered) {
                   case Shader::SAT_vec3: cgSetParameter3dv(p,(double*)_ptr_data->_ptr); continue;
                   case Shader::SAT_vec4: cgSetParameter4dv(p,(double*)_ptr_data->_ptr); continue;
                 }
-              case Shader::SAC_matrix: cgGLSetMatrixParameterdr(p,(double*)_ptr_data->_ptr); continue;
+              case Shader::SAC_matrix: cgGLSetMatrixParameterdc(p,(double*)_ptr_data->_ptr); continue;
               case Shader::SAC_array: {
                 switch(_ptr._info._subclass) {
                   case Shader::SAC_scalar: 
@@ -607,7 +607,7 @@ issue_parameters(GSG *gsg, int altered) {
                       case 4: cgGLSetParameterArray4d(p,0,_ptr._dim[0],(double*)_ptr_data->_ptr); continue;
                     }
                   case Shader::SAC_matrix:
-                    cgGLSetMatrixParameterArraydr(p,0,_ptr._dim[0],(double*)_ptr_data->_ptr); continue;
+                    cgGLSetMatrixParameterArraydc(p,0,_ptr._dim[0],(double*)_ptr_data->_ptr); continue;
                 }
               } 
             }
@@ -833,16 +833,21 @@ disable_shader_texture_bindings(GSG *gsg) {
       return;
     }
 #ifndef OPENGLES
-    GLP(Disable)(GL_TEXTURE_1D);
+    GLP(BindTexture)(GL_TEXTURE_1D, 0);
 #endif  // OPENGLES
-    GLP(Disable)(GL_TEXTURE_2D);
+    GLP(BindTexture)(GL_TEXTURE_2D, 0);
 #ifndef OPENGLES_1
     if (gsg->_supports_3d_texture) {
-      GLP(Disable)(GL_TEXTURE_3D);
+      GLP(BindTexture)(GL_TEXTURE_3D, 0);
     }
 #endif  // OPENGLES_1
+#ifndef OPENGLES
+    if (gsg->_supports_2d_texture_array) {
+      GLP(BindTexture)(GL_TEXTURE_2D_ARRAY_EXT, 0);
+    }
+#endif
     if (gsg->_supports_cube_map) {
-      GLP(Disable)(GL_TEXTURE_CUBE_MAP);
+      GLP(BindTexture)(GL_TEXTURE_CUBE_MAP, 0);
     }
     // This is probably faster - but maybe not as safe?
     // cgGLDisableTextureParameter(p);
@@ -938,9 +943,6 @@ update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) {
       // Unsupported texture mode.
       continue;
     }
-#ifndef OPENGLES_2
-    GLP(Enable)(target);
-#endif
     gsg->apply_texture(tc);
 
     if (_shader->get_language() == Shader::SL_GLSL) {
@@ -949,9 +951,6 @@ update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) {
     }
 
     if (!gsg->update_texture(tc, false)) {
-#ifndef OPENGLES_2
-      GLP(Disable)(target);
-#endif
       continue;
     }
   }

+ 52 - 39
panda/src/gobj/shader.cxx

@@ -1,6 +1,7 @@
 // Filename: shader.cxx
 // Created by: jyelon (01Sep05)
 // Updated by: fperazzi, PandaSE(06Apr10)
+// Updated by: fperazzi, PandaSE(29Apr10) (added SAT_sampler2dArray)
 ////////////////////////////////////////////////////////////////////
 //
 // PANDA 3D SOFTWARE
@@ -57,42 +58,43 @@ cp_report_error(ShaderArgInfo &p, const string &msg) {
 
   string tstr = "invalid ";
   switch (p._type) {
-  case SAT_scalar:      tstr = "scalar "; break; 
-  case SAT_vec1:        tstr = "vec1 "; break;     
-  case SAT_vec2:        tstr = "vec2 "; break;        
-  case SAT_vec3:        tstr = "vec3 "; break;        
-  case SAT_vec4:        tstr = "vec4 "; break;        
-  case SAT_mat1x1:      tstr = "mat1x1 "; break;      
-  case SAT_mat1x2:      tstr = "mat1x2 "; break;      
-  case SAT_mat1x3:      tstr = "mat1x3 "; break;      
-  case SAT_mat1x4:      tstr = "mat1x4 "; break;      
-  case SAT_mat2x1:      tstr = "mat2x1 "; break;      
-  case SAT_mat2x2:      tstr = "mat2x2 "; break;      
-  case SAT_mat2x3:      tstr = "mat2x3 "; break;      
-  case SAT_mat2x4:      tstr = "mat2x4 "; break;      
-  case SAT_mat3x1:      tstr = "mat3x1 "; break;      
-  case SAT_mat3x2:      tstr = "mat3x2 "; break;      
-  case SAT_mat3x3:      tstr = "mat3x3 "; break;       
-  case SAT_mat3x4:      tstr = "mat3x4 "; break;       
-  case SAT_mat4x1:      tstr = "mat4x1 "; break;       
-  case SAT_mat4x2:      tstr = "mat4x2 "; break;       
-  case SAT_mat4x3:      tstr = "mat4x3 "; break;       
-  case SAT_mat4x4:      tstr = "mat4x4 "; break;      
-  case SAT_sampler1d:   tstr = "sampler1d "; break;  
-  case SAT_sampler2d:   tstr = "sampler2d "; break;   
-  case SAT_sampler3d:   tstr = "sampler3d "; break;   
-  case SAT_samplercube: tstr = "samplercube "; break; 
-  default:              tstr = "unknown "; break; 
+  case SAT_scalar:    tstr = "scalar "; break; 
+  case SAT_vec1:      tstr = "vec1 "; break;     
+  case SAT_vec2:      tstr = "vec2 "; break;        
+  case SAT_vec3:      tstr = "vec3 "; break;        
+  case SAT_vec4:      tstr = "vec4 "; break;        
+  case SAT_mat1x1:    tstr = "mat1x1 "; break;      
+  case SAT_mat1x2:    tstr = "mat1x2 "; break;      
+  case SAT_mat1x3:    tstr = "mat1x3 "; break;      
+  case SAT_mat1x4:    tstr = "mat1x4 "; break;      
+  case SAT_mat2x1:    tstr = "mat2x1 "; break;      
+  case SAT_mat2x2:    tstr = "mat2x2 "; break;      
+  case SAT_mat2x3:    tstr = "mat2x3 "; break;      
+  case SAT_mat2x4:    tstr = "mat2x4 "; break;      
+  case SAT_mat3x1:    tstr = "mat3x1 "; break;      
+  case SAT_mat3x2:    tstr = "mat3x2 "; break;      
+  case SAT_mat3x3:    tstr = "mat3x3 "; break;       
+  case SAT_mat3x4:    tstr = "mat3x4 "; break;       
+  case SAT_mat4x1:    tstr = "mat4x1 "; break;       
+  case SAT_mat4x2:    tstr = "mat4x2 "; break;       
+  case SAT_mat4x3:    tstr = "mat4x3 "; break;       
+  case SAT_mat4x4:    tstr = "mat4x4 "; break;      
+  case SAT_sampler1d: tstr = "sampler1d "; break;  
+  case SAT_sampler2d: tstr = "sampler2d "; break;   
+  case SAT_sampler3d: tstr = "sampler3d "; break;   
+  case SAT_sampler2dArray: tstr = "sampler2dArray "; break; 
+  case SAT_samplercube:    tstr = "samplercube "; break; 
+  default:                 tstr = "unknown "; break; 
   }
   
   string cstr = "invalid";
   switch (p._class) {
-  case SAC_scalar:  cstr = "scalar "; break;              
-  case SAC_vector:  cstr = "vector "; break;       
-  case SAC_matrix:  cstr = "matrix "; break;        
+  case SAC_scalar:  cstr = "scalar ";  break;              
+  case SAC_vector:  cstr = "vector ";  break;       
+  case SAC_matrix:  cstr = "matrix ";  break;        
   case SAC_sampler: cstr = "sampler "; break;       
-  case SAC_array:   cstr = "array "; break;       
-  default:          cstr = "unknown ";break; 
+  case SAC_array:   cstr = "array ";   break;       
+  default:          cstr = "unknown "; break; 
   }    
 
   Filename fn = get_filename(p._id._type);
@@ -238,6 +240,7 @@ cp_errchk_parameter_sampler(ShaderArgInfo &p)
   if ((p._type!=SAT_sampler1d)&&
       (p._type!=SAT_sampler2d)&&
       (p._type!=SAT_sampler3d)&&
+      (p._type!=SAT_sampler2dArray)&&
       (p._type!=SAT_samplercube)) {
     cp_report_error(p, "parameter should have a 'sampler' type");
     return false;
@@ -1021,10 +1024,11 @@ compile_parameter(const ShaderArgId        &arg_id,
     bind._name = 0;
     bind._stage = atoi(pieces[1].c_str());
     switch (p._type) {
-    case SAT_sampler1d:   bind._desired_type = Texture::TT_1d_texture; break;
-    case SAT_sampler2d:   bind._desired_type = Texture::TT_2d_texture; break;
-    case SAT_sampler3d:   bind._desired_type = Texture::TT_3d_texture; break;
-    case SAT_samplercube: bind._desired_type = Texture::TT_cube_map; break;
+    case SAT_sampler1d:      bind._desired_type = Texture::TT_1d_texture; break;
+    case SAT_sampler2d:      bind._desired_type = Texture::TT_2d_texture; break;
+    case SAT_sampler3d:      bind._desired_type = Texture::TT_3d_texture; break;
+    case SAT_sampler2dArray: bind._desired_type = Texture::TT_2d_texture_array; break;
+    case SAT_samplercube:    bind._desired_type = Texture::TT_cube_map; break;
     default:
       cp_report_error(p, "Invalid type for a tex-parameter");
       return false;
@@ -1153,6 +1157,14 @@ compile_parameter(const ShaderArgId        &arg_id,
       _tex_spec.push_back(bind);
       return true;
     }
+    case SAT_sampler2dArray: {
+      ShaderTexSpec bind;
+      bind._id = arg_id;
+      bind._name = kinputname;
+      bind._desired_type = Texture::TT_2d_texture_array;
+      _tex_spec.push_back(bind);
+      return true;
+    }
     case SAT_samplercube: {
       ShaderTexSpec bind;
       bind._id = arg_id;
@@ -1245,10 +1257,11 @@ cg_parameter_type(CGparameter p) {
     }
   case CG_PARAMETERCLASS_SAMPLER:
     switch (cgGetParameterType(p)){
-    case CG_SAMPLER1D:   return Shader::SAT_sampler1d;
-    case CG_SAMPLER2D:   return Shader::SAT_sampler2d;
-    case CG_SAMPLER3D:   return Shader::SAT_sampler3d;
-    case CG_SAMPLERCUBE: return Shader::SAT_samplercube;
+    case CG_SAMPLER1D:      return Shader::SAT_sampler1d;
+    case CG_SAMPLER2D:      return Shader::SAT_sampler2d;
+    case CG_SAMPLER3D:      return Shader::SAT_sampler3d;
+    case CG_SAMPLER2DARRAY: return Shader::SAT_sampler2dArray;
+    case CG_SAMPLERCUBE:    return Shader::SAT_samplercube;
     default: return SAT_unknown;
     }
   case CG_PARAMETERCLASS_ARRAY: return SAT_unknown;

+ 3 - 2
panda/src/gobj/shader.h

@@ -1,6 +1,6 @@
 // Filename: shader.h
 // Created by: jyelon (01Sep05)
-// Updated by: fperazzi, PandaSE(06Apr10)
+// Updated by: fperazzi, PandaSE(29Apr10) (added SAT_sampler2dArray)
 ////////////////////////////////////////////////////////////////////
 //
 // PANDA 3D SOFTWARE
@@ -171,7 +171,8 @@ public:
     SAT_mat4x4,
     SAT_sampler1d,
     SAT_sampler2d,
-    SAT_sampler3d, 
+    SAT_sampler3d,
+    SAT_sampler2dArray,
     SAT_samplercube,
     SAT_unknown
 };

+ 29 - 0
panda/src/gobj/texture.I

@@ -1,5 +1,6 @@
 // Filename: texture.I
 // Created by:  drose (05Feb99)
+// Updated by: fperazzi, PandaSE(29Apr10) (added setup_2d_texture_array)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -144,6 +145,34 @@ setup_3d_texture(int x_size, int y_size, int z_size,
   setup_texture(TT_3d_texture, x_size, y_size, z_size, component_type, format);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::setup_2d_texture_array
+//       Access: Published
+//  Description: Sets the texture as an empty 2-d texture array with
+//               no dimensions (though if you know the depth ahead
+//               of time, it saves a bit of reallocation later).
+//               Follow up with read() or load() to fill the texture
+//               properties and image data.
+////////////////////////////////////////////////////////////////////
+INLINE void Texture::
+setup_2d_texture_array(int z_size) {
+  setup_2d_texture_array(0, 1, z_size, T_unsigned_byte, F_rgb);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::setup_2d_texture_array
+//       Access: Published
+//  Description: Sets the texture as an empty 2-d texture array with the
+//               specified dimensions and properties. Follow up with
+//               set_ram_image() or modify_ram_image() to fill the
+//               image data.
+////////////////////////////////////////////////////////////////////
+INLINE void Texture::
+setup_2d_texture_array(int x_size, int y_size, int z_size,
+                 ComponentType component_type, Format format) {
+  setup_texture(TT_2d_texture_array, x_size, y_size, z_size, component_type, format);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::setup_cube_map
 //       Access: Published

+ 32 - 9
panda/src/gobj/texture.cxx

@@ -1,5 +1,6 @@
 // Filename: texture.cxx
 // Created by:  mike (09Jan97)
+// Updated by: fperazzi, PandaSE(29Apr10) (added TT_2d_texture_array)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -1360,7 +1361,11 @@ write(ostream &out, int indent_level) const {
   case TT_3d_texture:
     out << "3-d, " << _x_size << " x " << _y_size << " x " << _z_size;
     break;
-
+  
+  case TT_2d_texture_array:
+    out << "2-d array, " << _x_size << " x " << _y_size << " x " << _z_size;
+    break;
+  
   case TT_cube_map:
     out << "cube map, " << _x_size << " x " << _y_size;
     break;
@@ -1490,6 +1495,10 @@ write(ostream &out, int indent_level) const {
     out << _wrap_u << " x " << _wrap_v << " x " << _wrap_w << ", ";
     break;
 
+  case TT_2d_texture_array:
+    out << _wrap_u << " x " << _wrap_v << " x " << _wrap_w << ", ";
+    break;
+  
   case TT_cube_map:
     break;
   }
@@ -3553,7 +3562,9 @@ do_compress_ram_image(Texture::CompressionMode compression,
   }
 
 #ifdef HAVE_SQUISH
-  if (_texture_type != TT_3d_texture && _component_type == T_unsigned_byte) {
+  if (_texture_type != TT_3d_texture && 
+      _texture_type != TT_2d_texture_array && 
+      _component_type == T_unsigned_byte) {
     int squish_flags = 0;
     switch (compression) {
     case CM_dxt1:
@@ -3612,7 +3623,9 @@ bool Texture::
 do_uncompress_ram_image() {
 
 #ifdef HAVE_SQUISH
-  if (_texture_type != TT_3d_texture && _component_type == T_unsigned_byte) {
+  if (_texture_type != TT_3d_texture && 
+      _texture_type != TT_2d_texture_array && 
+      _component_type == T_unsigned_byte) {
     int squish_flags = 0;
     switch (_ram_image_compression) {
     case CM_dxt1:
@@ -3689,9 +3702,10 @@ do_reconsider_z_size(int z) {
   if (z >= _z_size) {
     // If we're loading a page past _z_size, treat it as an implicit
     // request to enlarge _z_size.  However, this is only legal if
-    // this is, in fact, a 3-d texture (cube maps always have z_size
-    // 6, and other types have z_size 1).
-    nassertr(_texture_type == Texture::TT_3d_texture, false);
+    // this is, in fact, a 3-d texture or a 2d texture array (cube maps
+    // always have z_size 6, and other types have z_size 1).
+    nassertr(_texture_type == Texture::TT_3d_texture ||
+             _texture_type == Texture::TT_2d_texture_array, false);
 
     _z_size = z + 1;
     // Increase the size of the data buffer to make room for the new
@@ -3882,6 +3896,9 @@ do_setup_texture(Texture::TextureType texture_type, int x_size, int y_size,
   case TT_3d_texture:
     break;
 
+  case TT_2d_texture_array:
+    break;
+  
   case TT_cube_map:
     // Cube maps must always consist of six square images.
     nassertv(x_size == y_size && z_size == 6);
@@ -4039,9 +4056,9 @@ do_set_y_size(int y_size) {
 void Texture::
 do_set_z_size(int z_size) {
   if (_z_size != z_size) {
-    nassertv(_texture_type == Texture::TT_3d_texture ||
+    nassertv((_texture_type == Texture::TT_3d_texture) ||
              (_texture_type == Texture::TT_cube_map && z_size == 6) ||
-             (z_size == 1));
+             (_texture_type == Texture::TT_2d_texture_array) || (z_size == 1));
     _z_size = z_size;
     ++_image_modified;
     do_clear_ram_image();
@@ -6139,7 +6156,11 @@ make_from_bam(const FactoryParams &params) {
       case TT_3d_texture:
         me = TexturePool::load_3d_texture(filename, false, options);
         break;
-
+      
+      case TT_2d_texture_array:
+        me = TexturePool::load_2d_texture_array(filename, false, options);
+        break;
+      
       case TT_cube_map:
         me = TexturePool::load_cube_map(filename, false, options);
         break;
@@ -6465,6 +6486,8 @@ operator << (ostream &out, Texture::TextureType tt) {
     return out << "2d_texture";
   case Texture::TT_3d_texture:
     return out << "3d_texture";
+  case Texture::TT_2d_texture_array:
+    return out << "2d_texture_array";
   case Texture::TT_cube_map:
     return out << "cube_map";
   }

+ 5 - 1
panda/src/gobj/texture.h

@@ -1,5 +1,6 @@
 // Filename: texture.h
 // Created by:  mike (09Jan97)
+// Updated by: fperazzi, PandaSE(29Apr10) (added TT_2d_texture_array)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -66,6 +67,7 @@ PUBLISHED:
     TT_1d_texture,
     TT_2d_texture,
     TT_3d_texture,
+    TT_2d_texture_array,
     TT_cube_map,
   };
 
@@ -217,7 +219,9 @@ PUBLISHED:
   INLINE void setup_cube_map();
   INLINE void setup_cube_map(int size,
                              ComponentType component_type, Format format);
-
+  INLINE void setup_2d_texture_array(int z_size = 1);
+  INLINE void setup_2d_texture_array(int x_size, int y_size, int z_size,
+                                     ComponentType component_type, Format format);
   void generate_normalization_cube_map(int size);
   void generate_alpha_scale_map();
 

+ 22 - 0
panda/src/gobj/texturePool.I

@@ -1,5 +1,6 @@
 // Filename: texturePool.I
 // Created by:  drose (26Apr00)
+// Updated by: fperazzi, PandaSE(29Apr10) (added load_2d_texture_array)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -106,6 +107,27 @@ load_3d_texture(const Filename &filename_pattern, bool read_mipmaps,
                                               options);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::load_2d_texture_array
+//       Access: Published, Static
+//  Description: Loads a 2-D texture array that is specified with a series
+//               of n pages, all numbered in sequence, and beginning
+//               with index 0.  The filename should include a sequence
+//               of one or more hash characters ("#") which will be
+//               filled in with the index number of each level.
+//
+//               If read_mipmaps is true, the filename should contain
+//               an additional hash mark.  The first hash mark will be
+//               filled in with the mipmap level number, and the
+//               second with the index number of each 2-d level.
+////////////////////////////////////////////////////////////////////
+INLINE Texture *TexturePool::
+load_2d_texture_array(const Filename &filename_pattern, bool read_mipmaps, 
+                const LoaderOptions &options) {
+  return get_global_ptr()->ns_load_2d_texture_array(filename_pattern, read_mipmaps, 
+                                                    options);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TexturePool::load_cube_map
 //       Access: Published, Static

+ 115 - 4
panda/src/gobj/texturePool.cxx

@@ -1,5 +1,6 @@
 // Filename: texturePool.cxx
 // Created by:  drose (26Apr00)
+// Updated by: fperazzi, PandaSE(29Apr10) (added ns_load_2d_texture_array)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -491,8 +492,10 @@ ns_load_3d_texture(const Filename &filename_pattern,
     Textures::const_iterator ti;
     ti = _textures.find(filename);
     if (ti != _textures.end()) {
-      // This texture was previously loaded.
-      return (*ti).second;
+      if ((*ti).second->get_texture_type() == Texture::TT_3d_texture) {
+        // This texture was previously loaded, as a 3d texture
+        return (*ti).second;
+      }
     }
   }
 
@@ -554,8 +557,10 @@ ns_load_3d_texture(const Filename &filename_pattern,
     Textures::const_iterator ti;
     ti = _textures.find(filename);
     if (ti != _textures.end()) {
-      // This texture was previously loaded.
-      return (*ti).second;
+      if ((*ti).second->get_texture_type() == Texture::TT_3d_texture) {
+        // This texture was previously loaded, as a 3d texture
+        return (*ti).second;
+      }
     }
 
     _textures[filename] = tex;
@@ -571,6 +576,112 @@ ns_load_3d_texture(const Filename &filename_pattern,
   return tex;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::ns_load_2d_texture_array
+//       Access: Private
+//  Description: The nonstatic implementation of load_2d_texture_array().
+////////////////////////////////////////////////////////////////////
+Texture *TexturePool::
+ns_load_2d_texture_array(const Filename &filename_pattern,
+                         bool read_mipmaps, const LoaderOptions &options) {
+  Filename orig_filename(filename_pattern);
+  orig_filename.set_pattern(true);
+
+  Filename filename;
+  Filename unique_filename; //differentiate 3d-textures from 2d-texture arrays
+  {
+    MutexHolder holder(_lock);
+    resolve_filename(filename, orig_filename);
+    // Differentiate from preloaded 3d textures
+    unique_filename = filename + ".2DARRAY";
+
+    Textures::const_iterator ti;
+    ti = _textures.find(unique_filename);
+    if (ti != _textures.end()) {
+      if ((*ti).second->get_texture_type() == Texture::TT_2d_texture_array) {
+        // This texture was previously loaded, as a 2d texture array
+        return (*ti).second;
+      }
+    }
+  }
+
+  PT(Texture) tex;
+  PT(BamCacheRecord) record;
+  bool store_record = false;
+
+  BamCache *cache = BamCache::get_global_ptr();
+  bool compressed_cache_record = false;
+  try_load_cache(tex, cache, filename, record, compressed_cache_record,
+                 options);
+
+  if (tex == (Texture *)NULL || 
+      tex->get_texture_type() != Texture::TT_2d_texture_array) {
+    // The texture was neither in the pool, nor found in the on-disk
+    // cache; it needs to be loaded from its source image(s).
+    gobj_cat.info()
+      << "Loading 2-d texture array " << filename << "\n";
+    tex = make_texture(filename.get_extension());
+    tex->setup_2d_texture_array();
+    if (!tex->read(filename, 0, 0, true, read_mipmaps, options)) {
+      // This texture was not found or could not be read.
+      report_texture_unreadable(filename);
+      return NULL;
+    }
+    store_record = (record != (BamCacheRecord *)NULL);
+  }
+
+  if (cache->get_cache_compressed_textures() && tex->has_compression()) {
+#ifndef HAVE_SQUISH
+    bool needs_driver_compression = true;
+#else
+    bool needs_driver_compression = driver_compress_textures;
+#endif // HAVE_SQUISH
+    if (needs_driver_compression) {
+      // We don't want to save the uncompressed version; we'll save the
+      // compressed version when it becomes available.
+      store_record = false;
+      if (!compressed_cache_record) {
+        tex->set_post_load_store_cache(true);
+      }
+    }
+
+  } else if (!cache->get_cache_textures()) {
+    // We don't want to save this texture.
+    store_record = false;
+  }
+
+  // Set the original filename, before we searched along the path.
+  nassertr(tex != (Texture *)NULL, false);
+  tex->set_filename(filename_pattern);
+  tex->set_fullpath(filename);
+  tex->_texture_pool_key = filename;
+
+  {
+    MutexHolder holder(_lock);
+
+    // Now look again.
+    Textures::const_iterator ti;
+    ti = _textures.find(unique_filename);
+    if (ti != _textures.end()) {
+      if ((*ti).second->get_texture_type() == Texture::TT_2d_texture_array) {
+        // This texture was previously loaded, as a 2d texture array
+        return (*ti).second;
+      }
+    }
+
+    _textures[unique_filename] = tex;
+  }
+
+  if (store_record && tex->has_ram_image()) {
+    // Store the on-disk cache record for next time.
+    record->set_data(tex, tex);
+    cache->store(record);
+  }
+
+  nassertr(!tex->get_fullpath().empty(), tex);
+  return tex;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TexturePool::ns_load_cube_map
 //       Access: Private

+ 7 - 0
panda/src/gobj/texturePool.h

@@ -1,5 +1,6 @@
 // Filename: texturePool.h
 // Created by:  drose (26Apr00)
+// Updated by: fperazzi, PandaSE(29Apr10) (added load_2d_texture_array)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -53,6 +54,9 @@ PUBLISHED:
   INLINE static Texture *load_3d_texture(const Filename &filename_pattern,
                                          bool read_mipmaps = false,
                                          const LoaderOptions &options = LoaderOptions());
+  INLINE static Texture *load_2d_texture_array(const Filename &filename_pattern,
+                                               bool read_mipmaps = false,
+                                               const LoaderOptions &options = LoaderOptions());
   INLINE static Texture *load_cube_map(const Filename &filename_pattern,
                                        bool read_mipmaps = false,
                                        const LoaderOptions &options = LoaderOptions());
@@ -108,6 +112,9 @@ private:
   Texture *ns_load_3d_texture(const Filename &filename_pattern,
                               bool read_mipmaps,
                               const LoaderOptions &options);
+  Texture *ns_load_2d_texture_array(const Filename &filename_pattern,
+                                    bool read_mipmaps,
+                                    const LoaderOptions &options);
   Texture *ns_load_cube_map(const Filename &filename_pattern,
                             bool read_mipmaps,
                             const LoaderOptions &options);

+ 5 - 1
panda/src/pgraph/nodePath.cxx

@@ -3420,7 +3420,11 @@ set_texture(Texture *tex, int priority) {
 void NodePath::
 set_texture(TextureStage *stage, Texture *tex, int priority) {
   nassertv_always(!is_empty());
-
+  if (tex->get_texture_type() == Texture::TT_2d_texture_array){
+    pgraph_cat.error() << "Texture::TT_2d_texture_array is not supported by" << \
+     " the fixed pipeline.\n";
+    return;
+  }
   const RenderAttrib *attrib =
     node()->get_attrib(TextureAttrib::get_class_slot());
   if (attrib != (const RenderAttrib *)NULL) {