1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12 */
13 
14 
15 #include <osgText/FadeText>
16 #include <osg/Notify>
17 #include <osg/io_utils>
18 #include <OpenThreads/Mutex>
19 #include <OpenThreads/ScopedLock>
20 
21 using namespace osgText;
22 
23 struct FadeTextData : public osg::Referenced
24 {
FadeTextDataFadeTextData25     FadeTextData(FadeText* fadeText=0):
26         _fadeText(fadeText),
27         _visible(true) {}
28 
operator <FadeTextData29     bool operator < (const FadeTextData& rhs) const
30     {
31         return _fadeText < rhs._fadeText;
32     }
33 
getNearestZFadeTextData34     double getNearestZ() const
35     {
36         double nearestZ = _vertices[0].z();
37         if (nearestZ < _vertices[1].z()) nearestZ = _vertices[1].z();
38         if (nearestZ < _vertices[2].z()) nearestZ = _vertices[2].z();
39         if (nearestZ < _vertices[3].z()) nearestZ = _vertices[3].z();
40 
41         // OSG_NOTICE<<"getNearestZ()="<<_fadeText->getText().createUTF8EncodedString()<<" "<<nearestZ<<std::endl;
42 
43         return nearestZ;
44     }
45 
46     FadeText*   _fadeText;
47     osg::Vec3d   _vertices[4];
48     bool        _visible;
49 };
50 
51 struct FadeTextPolytopeData : public FadeTextData, public osg::Polytope
52 {
FadeTextPolytopeDataFadeTextPolytopeData53     FadeTextPolytopeData(FadeTextData& fadeTextData):
54         FadeTextData(fadeTextData)
55     {
56         _referenceVertexList.push_back(_vertices[0]);
57         _referenceVertexList.push_back(_vertices[1]);
58         _referenceVertexList.push_back(_vertices[2]);
59         _referenceVertexList.push_back(_vertices[3]);
60     }
61 
addEdgePlaneFadeTextPolytopeData62     void addEdgePlane(const osg::Vec3& corner, const osg::Vec3& edge)
63     {
64         osg::Vec3 normal( edge.y(), -edge.x(), 0.0f);
65         normal.normalize();
66 
67         add(osg::Plane(normal, corner));
68     }
69 
buildPolytopeFadeTextPolytopeData70     void buildPolytope()
71     {
72         osg::Vec3d edge01 = _vertices[1] - _vertices[0];
73         osg::Vec3d edge12 = _vertices[2] - _vertices[1];
74 
75         osg::Vec3d normalFrontFace = edge01 ^ edge12;
76         bool needToFlip = normalFrontFace.z()>0.0f;
77 
78         normalFrontFace.normalize();
79         add(osg::Plane(normalFrontFace, _vertices[0]));
80 
81         add(osg::Plane( osg::Vec3d(0.0f,0.0f,0.0f), _vertices[0], _vertices[1]));
82         add(osg::Plane( osg::Vec3d(0.0f,0.0f,0.0f), _vertices[1], _vertices[2]));
83         add(osg::Plane( osg::Vec3d(0.0f,0.0f,0.0f), _vertices[2], _vertices[3]));
84         add(osg::Plane( osg::Vec3d(0.0f,0.0f,0.0f), _vertices[3], _vertices[0]));
85 
86 #if 0
87         OSG_NOTICE<<" normalFrontFace = "<<normalFrontFace<<std::endl;
88         OSG_NOTICE<<" edge01 = "<<edge01<<std::endl;
89         OSG_NOTICE<<" edge12 = "<<edge12<<std::endl;
90         OSG_NOTICE<<" _vertices[0]= "<<_vertices[0]<<std::endl;
91         OSG_NOTICE<<" _vertices[1]= "<<_vertices[1]<<std::endl;
92         OSG_NOTICE<<" _vertices[2]= "<<_vertices[2]<<std::endl;
93         OSG_NOTICE<<" _vertices[3]= "<<_vertices[3]<<std::endl;
94 #endif
95 
96         if (needToFlip) flip();
97 
98 #if 0
99         OSG_NOTICE<<"   plane 0 "<< _planeList[0]<<std::endl;
100         OSG_NOTICE<<"   plane 1 "<< _planeList[1]<<std::endl;
101         OSG_NOTICE<<"   plane 2 "<< _planeList[2]<<std::endl;
102         OSG_NOTICE<<"   plane 3 "<< _planeList[3]<<std::endl;
103         OSG_NOTICE<<"   plane 4 "<< _planeList[4]<<std::endl;
104 #endif
105 
106     }
107 
containsFadeTextPolytopeData108     inline bool contains(const std::vector<osg::Vec3>& vertices)
109     {
110         for(std::vector<osg::Vec3>::const_iterator itr = vertices.begin();
111             itr != vertices.end();
112             ++itr)
113         {
114             if (osg::Polytope::contains(*itr))
115             {
116                 return true;
117             }
118         }
119         return false;
120     }
121 
122 };
123 
124 struct FadeTextUserData : public osg::Referenced
125 {
FadeTextUserDataFadeTextUserData126     FadeTextUserData():
127         _frameNumber(0) {}
128 
129     typedef std::list<FadeTextData> FadeTextList;
130     unsigned int _frameNumber;
131     FadeTextList _fadeTextInView;
132 };
133 
134 struct GlobalFadeText : public osg::Referenced
135 {
136     typedef std::set< osg::ref_ptr<FadeTextUserData> > UserDataSet;
137     typedef std::set<FadeText*> FadeTextSet;
138     typedef std::multimap<double, osg::ref_ptr<FadeTextPolytopeData> > FadeTextPolytopeMap;
139     typedef std::map<osg::View*, UserDataSet> ViewUserDataMap;
140     typedef std::map<osg::View*, FadeTextSet > ViewFadeTextMap;
141 
GlobalFadeTextGlobalFadeText142     GlobalFadeText():
143         _frameNumber(0xffffffff)
144     {
145     }
146 
147 
createNewFadeTextUserDataGlobalFadeText148     FadeTextUserData* createNewFadeTextUserData(osg::View* view)
149     {
150         OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
151 
152         FadeTextUserData* userData = new FadeTextUserData;
153 
154         if (!userData)
155         {
156             OSG_NOTICE<<"Memory error, unable to create FadeTextUserData."<<std::endl;
157             return 0;
158         }
159 
160         _viewMap[view].insert(userData);
161 
162         return userData;
163     }
164 
165 
updateGlobalFadeText166     void update(unsigned int frameNumber)
167     {
168         _frameNumber = frameNumber;
169 
170         for(GlobalFadeText::ViewUserDataMap::iterator vitr = _viewMap.begin();
171             vitr != _viewMap.end();
172             ++vitr)
173         {
174 
175             osg::View* view = vitr->first;
176 
177             FadeTextSet& fadeTextSet = _viewFadeTextMap[view];
178             fadeTextSet.clear();
179 
180             FadeTextPolytopeMap fadeTextPolytopeMap;
181 
182             for(GlobalFadeText::UserDataSet::iterator uitr = vitr->second.begin();
183                 uitr != vitr->second.end();
184                 ++uitr)
185             {
186                 FadeTextUserData* userData = uitr->get();
187 
188                 int frameDelta = frameNumber - userData->_frameNumber;
189                 if (frameDelta<=1)
190                 {
191                     for(FadeTextUserData::FadeTextList::iterator fitr = userData->_fadeTextInView.begin();
192                         fitr != userData->_fadeTextInView.end();
193                         ++fitr)
194                     {
195                         FadeTextData& fadeTextData = *fitr;
196                         if (fadeTextSet.count(fadeTextData._fadeText)==0)
197                         {
198                             fadeTextSet.insert(fadeTextData._fadeText);
199                             fadeTextPolytopeMap.insert(FadeTextPolytopeMap::value_type(
200                                 -fadeTextData.getNearestZ(), new FadeTextPolytopeData(fadeTextData)));
201                         }
202                     }
203                 }
204             }
205 
206             // for each FadeTexPoltopeData
207             //    create polytopes
208             //    test against all FTPD's later in the list
209             //       test all control points on FTPD against each plane of the current polytope
210             //       if all control points removed or outside then discard FTPD and make FT visible = false;
211 
212             FadeTextPolytopeMap::iterator outer_itr = fadeTextPolytopeMap.begin();
213             while (outer_itr != fadeTextPolytopeMap.end())
214             {
215                 FadeTextPolytopeMap::iterator inner_itr = outer_itr;
216                 ++inner_itr;
217 
218                 if (inner_itr == fadeTextPolytopeMap.end()) break;
219 
220                 FadeTextPolytopeData& outer_ftpm = *(outer_itr->second);
221                 outer_ftpm.buildPolytope();
222 
223                 // OSG_NOTICE<<"Outer z "<<outer_ftpm.getNearestZ()<<std::endl;
224 
225                 while(inner_itr != fadeTextPolytopeMap.end())
226                 {
227                     FadeTextPolytopeData& inner_ftpm = *(inner_itr->second);
228 
229                     // OSG_NOTICE<<"Inner z "<<inner_ftpm.getNearestZ()<<std::endl;
230 
231                     if (outer_ftpm.contains(inner_ftpm.getReferenceVertexList()))
232                     {
233                         FadeTextPolytopeMap::iterator erase_itr = inner_itr;
234                         // move to next ftpm
235                         ++inner_itr;
236 
237                         fadeTextSet.erase(inner_ftpm._fadeText);
238 
239                         // need to remove inner_ftpm as its occluded.
240                         fadeTextPolytopeMap.erase(erase_itr);
241 
242                     }
243                     else
244                     {
245                         // move to next ftpm
246                         ++inner_itr;
247                     }
248                 }
249 
250                 ++outer_itr;
251 
252             }
253         }
254     }
255 
updateIfRequiredGlobalFadeText256     inline void updateIfRequired(unsigned int frameNumber)
257     {
258         if (_frameNumber!=frameNumber) update(frameNumber);
259     }
260 
261     unsigned int _frameNumber;
262     OpenThreads::Mutex _mutex;
263     ViewUserDataMap _viewMap;
264     ViewFadeTextMap _viewFadeTextMap;
265 };
266 
getGlobalFadeText()267 GlobalFadeText* getGlobalFadeText()
268 {
269     static osg::ref_ptr<GlobalFadeText> s_globalFadeText = new GlobalFadeText;
270     return s_globalFadeText.get();
271 }
272 
273 struct FadeText::FadeTextUpdateCallback : public osg::DrawableUpdateCallback
274 {
275     FadeTextData _ftd;
276 
updateFadeText::FadeTextUpdateCallback277     virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable)
278     {
279         osgText::FadeText* fadeText = dynamic_cast<osgText::FadeText*>(drawable);
280         if (!fadeText) return;
281 
282         unsigned int frameNumber = nv->getFrameStamp()->getFrameNumber();
283 
284         GlobalFadeText* gft = getGlobalFadeText();
285         gft->updateIfRequired(frameNumber);
286 
287         osgText::FadeText::ViewBlendColourMap& vbcm = fadeText->getViewBlendColourMap();
288 
289         _ftd._fadeText = fadeText;
290 
291         float fadeSpeed = fadeText->getFadeSpeed();
292 
293         GlobalFadeText::ViewFadeTextMap& vftm = gft->_viewFadeTextMap;
294         for(GlobalFadeText::ViewFadeTextMap::iterator itr = vftm.begin();
295             itr != vftm.end();
296             ++itr)
297         {
298             osg::View* view = itr->first;
299             GlobalFadeText::FadeTextSet& fadeTextSet = itr->second;
300             bool visible = fadeTextSet.count(fadeText)!=0;
301 
302             osg::Vec4& tec = vbcm[view];
303             tec[0] = 1.0f;
304             tec[1] = 1.0f;
305             tec[2] = 1.0f;
306             if (visible)
307             {
308                 if (tec[3]<1.0f)
309                 {
310                     tec[3] += fadeSpeed;
311                     if (tec[3]>1.0f) tec[3] = 1.0f;
312                 }
313 
314             }
315             else
316             {
317                 if (tec[3]>0.0f)
318                 {
319                     tec[3] -= fadeSpeed;
320                     if (tec[3]<0.0f) tec[3] = 0.0f;
321                 }
322             }
323         }
324 
325     }
326 };
327 
328 
FadeText()329 FadeText::FadeText()
330 {
331     init();
332 }
333 
FadeText(const Text & text,const osg::CopyOp & copyop)334 FadeText::FadeText(const Text& text,const osg::CopyOp& copyop):
335     Text(text,copyop)
336 {
337     init();
338 }
339 
init()340 void FadeText::init()
341 {
342     setDataVariance(osg::Object::DYNAMIC);
343 
344     _fadeSpeed = 0.01f;
345     setUpdateCallback(new FadeTextUpdateCallback());
346 }
347 
348 
349 
drawImplementation(osg::RenderInfo & renderInfo) const350 void FadeText::drawImplementation(osg::RenderInfo& renderInfo) const
351 {
352 
353     osg::State& state = *renderInfo.getState();
354 
355     ViewBlendColourMap::iterator itr = _viewBlendColourMap.find(renderInfo.getView());
356     if (itr != _viewBlendColourMap.end())
357     {
358         Text::drawImplementation(*renderInfo.getState(), itr->second );
359     }
360     else
361     {
362         Text::drawImplementation(*renderInfo.getState(), osg::Vec4(1.0f,1.0f,1.0f,1.0f) );
363     }
364 
365 
366     // now pass on new details
367 
368     FadeTextUserData* userData = dynamic_cast<FadeTextUserData*>(renderInfo.getUserData());
369     if (!userData)
370     {
371         if (renderInfo.getUserData())
372         {
373             OSG_NOTICE<<"Warning user data not of supported type."<<std::endl;
374             return;
375         }
376 
377         userData = getGlobalFadeText()->createNewFadeTextUserData(renderInfo.getView());
378 
379         if (!userData)
380         {
381             OSG_NOTICE<<"Memory error, unable to create FadeTextUserData."<<std::endl;
382             return;
383         }
384 
385         renderInfo.setUserData(userData);
386     }
387 
388     unsigned int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
389     if (frameNumber != userData->_frameNumber)
390     {
391         // new frame so must reset UserData structure.
392         userData->_frameNumber = frameNumber;
393         userData->_fadeTextInView.clear();
394     }
395 
396     osg::Matrix lmv = state.getModelViewMatrix();
397     computeMatrix(lmv, &state);
398     lmv.postMult(state.getModelViewMatrix());
399 
400     if (renderInfo.getView() && renderInfo.getView()->getCamera())
401     {
402         // move from camera into the view space.
403         lmv.postMult(state.getInitialInverseViewMatrix());
404         lmv.postMult(renderInfo.getView()->getCamera()->getViewMatrix());
405     }
406 
407     FadeTextData ftd(const_cast<osgText::FadeText*>(this));
408 
409     ftd._vertices[0].set(osg::Vec3d(_textBB.xMin(),_textBB.yMin(),_textBB.zMin())*lmv);
410     ftd._vertices[1].set(osg::Vec3d(_textBB.xMax(),_textBB.yMin(),_textBB.zMin())*lmv);
411     ftd._vertices[2].set(osg::Vec3d(_textBB.xMax(),_textBB.yMax(),_textBB.zMin())*lmv);
412     ftd._vertices[3].set(osg::Vec3d(_textBB.xMin(),_textBB.yMax(),_textBB.zMin())*lmv);
413 
414     userData->_fadeTextInView.push_back(ftd);
415 
416 }
417