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::Drawable::UpdateCallback
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
397
398 osgText::Text::AutoTransformCache& atc = _autoTransformCache[renderInfo.getContextID()];
399
400 osg::Matrix lmv = atc._matrix;
401 lmv.postMult(state.getModelViewMatrix());
402
403 if (renderInfo.getView() && renderInfo.getView()->getCamera())
404 {
405 // move from camera into the view space.
406 lmv.postMult(state.getInitialInverseViewMatrix());
407 lmv.postMult(renderInfo.getView()->getCamera()->getViewMatrix());
408 }
409
410 FadeTextData ftd(const_cast<osgText::FadeText*>(this));
411
412 ftd._vertices[0].set(osg::Vec3d(_textBB.xMin(),_textBB.yMin(),_textBB.zMin())*lmv);
413 ftd._vertices[1].set(osg::Vec3d(_textBB.xMax(),_textBB.yMin(),_textBB.zMin())*lmv);
414 ftd._vertices[2].set(osg::Vec3d(_textBB.xMax(),_textBB.yMax(),_textBB.zMin())*lmv);
415 ftd._vertices[3].set(osg::Vec3d(_textBB.xMin(),_textBB.yMax(),_textBB.zMin())*lmv);
416
417 userData->_fadeTextInView.push_back(ftd);
418
419 }
420