]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/sky/CloudShaderGeometry.cxx
Merge branch 'ehofman/sound'
[simgear.git] / simgear / scene / sky / CloudShaderGeometry.cxx
index 6fe9f8cfbaf28f2584aafd789a764af0e687e5f2..229710db32ba4fa96dad76aa3ec4bf0a59c5820d 100755 (executable)
@@ -19,6 +19,8 @@
  *
  */
 
+#include <algorithm>
+
 #include <osgDB/Registry>
 #include <osgDB/Input>
 #include <osgDB/ParameterOutput>
 
 using namespace osg;
 using namespace osgDB;
+using namespace simgear;
 
+namespace
+{
+struct SpriteComp
+{
+    bool operator() (const CloudShaderGeometry::SortData::SortItem& lhs,
+                     const CloudShaderGeometry::SortData::SortItem& rhs) const
+    {
+        return lhs.depth > rhs.depth;
+    }
+};
+}
 namespace simgear
 {
 void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
 {
+    if (!_cloudsprites.size()) return;
+    
     osg::State& state = *renderInfo.getState();
+    unsigned int contextID = state.getContextID();
+    SortData& sortData = _sortData[contextID];
+    int frameNumber = state.getFrameStamp()->getFrameNumber();
+
+    if (!sortData.spriteIdx)
+        sortData.spriteIdx = new SortData::SortItemList;
+    if (sortData.spriteIdx->size() < _cloudsprites.size()) {
+        for (unsigned i = sortData.spriteIdx->size(); i < (unsigned)_cloudsprites.size(); ++i)
+            sortData.spriteIdx->push_back(SortData::SortItem(i, 0.0f));
+        sortData.frameSorted = frameNumber - (sortData.skip_limit + 1);
+    }
+    // If the cloud is already sorted, then it is likely to still be sorted.
+    // Therefore we can avoid re-sorting it for a period. If it is still
+    // sorted after that period, then we can wait for a longer period before
+    // checking again. In this way, only clouds that are changing regularly
+    // are sorted.
+    if (frameNumber - sortData.skip_limit >= sortData.frameSorted) {
+        Matrix mvp = state.getModelViewMatrix() * state.getProjectionMatrix();
+        for (SortData::SortItemList::iterator itr = sortData.spriteIdx->begin(),
+                 end = sortData.spriteIdx->end();
+             itr != end;
+             ++itr) {
+            Vec4f projPos
+                = Vec4f(toOsg(_cloudsprites[itr->idx].position), 1.0f) * mvp;
+            itr->depth = projPos.z() / projPos.w();
+        }
+        // Already sorted?
+        if (std::adjacent_find(sortData.spriteIdx->rbegin(),
+                               sortData.spriteIdx->rend(), SpriteComp())
+            == sortData.spriteIdx->rend()) {
+            // This cloud is sorted, so no need to re-sort.
+            sortData.skip_limit = sortData.skip_limit * 2;
+            if (sortData.skip_limit > 30) {
+                // Jitter the skip frames to avoid synchronized sorts
+                // which will cause periodic frame-rate drops
+                sortData.skip_limit += sg_random() * 10;
+            }
+            if (sortData.skip_limit > 128) {
+                // Maximum of every 128 frames (2 - 4 seconds)
+                sortData.skip_limit = 128 + sg_random() * 10;
+            }
+
+        } else {
+            std::sort(sortData.spriteIdx->begin(), sortData.spriteIdx->end(),
+                      SpriteComp());
+            sortData.skip_limit = 1;
+        }
+        sortData.frameSorted = frameNumber;
+    }
+
     const Extensions* extensions = getExtensions(state.getContextID(),true);
 
-    for(CloudSpriteList::const_iterator t = _cloudsprites.begin(); t != _cloudsprites.end(); ++t)
-    {
-        extensions->glVertexAttrib1f(TEXTURE_INDEX_X, (GLfloat) t->texture_index_x/varieties_x);
-        extensions->glVertexAttrib1f(TEXTURE_INDEX_Y, (GLfloat) t->texture_index_y/varieties_y);
-        extensions->glVertexAttrib1f(WIDTH, (GLfloat) t->width);
-        extensions->glVertexAttrib1f(HEIGHT, (GLfloat) t->height);
-        extensions->glVertexAttrib1f(SHADE, (GLfloat) t->shade);
-        glColor4f(t->position.x(), t->position.y(), t->position.z(), 1.0);
+    for(SortData::SortItemList::const_iterator itr = sortData.spriteIdx->begin(),
+            end = sortData.spriteIdx->end();
+        itr != end;
+        ++itr) {
+        const CloudSprite& t = _cloudsprites[itr->idx];
+        GLfloat ua1[3] = { (GLfloat) t.texture_index_x/varieties_x,
+                           (GLfloat) t.texture_index_y/varieties_y,
+                          (GLfloat) t.width };
+        GLfloat ua2[3] = { (GLfloat) t.height,
+                          (GLfloat) t.shade,
+                           (GLfloat) t.cloud_height };
+        extensions->glVertexAttrib3fv(USR_ATTR_1, ua1 );
+        extensions->glVertexAttrib3fv(USR_ATTR_2, ua2 );
+        glColor4f(t.position.x(), t.position.y(), t.position.z(), 1.0);
         _geometry->draw(renderInfo);
     }
 }
 
-BoundingBox CloudShaderGeometry::computeBound() const
+void CloudShaderGeometry::addSprite(const SGVec3f& p, int tx, int ty,
+                                    float w, float h,
+                                    float s, float cull, float cloud_height)
 {
-    BoundingBox geom_box = _geometry->getBound();
-    BoundingBox bb;
-    for(CloudSpriteList::const_iterator itr = _cloudsprites.begin();
-        itr != _cloudsprites.end();
-        ++itr) {
-         bb.expandBy(geom_box.corner(0)*itr->width +
-                     osg::Vec3( itr->position.x(), itr->position.y(), itr->position.z() ));
-         bb.expandBy(geom_box.corner(7)*itr->height +
-                     osg::Vec3( itr->position.x(), itr->position.y(), itr->position.z() ));
+    // Only add the sprite if it is further than the cull distance to all other sprites
+    // except for the center sprite.   
+    for (CloudShaderGeometry::CloudSpriteList::iterator iter = _cloudsprites.begin();
+         iter != _cloudsprites.end();
+         ++iter) 
+    {
+        if ((iter != _cloudsprites.begin()) &&
+           (distSqr(iter->position, p) < cull)) {
+            // Too close - cull it
+            return;
+        }
     }
-    return bb;
+
+    _cloudsprites.push_back(CloudSprite(p, tx, ty, w, h, s, cloud_height));
 }
 
 bool CloudShaderGeometry_readLocalData(Object& obj, Input& fr)
@@ -89,13 +166,13 @@ bool CloudShaderGeometry_readLocalData(Object& obj, Input& fr)
         while (!fr.eof() && fr[0].getNoNestedBrackets() > entry) {
             SGVec3f v;
             int tx, ty;
-            float w, h, s;
+            float w, h, s, ch;
             if (fr[0].getFloat(v.x()) && fr[1].getFloat(v.y())
-                && fr[2].getFloat(v.z()) && fr[3].getInt(tx) && fr[3].getInt(ty) &&  
-                fr[4].getFloat(w) && fr[4].getFloat(h)&& fr[4].getFloat(s)) {
+                && fr[2].getFloat(v.z()) && fr[3].getInt(tx) && fr[4].getInt(ty) &&  
+                fr[5].getFloat(w) && fr[6].getFloat(h)&& fr[7].getFloat(s) && fr[8].getFloat(ch)) {
                     fr += 5;
                     //SGVec3f* v = new SGVec3f(v.x(), v.y(), v.z());
-                    geom._cloudsprites.push_back(CloudShaderGeometry::CloudSprite(v, tx, ty, w, h,s));
+                    geom._cloudsprites.push_back(CloudShaderGeometry::CloudSprite(v, tx, ty, w, h,s,ch));
             } else {
                 ++fr;
             }
@@ -113,14 +190,15 @@ bool CloudShaderGeometry_writeLocalData(const Object& obj, Output& fw)
     fw.indent() << "instances " << geom._cloudsprites.size() << std::endl;
     fw.indent() << "{" << std::endl;
     fw.moveIn();
-    for (CloudShaderGeometry::CloudSpriteList::const_iterator iter
+    for (CloudShaderGeometry::CloudSpriteList::const_iterator itr
              = geom._cloudsprites.begin();
-         iter != geom._cloudsprites.end();
-         ++iter) {
-        fw.indent() << iter->position.x() << " " << iter->position.y() << " " 
-                << iter->position.z() << " " << iter->texture_index_x << " "
-                << iter->texture_index_y << " "  
-                << iter->width << " " << iter->height << " " << iter->shade << std::endl;
+         itr != geom._cloudsprites.end();
+         ++itr) {
+             fw.indent() << itr->position.x() << " " << itr->position.y() << " " 
+                     << itr->position.z() << " " << itr->texture_index_x << " "
+                     << itr->texture_index_y << " "  << itr->width << " " 
+                     << itr->height << " " << itr->shade 
+                     << itr->cloud_height << " "<< std::endl;
     }
     fw.moveOut();
     fw.indent() << "}" << std::endl;