]> git.mxchange.org Git - simgear.git/blob - simgear/scene/sky/CloudShaderGeometry.cxx
Fixes for headless mode.
[simgear.git] / simgear / scene / sky / CloudShaderGeometry.cxx
1 /* -*-c++-*-
2  *
3  * Copyright (C) 2008 Stuart Buchanan
4  *
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.
9  *
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.
14  *
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,
18  * MA 02110-1301, USA.
19  *
20  */
21
22 #include <algorithm>
23
24 #include <osgDB/Registry>
25 #include <osgDB/Input>
26 #include <osgDB/ParameterOutput>
27
28 #include "CloudShaderGeometry.hxx"
29
30 #include <simgear/props/props.hxx>
31
32 using namespace osg;
33 using namespace osgDB;
34 using namespace simgear;
35
36 namespace
37 {
38 struct SpriteComp
39 {
40     bool operator() (const CloudShaderGeometry::SortData::SortItem& lhs,
41                      const CloudShaderGeometry::SortData::SortItem& rhs) const
42     {
43         return lhs.depth > rhs.depth;
44     }
45 };
46 }
47 namespace simgear
48 {
49 void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
50 {
51     if (!_cloudsprites.size()) return;
52     
53     osg::State& state = *renderInfo.getState();
54     unsigned int contextID = state.getContextID();
55     SortData& sortData = _sortData[contextID];
56     int frameNumber = state.getFrameStamp()->getFrameNumber();
57
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);
64     }
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
69     // are sorted.
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();
74              itr != end;
75              ++itr) {
76             Vec4f projPos
77                 = Vec4f(toOsg(_cloudsprites[itr->idx].position), 1.0f) * mvp;
78             itr->depth = projPos.z() / projPos.w();
79         }
80         // Already sorted?
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;
90             }
91             if (sortData.skip_limit > 128) {
92                 // Maximum of every 128 frames (2 - 4 seconds)
93                 sortData.skip_limit = 128 + sg_random() * 10;
94             }
95
96         } else {
97             std::sort(sortData.spriteIdx->begin(), sortData.spriteIdx->end(),
98                       SpriteComp());
99             sortData.skip_limit = 1;
100         }
101         sortData.frameSorted = frameNumber;
102     }
103
104     const Extensions* extensions = getExtensions(state.getContextID(),true);
105
106     for(SortData::SortItemList::const_iterator itr = sortData.spriteIdx->begin(),
107             end = sortData.spriteIdx->end();
108         itr != end;
109         ++itr) {
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,
113                            (GLfloat) t.width };
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 };
120                            
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);
126     }
127 }
128
129 void CloudShaderGeometry::addSprite(const SGVec3f& p, int tx, int ty,
130                                     float w, float h, float cull)
131 {
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();
136          ++iter) 
137     {
138         if ((iter != _cloudsprites.begin()) &&
139             (distSqr(iter->position, p) < cull)) {
140             // Too close - cull it
141             return;
142         }
143     }
144     
145     _cloudsprites.push_back(CloudSprite(p, tx, ty, w, h));
146 }
147
148 bool CloudShaderGeometry_readLocalData(Object& obj, Input& fr)
149 {
150     bool iteratorAdvanced = false;
151
152     CloudShaderGeometry& geom = static_cast<CloudShaderGeometry&>(obj);
153
154     if ((fr[0].matchWord("geometry"))) {
155         ++fr;
156         iteratorAdvanced = true;
157         osg::Drawable* drawable = fr.readDrawable();
158         if (drawable) {
159             geom._geometry = drawable;
160         }
161     }
162     if ((fr.matchSequence("instances %i"))) {
163         int entry = fr[0].getNoNestedBrackets();
164         int capacity;
165         fr[1].getInt(capacity);
166         geom._cloudsprites.reserve(capacity);
167         fr += 3;
168         iteratorAdvanced = true;
169         // skip {
170         while (!fr.eof() && fr[0].getNoNestedBrackets() > entry) {
171             SGVec3f v;
172             int tx, ty;
173             float w, h;
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)) {
177                     fr += 5;
178                     //SGVec3f* v = new SGVec3f(v.x(), v.y(), v.z());
179                     geom._cloudsprites.push_back(CloudShaderGeometry::CloudSprite(v, tx, ty, w, h));
180             } else {
181                 ++fr;
182             }
183         }
184     }
185     return iteratorAdvanced;
186 }
187
188 bool CloudShaderGeometry_writeLocalData(const Object& obj, Output& fw)
189 {
190     const CloudShaderGeometry& geom = static_cast<const CloudShaderGeometry&>(obj);
191
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;
196     fw.moveIn();
197     for (CloudShaderGeometry::CloudSpriteList::const_iterator itr
198              = geom._cloudsprites.begin();
199          itr != geom._cloudsprites.end();
200          ++itr) {
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;
205     }
206     fw.moveOut();
207     fw.indent() << "}" << std::endl;
208     return true;
209 }
210
211
212 osgDB::RegisterDotOsgWrapperProxy cloudShaderGeometryProxy
213 (
214     new CloudShaderGeometry,
215     "CloudShaderGeometry",
216     "Object Drawable CloudShaderGeometry",
217     &CloudShaderGeometry_readLocalData,
218     &CloudShaderGeometry_writeLocalData
219     );
220 }