3 * Copyright (C) 2008 Stuart Buchanan
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24 #include <osgDB/Registry>
25 #include <osgDB/Input>
26 #include <osgDB/ParameterOutput>
28 #include "CloudShaderGeometry.hxx"
30 #include <simgear/props/props.hxx>
33 using namespace osgDB;
34 using namespace simgear;
40 bool operator() (const CloudShaderGeometry::SortData::SortItem& lhs,
41 const CloudShaderGeometry::SortData::SortItem& rhs) const
43 return lhs.depth > rhs.depth;
49 void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
51 if (!_cloudsprites.size()) return;
53 osg::State& state = *renderInfo.getState();
54 unsigned int contextID = state.getContextID();
55 SortData& sortData = _sortData[contextID];
56 int frameNumber = state.getFrameStamp()->getFrameNumber();
58 if (!sortData.spriteIdx)
59 sortData.spriteIdx = new SortData::SortItemList;
60 if (sortData.spriteIdx->size() < _cloudsprites.size()) {
61 for (unsigned i = sortData.spriteIdx->size(); i < (unsigned)_cloudsprites.size(); ++i)
62 sortData.spriteIdx->push_back(SortData::SortItem(i, 0.0f));
63 sortData.frameSorted = frameNumber - (sortData.skip_limit + 1);
65 // If the cloud is already sorted, then it is likely to still be sorted.
66 // Therefore we can avoid re-sorting it for a period. If it is still
67 // sorted after that period, then we can wait for a longer period before
68 // checking again. In this way, only clouds that are changing regularly
70 if (frameNumber - sortData.skip_limit >= sortData.frameSorted) {
71 Matrix mvp = state.getModelViewMatrix() * state.getProjectionMatrix();
72 for (SortData::SortItemList::iterator itr = sortData.spriteIdx->begin(),
73 end = sortData.spriteIdx->end();
77 = Vec4f(toOsg(_cloudsprites[itr->idx].position), 1.0f) * mvp;
78 itr->depth = projPos.z() / projPos.w();
81 if (std::adjacent_find(sortData.spriteIdx->rbegin(),
82 sortData.spriteIdx->rend(), SpriteComp())
83 == sortData.spriteIdx->rend()) {
84 // This cloud is sorted, so no need to re-sort.
85 sortData.skip_limit = sortData.skip_limit * 2;
86 if (sortData.skip_limit > 30) {
87 // Jitter the skip frames to avoid synchronized sorts
88 // which will cause periodic frame-rate drops
89 sortData.skip_limit += sg_random() * 10;
91 if (sortData.skip_limit > 128) {
92 // Maximum of every 128 frames (2 - 4 seconds)
93 sortData.skip_limit = 128 + sg_random() * 10;
97 std::sort(sortData.spriteIdx->begin(), sortData.spriteIdx->end(),
99 sortData.skip_limit = 1;
101 sortData.frameSorted = frameNumber;
104 const Extensions* extensions = getExtensions(state.getContextID(),true);
106 for(SortData::SortItemList::const_iterator itr = sortData.spriteIdx->begin(),
107 end = sortData.spriteIdx->end();
110 const CloudSprite& t = _cloudsprites[itr->idx];
111 GLfloat ua1[3] = { (GLfloat) t.texture_index_x/varieties_x,
112 (GLfloat) t.texture_index_y/varieties_y,
114 GLfloat ua2[3] = { (GLfloat) t.height,
115 (GLfloat) shade_factor,
116 (GLfloat) cloud_height };
117 GLfloat ua3[3] = { (GLfloat) bottom_factor,
118 (GLfloat) middle_factor,
119 (GLfloat) top_factor };
121 extensions->glVertexAttrib3fv(USR_ATTR_1, ua1 );
122 extensions->glVertexAttrib3fv(USR_ATTR_2, ua2 );
123 extensions->glVertexAttrib3fv(USR_ATTR_3, ua3 );
124 glColor4f(t.position.x(), t.position.y(), t.position.z(), zscale);
125 _geometry->draw(renderInfo);
129 void CloudShaderGeometry::addSprite(const SGVec3f& p, int tx, int ty,
130 float w, float h, float cull)
132 // Only add the sprite if it is further than the cull distance to all other sprites
133 // except for the center sprite.
134 for (CloudShaderGeometry::CloudSpriteList::iterator iter = _cloudsprites.begin();
135 iter != _cloudsprites.end();
138 if ((iter != _cloudsprites.begin()) &&
139 (distSqr(iter->position, p) < cull)) {
140 // Too close - cull it
145 _cloudsprites.push_back(CloudSprite(p, tx, ty, w, h));
148 bool CloudShaderGeometry_readLocalData(Object& obj, Input& fr)
150 bool iteratorAdvanced = false;
152 CloudShaderGeometry& geom = static_cast<CloudShaderGeometry&>(obj);
154 if ((fr[0].matchWord("geometry"))) {
156 iteratorAdvanced = true;
157 osg::Drawable* drawable = fr.readDrawable();
159 geom._geometry = drawable;
162 if ((fr.matchSequence("instances %i"))) {
163 int entry = fr[0].getNoNestedBrackets();
165 fr[1].getInt(capacity);
166 geom._cloudsprites.reserve(capacity);
168 iteratorAdvanced = true;
170 while (!fr.eof() && fr[0].getNoNestedBrackets() > entry) {
174 if (fr[0].getFloat(v.x()) && fr[1].getFloat(v.y())
175 && fr[2].getFloat(v.z()) && fr[3].getInt(tx) && fr[4].getInt(ty) &&
176 fr[5].getFloat(w) && fr[6].getFloat(h)) {
178 //SGVec3f* v = new SGVec3f(v.x(), v.y(), v.z());
179 geom._cloudsprites.push_back(CloudShaderGeometry::CloudSprite(v, tx, ty, w, h));
185 return iteratorAdvanced;
188 bool CloudShaderGeometry_writeLocalData(const Object& obj, Output& fw)
190 const CloudShaderGeometry& geom = static_cast<const CloudShaderGeometry&>(obj);
192 fw.indent() << "geometry" << std::endl;
193 fw.writeObject(*geom._geometry);
194 fw.indent() << "instances " << geom._cloudsprites.size() << std::endl;
195 fw.indent() << "{" << std::endl;
197 for (CloudShaderGeometry::CloudSpriteList::const_iterator itr
198 = geom._cloudsprites.begin();
199 itr != geom._cloudsprites.end();
201 fw.indent() << itr->position.x() << " " << itr->position.y() << " "
202 << itr->position.z() << " " << itr->texture_index_x << " "
203 << itr->texture_index_y << " " << itr->width << " "
204 << itr->height << " " << std::endl;
207 fw.indent() << "}" << std::endl;
212 osgDB::RegisterDotOsgWrapperProxy cloudShaderGeometryProxy
214 new CloudShaderGeometry,
215 "CloudShaderGeometry",
216 "Object Drawable CloudShaderGeometry",
217 &CloudShaderGeometry_readLocalData,
218 &CloudShaderGeometry_writeLocalData