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