Browse Source

Merge remote-tracking branch 'origin/master' into webgl-port

rdb 9 years ago
parent
commit
8c20226fd7

+ 19 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -8350,6 +8350,7 @@ get_external_image_format(Texture *tex) const {
       case Texture::F_blue:
       case Texture::F_r8i:
       case Texture::F_r16:
+      case Texture::F_r16i:
       case Texture::F_r32:
       case Texture::F_r32i:
         return GL_COMPRESSED_RED;
@@ -8555,6 +8556,7 @@ get_external_image_format(Texture *tex) const {
 
 #ifndef OPENGLES_1
   case Texture::F_r8i:
+  case Texture::F_r16i:
   case Texture::F_r32i:
     return GL_RED_INTEGER;
   case Texture::F_rg8i:
@@ -8612,6 +8614,7 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
       case Texture::F_rg8i:
       case Texture::F_rgb8i:
       case Texture::F_rgba8i:
+      case Texture::F_r16i:
       case Texture::F_r32i:
       case Texture::F_r11_g11_b10:
       case Texture::F_rgb9_e5:
@@ -9093,6 +9096,12 @@ get_internal_image_format(Texture *tex, bool force_sized) const {
     } else {
       return GL_R16_SNORM;
     }
+  case Texture::F_r16i:
+    if (Texture::is_unsigned(tex->get_component_type())) {
+      return GL_R16UI;
+    } else {
+      return GL_R16I;
+    }
   case Texture::F_rg16:
     if (tex->get_component_type() == Texture::T_float) {
       return GL_RG16F;
@@ -12683,6 +12692,16 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
     type = Texture::T_unsigned_byte;
     format = Texture::F_rgba8i;
     break;
+
+  case GL_R16I:
+    type = Texture::T_short;
+    format = Texture::F_r16i;
+    break;
+  case GL_R16UI:
+    type = Texture::T_unsigned_short;
+    format = Texture::F_r16i;
+    break;
+
 #endif
 
 #ifndef OPENGLES_1

+ 11 - 2
panda/src/glstuff/glShaderContext_src.cxx

@@ -2666,10 +2666,10 @@ glsl_report_shader_errors(GLuint shader, Shader::ShaderType type, bool fatal) {
   istringstream log(info_log);
   string line;
   while (getline(log, line)) {
-    int fileno, lineno;
+    int fileno, lineno, colno;
     int prefixlen = 0;
 
-    // First is AMDIntel driver syntax, second is NVIDIA syntax.
+    // This first format is used by the majority of compilers.
     if (sscanf(line.c_str(), "ERROR: %d:%d: %n", &fileno, &lineno, &prefixlen) == 2
         && prefixlen > 0) {
 
@@ -2688,10 +2688,19 @@ glsl_report_shader_errors(GLuint shader, Shader::ShaderType type, bool fatal) {
     } else if (sscanf(line.c_str(), "%d(%d) : %n", &fileno, &lineno, &prefixlen) == 2
                && prefixlen > 0) {
 
+      // This is the format NVIDIA uses.
       Filename fn = _shader->get_filename_from_index(fileno, type);
       GLCAT.error(false)
         << fn << "(" << lineno << ") : " << (line.c_str() + prefixlen) << "\n";
 
+    } else if (sscanf(line.c_str(), "%d:%d(%d): %n", &fileno, &lineno, &colno, &prefixlen) == 3
+               && prefixlen > 0) {
+
+      // This is the format for Mesa's OpenGL ES 2 implementation.
+      Filename fn = _shader->get_filename_from_index(fileno, type);
+      GLCAT.error(false)
+        << fn << ":" << lineno << "(" << colno << "): " << (line.c_str() + prefixlen) << "\n";
+
     } else if (!fatal) {
       GLCAT.warning(false) << line << "\n";
 

+ 30 - 0
panda/src/gobj/shader.I

@@ -50,6 +50,36 @@ get_filename(ShaderType type) const {
   }
 }
 
+/**
+ * Sets the Shader's filename for the given shader type.  Useful for
+ * associating a shader created with Shader.make with a name for diagnostics.
+ */
+INLINE void Shader::
+set_filename(ShaderType type, const Filename &filename) {
+  switch (type) {
+  case ST_vertex:
+    _filename._vertex = filename;
+    break;
+  case ST_fragment:
+    _filename._fragment = filename;
+    break;
+  case ST_geometry:
+    _filename._geometry = filename;
+    break;
+  case ST_tess_control:
+    _filename._tess_control = filename;
+    break;
+  case ST_tess_evaluation:
+    _filename._tess_evaluation = filename;
+    break;
+  case ST_compute:
+    _filename._compute = filename;
+    break;
+  default:
+    _filename._shared = filename;
+  }
+}
+
 /**
  * Return the Shader's text for the given shader type.
  */

+ 1 - 0
panda/src/gobj/shader.h

@@ -98,6 +98,7 @@ PUBLISHED:
   static PT(Shader) make_compute(ShaderLanguage lang, const string &body);
 
   INLINE Filename get_filename(ShaderType type = ST_none) const;
+  INLINE void set_filename(ShaderType type, const Filename &filename);
   INLINE const string &get_text(ShaderType type = ST_none) const;
   INLINE bool get_error_flag() const;
   INLINE ShaderLanguage get_language() const;

+ 10 - 0
panda/src/gobj/texture.cxx

@@ -514,6 +514,7 @@ estimate_texture_memory() const {
     break;
 
   case Texture::F_r16:
+  case Texture::F_r16i:
   case Texture::F_rg8i:
     bpp = 2;
     break;
@@ -1532,6 +1533,10 @@ write(ostream &out, int indent_level) const {
   case F_r16:
     out << "r16";
     break;
+  case F_r16i:
+    out << "r16i";
+    break;
+
   case F_rg16:
     out << "rg16";
     break;
@@ -1950,6 +1955,8 @@ format_format(Format format) {
     return "rgba32";
   case F_r16:
     return "r16";
+  case F_r16i:
+    return "r16i";  
   case F_rg16:
     return "rg16";
   case F_rgb16:
@@ -2049,6 +2056,8 @@ string_format(const string &str) {
     return F_rgba32;
   } else if (cmp_nocase(str, "r16") == 0 || cmp_nocase(str, "red16") == 0) {
     return F_r16;
+  } else if (cmp_nocase(str, "r16i") == 0) {
+    return F_r16i;
   } else if (cmp_nocase(str, "rg16") == 0 || cmp_nocase(str, "r16g16") == 0) {
     return F_rg16;
   } else if (cmp_nocase(str, "rgb16") == 0 || cmp_nocase(str, "r16g16b16") == 0) {
@@ -5745,6 +5754,7 @@ do_set_format(CData *cdata, Texture::Format format) {
   case F_alpha:
   case F_luminance:
   case F_r16:
+  case F_r16i:
   case F_sluminance:
   case F_r32i:
   case F_r32:

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

@@ -159,6 +159,7 @@ PUBLISHED:
     F_rgb10_a2,
 
     F_rg,
+    F_r16i
   };
 
   // Deprecated.  See SamplerState.FilterType.

+ 11 - 9
panda/src/grutil/shaderTerrainMesh.I

@@ -12,26 +12,28 @@
  */
 
 /**
- * @brief Sets the path to the heightfield
- * @details This sets the path to the terrain heightfield. It should be 16bit
+ * @brief Sets the heightfield texture
+ * @details This sets the heightfield texture. It should be 16bit
  *   single channel, and have a power-of-two resolution greater than 32.
  *   Common sizes are 2048x2048 or 4096x4096.
  *
- * @param filename Path to the heightfield
+ *   You should call generate() after setting the heightfield.
+ *
+ * @param filename Heightfield texture
  */
-INLINE void ShaderTerrainMesh::set_heightfield_filename(const Filename& filename) {
-  _heightfield_source = filename;
+INLINE void ShaderTerrainMesh::set_heightfield(Texture* heightfield) {
+  _heightfield_tex = heightfield;
 }
 
 /**
- * @brief Returns the heightfield path
- * @details This returns the path of the terrain heightfield, previously set with
+ * @brief Returns the heightfield
+ * @details This returns the terrain heightfield, previously set with
  *   set_heightfield()
  *
  * @return Path to the heightfield
  */
-INLINE const Filename& ShaderTerrainMesh::get_heightfield_filename() const {
-  return _heightfield_source;
+INLINE Texture* ShaderTerrainMesh::get_heightfield() const {
+  return _heightfield_tex;
 }
 
 /**

+ 26 - 32
panda/src/grutil/shaderTerrainMesh.cxx

@@ -35,7 +35,7 @@
 #include "typeHandle.h"
 
 ConfigVariableBool stm_use_hexagonal_layout
-("stm-use-hexagonal-layout", true,
+("stm-use-hexagonal-layout", false,
  PRC_DESC("Set this to true to use a hexagonal vertex layout. This approximates "
           "the heightfield in a better way, however the CLOD transitions might be "
           "visible due to the vertices not matching exactly."));
@@ -81,7 +81,6 @@ ShaderTerrainMesh::ShaderTerrainMesh() :
   PandaNode("ShaderTerrainMesh"),
   _size(0),
   _chunk_size(32),
-  _heightfield_source(""),
   _generate_patches(false),
   _data_texture(NULL),
   _chunk_geom(NULL),
@@ -107,7 +106,7 @@ ShaderTerrainMesh::ShaderTerrainMesh() :
  * @return true if the terrain was initialized, false if an error occured
  */
 bool ShaderTerrainMesh::generate() {
-  if (!do_load_heightfield())
+  if (!do_check_heightfield())
     return false;
 
   if (_chunk_size < 8 || !check_power_of_two(_chunk_size)) {
@@ -120,28 +119,29 @@ bool ShaderTerrainMesh::generate() {
     return false;
   }
 
+  do_extract_heightfield();
   do_create_chunks();
   do_compute_bounds(&_base_chunk);
   do_create_chunk_geom();
   do_init_data_texture();
-  do_convert_heightfield();
+
+  // Clear image after using it, otherwise we have two copies of the heightfield
+  // in memory.
+  _heightfield.clear();
 
   return true;
 }
 
 /**
- * @brief Converts the internal used PNMImage to a Texture
- * @details This converts the internal used PNMImage to a texture object. The
- *   reason for this is, that we need the PNMimage for computing the chunk
- *   bounds, but don't need it afterwards. However, since we have it in ram,
- *   we can just put its contents into a Texture object, which enables the
- *   user to call get_heightfield() instead of manually loading the texture
- *   from disk again to set it as shader input (Panda does not cache PNMImages)
+ * @brief Converts the internal used Texture to a PNMImage
+ * @details This converts the texture passed with set_heightfield to a PNMImage,
+ *   so we can read the pixels in a fast way. This is only used while generating
+ *   the chunks, and the PNMImage is destroyed afterwards.
  */
-void ShaderTerrainMesh::do_convert_heightfield() {
-  _heightfield_tex = new Texture();
-  _heightfield_tex->load(_heightfield);
-  _heightfield_tex->set_keep_ram_image(true);
+void ShaderTerrainMesh::do_extract_heightfield() {
+  nassertv(_heightfield_tex->has_ram_image()); // Heightfield not in RAM, extract ram image first
+
+  _heightfield_tex->store(_heightfield);
 
   if (_heightfield.get_maxval() != 65535) {
     shader_terrain_cat.warning() << "Using non 16-bit heightfield!" << endl;
@@ -150,31 +150,23 @@ void ShaderTerrainMesh::do_convert_heightfield() {
   }
   _heightfield_tex->set_minfilter(SamplerState::FT_linear);
   _heightfield_tex->set_magfilter(SamplerState::FT_linear);
-  _heightfield.clear();
 }
 
 /**
- * @brief Intermal method to load the heightfield
- * @details This method loads the heightfield from the heightfield path,
+ * @brief Intermal method to check the heightfield
+ * @details This method cecks the heightfield generated from the heightfield texture,
  *   and performs some basic checks, including a check for a power of two,
  *   and same width and height.
  *
- * @return true if the heightfield was loaded and meets the requirements
+ * @return true if the heightfield meets the requirements
  */
-bool ShaderTerrainMesh::do_load_heightfield() {
-
-  if(!_heightfield.read(_heightfield_source)) {
-    shader_terrain_cat.error() << "Could not load heightfield from " << _heightfield_source << endl;
-    return false;
-  }
-
-  if (_heightfield.get_x_size() != _heightfield.get_y_size()) {
+bool ShaderTerrainMesh::do_check_heightfield() {
+  if (_heightfield_tex->get_x_size() != _heightfield_tex->get_y_size()) {
     shader_terrain_cat.error() << "Only square heightfields are supported!";
     return false;
   }
 
-  _size = _heightfield.get_x_size();
-
+  _size = _heightfield_tex->get_x_size();
   if (_size < 32 || !check_power_of_two(_size)) {
     shader_terrain_cat.error() << "Invalid heightfield! Needs to be >= 32 and a power of two (was: "
          << _size << ")!" << endl;
@@ -687,8 +679,8 @@ void ShaderTerrainMesh::do_emit_chunk(Chunk* chunk, TraversalData* data) {
   data_entry.size = chunk->size / _chunk_size;
   data_entry.clod = chunk->last_clod;
 
-  data->emitted_chunks ++;
-  data->storage_ptr ++;
+  data->emitted_chunks++;
+  data->storage_ptr++;
 }
 
 /**
@@ -701,7 +693,9 @@ void ShaderTerrainMesh::do_emit_chunk(Chunk* chunk, TraversalData* data) {
  * @return World-Space point
  */
 LPoint3 ShaderTerrainMesh::uv_to_world(const LTexCoord& coord) const {
-  nassertr(_heightfield_tex != NULL, LPoint3(0));
+  nassertr(_heightfield_tex != NULL, LPoint3(0)); // Heightfield not set yet
+  nassertr(_heightfield_tex->has_ram_image(), LPoint3(0)); // Heightfield not in memory
+
   PT(TexturePeeker) peeker = _heightfield_tex->peek();
   nassertr(peeker != NULL, LPoint3(0));
 

+ 5 - 6
panda/src/grutil/shaderTerrainMesh.h

@@ -55,9 +55,9 @@ PUBLISHED:
 
   ShaderTerrainMesh();
 
-  INLINE void set_heightfield_filename(const Filename& filename);
-  INLINE const Filename& get_heightfield_filename() const;
-  MAKE_PROPERTY(heightfield_filename, get_heightfield_filename, set_heightfield_filename);
+  INLINE void set_heightfield(Texture* heightfield);
+  INLINE Texture* get_heightfield() const;
+  MAKE_PROPERTY(heightfield, get_heightfield, set_heightfield);
 
   INLINE void set_chunk_size(size_t chunk_size);
   INLINE size_t get_chunk_size() const;
@@ -152,8 +152,8 @@ private:
     ChunkDataEntry* storage_ptr;
   };
 
-  bool do_load_heightfield();
-  void do_convert_heightfield();
+  bool do_check_heightfield();
+  void do_extract_heightfield();
   void do_init_data_texture();
   void do_create_chunks();
   void do_init_chunk(Chunk* chunk);
@@ -164,7 +164,6 @@ private:
   bool do_check_lod_matches(Chunk* chunk, TraversalData* data);
 
   Chunk _base_chunk;
-  Filename _heightfield_source;
   size_t _size;
   size_t _chunk_size;
   bool _generate_patches;

+ 13 - 11
samples/shader-terrain/main.py

@@ -2,16 +2,15 @@
 
 # Author: tobspr
 #
-# Last Updated: 2016-02-13
+# Last Updated: 2016-04-30
 #
 # This tutorial provides an example of using the ShaderTerrainMesh class
 
-import os, sys, math, random
-
 from direct.showbase.ShowBase import ShowBase
 from panda3d.core import ShaderTerrainMesh, Shader, load_prc_file_data
 from panda3d.core import SamplerState
 
+
 class ShaderTerrainDemo(ShowBase):
     def __init__(self):
 
@@ -19,14 +18,14 @@ class ShaderTerrainDemo(ShowBase):
         # before the ShowBase is initialized
         load_prc_file_data("", """
             textures-power-2 none
-            window-title Panda3D Shader Terrain Demo
             gl-coordinate-system default
+            window-title Panda3D ShaderTerrainMesh Demo
         """)
 
         # Initialize the showbase
         ShowBase.__init__(self)
 
-        # Increase camera FOV aswell as the far plane
+        # Increase camera FOV as well as the far plane
         self.camLens.set_fov(90)
         self.camLens.set_near_far(0.1, 50000)
 
@@ -35,7 +34,7 @@ class ShaderTerrainDemo(ShowBase):
 
         # Set a heightfield, the heightfield should be a 16-bit png and
         # have a quadratic size of a power of two.
-        self.terrain_node.heightfield_filename = "heightfield.png"
+        self.terrain_node.heightfield = self.loader.loadTexture("heightfield.png")
 
         # Set the target triangle width. For a value of 10.0 for example,
         # the terrain will attempt to make every triangle 10 pixels wide on screen.
@@ -44,24 +43,28 @@ class ShaderTerrainDemo(ShowBase):
         # Generate the terrain
         self.terrain_node.generate()
 
-        # Attach the terrain to the main scene and set its scale
+        # Attach the terrain to the main scene and set its scale. With no scale
+        # set, the terrain ranges from (0, 0, 0) to (1, 1, 1)
         self.terrain = self.render.attach_new_node(self.terrain_node)
         self.terrain.set_scale(1024, 1024, 100)
         self.terrain.set_pos(-512, -512, -70.0)
 
         # Set a shader on the terrain. The ShaderTerrainMesh only works with
-        # an applied shader. You can use the shaders used here in your own shaders
+        # an applied shader. You can use the shaders used here in your own application
         terrain_shader = Shader.load(Shader.SL_GLSL, "terrain.vert.glsl", "terrain.frag.glsl")
         self.terrain.set_shader(terrain_shader)
         self.terrain.set_shader_input("camera", self.camera)
 
+        # Shortcut to view the wireframe mesh
+        self.accept("f3", self.toggleWireframe)
+
         # Set some texture on the terrain
         grass_tex = self.loader.loadTexture("textures/grass.png")
         grass_tex.set_minfilter(SamplerState.FT_linear_mipmap_linear)
         grass_tex.set_anisotropic_degree(16)
         self.terrain.set_texture(grass_tex)
 
-        # Load some skybox - you can safely ignore this code
+        # Load a skybox - you can safely ignore this code
         skybox = self.loader.loadModel("models/skybox.bam")
         skybox.reparent_to(self.render)
         skybox.set_scale(20000)
@@ -77,5 +80,4 @@ class ShaderTerrainDemo(ShowBase):
         skybox_shader = Shader.load(Shader.SL_GLSL, "skybox.vert.glsl", "skybox.frag.glsl")
         skybox.set_shader(skybox_shader)
 
-demo = ShaderTerrainDemo()
-demo.run()
+ShaderTerrainDemo().run()