1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2014 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 #include <osgUI/Style>
15 #include <osg/io_utils>
16 #include <osg/Geode>
17 #include <osg/ShapeDrawable>
18 #include <osg/Depth>
19 #include <osg/TexGen>
20 #include <osg/AlphaFunc>
21 #include <osg/MatrixTransform>
22 #include <osg/ComputeBoundsVisitor>
23 #include <osgUtil/Optimizer>
24 #include <osgText/Text>
25 #include <osgDB/ReadFile>
26
27 using namespace osgUI;
28
instance()29 osg::ref_ptr<Style>& Style::instance()
30 {
31 static osg::ref_ptr<Style> s_style = new Style;
32 return s_style;
33 }
34
OSG_INIT_SINGLETON_PROXY(StyleSingletonProxy,Style::instance ())35 OSG_INIT_SINGLETON_PROXY(StyleSingletonProxy, Style::instance())
36
37 Style::Style()
38 {
39 osg::ref_ptr<osg::Image> image = new osg::Image;
40 image->allocateImage(1,1,1,GL_RGBA, GL_FLOAT);
41 *(reinterpret_cast<osg::Vec4f*>(image->data(0,0,0))) = osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f);
42
43 _clipTexture = new osg::Texture2D;
44 _clipTexture->setImage(image.get());
45 _clipTexture->setBorderColor(osg::Vec4f(1.0f,1.0f,1.0f,0.0f));
46 _clipTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER);
47 _clipTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER);
48 _clipTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
49 _clipTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
50
51 //image = osgDB::readImageFile("Images/lz.rgb");
52 //_clipTexture->setImage(image.get());
53
54 _disabledDepthWrite = new osg::Depth(osg::Depth::LESS,0.0, 1.0,false);
55 _enabledDepthWrite = new osg::Depth(osg::Depth::LESS,0.0, 1.0,true);
56 _disableColorWriteMask = new osg::ColorMask(false, false, false, false);
57 }
58
Style(const Style & style,const osg::CopyOp & copyop)59 Style::Style(const Style& style, const osg::CopyOp& copyop):
60 osg::Object(style, copyop),
61 _clipTexture(style._clipTexture)
62 {
63 }
64
createFrame(const osg::BoundingBox & extents,const FrameSettings * frameSettings,const osg::Vec4 & color)65 osg::Node* Style::createFrame(const osg::BoundingBox& extents, const FrameSettings* frameSettings, const osg::Vec4& color)
66 {
67 // OSG_NOTICE<<"createFrame"<<std::endl;
68
69 osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
70 geometry->setName("Frame");
71
72 float topScale = 1.0f;
73 float bottomScale = 1.0f;
74 float leftScale = 1.0f;
75 float rightScale = 1.0f;
76
77 if (frameSettings)
78 {
79 switch(frameSettings->getShadow())
80 {
81 case(FrameSettings::PLAIN):
82 // default settings are appropriate for PLAIN
83 break;
84 case(FrameSettings::SUNKEN):
85 topScale = 0.6f;
86 bottomScale = 1.2f;
87 leftScale = 0.8f;
88 rightScale = 0.8f;
89 break;
90 case(FrameSettings::RAISED):
91 topScale = 1.2f;
92 bottomScale = 0.6f;
93 leftScale = 0.8f;
94 rightScale = 0.8f;
95 break;
96 }
97 }
98
99 osg::Vec4 topColor(osg::minimum(color.r()*topScale,1.0f), osg::minimum(color.g()*topScale,1.0f), osg::minimum(color.b()*topScale,1.0f), color.a());
100 osg::Vec4 bottomColor(osg::minimum(color.r()*bottomScale,1.0f), osg::minimum(color.g()*bottomScale,1.0f), osg::minimum(color.b()*bottomScale,1.0f), color.a());
101 osg::Vec4 leftColor(osg::minimum(color.r()*leftScale,1.0f), osg::minimum(color.g()*leftScale,1.0f), osg::minimum(color.b()*leftScale,1.0f), color.a());
102 osg::Vec4 rightColor(osg::minimum(color.r()*rightScale,1.0f), osg::minimum(color.g()*rightScale,1.0f), osg::minimum(color.b()*rightScale,1.0f), color.a());
103
104 float lineWidth = frameSettings ? frameSettings->getLineWidth() : 1.0f;
105
106 osg::Vec3 outerBottomLeft(extents.xMin(), extents.yMin(), extents.zMin());
107 osg::Vec3 outerBottomRight(extents.xMax(), extents.yMin(), extents.zMin());
108 osg::Vec3 outerTopLeft(extents.xMin(), extents.yMax(), extents.zMin());
109 osg::Vec3 outerTopRight(extents.xMax(), extents.yMax(), extents.zMin());
110
111 osg::Vec3 innerBottomLeft(extents.xMin()+lineWidth, extents.yMin()+lineWidth, extents.zMin());
112 osg::Vec3 innerBottomRight(extents.xMax()-lineWidth, extents.yMin()+lineWidth, extents.zMin());
113 osg::Vec3 innerTopLeft(extents.xMin()+lineWidth, extents.yMax()-lineWidth, extents.zMin());
114 osg::Vec3 innerTopRight(extents.xMax()-lineWidth, extents.yMax()-lineWidth, extents.zMin());
115
116 osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
117 geometry->setVertexArray(vertices.get());
118
119 vertices->push_back( outerBottomLeft ); // 0
120 vertices->push_back( outerBottomRight ); // 1
121 vertices->push_back( outerTopLeft ); // 2
122 vertices->push_back( outerTopRight ); // 3
123
124 vertices->push_back( innerBottomLeft ); // 4
125 vertices->push_back( innerBottomRight ); // 5
126 vertices->push_back( innerTopLeft ); // 6
127 vertices->push_back( innerTopRight ); // 7
128
129 osg::ref_ptr<osg::Vec4Array> colours = new osg::Vec4Array;
130 geometry->setColorArray(colours.get(), osg::Array::BIND_PER_PRIMITIVE_SET);
131
132 // bottom
133 {
134 colours->push_back(bottomColor);
135
136 osg::ref_ptr<osg::DrawElementsUShort> primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP);
137 geometry->addPrimitiveSet(primitives.get());
138 primitives->push_back(4);
139 primitives->push_back(0);
140 primitives->push_back(5);
141 primitives->push_back(1);
142 }
143
144 // top
145 {
146 colours->push_back(topColor);
147
148 osg::ref_ptr<osg::DrawElementsUShort> primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP);
149 geometry->addPrimitiveSet(primitives.get());
150 primitives->push_back(2);
151 primitives->push_back(6);
152 primitives->push_back(3);
153 primitives->push_back(7);
154 }
155
156 // left
157 {
158 colours->push_back(leftColor);
159
160 osg::ref_ptr<osg::DrawElementsUShort> primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP);
161 geometry->addPrimitiveSet(primitives.get());
162 primitives->push_back(2);
163 primitives->push_back(0);
164 primitives->push_back(6);
165 primitives->push_back(4);
166 }
167
168 // right
169 {
170 colours->push_back(rightColor);
171
172 osg::ref_ptr<osg::DrawElementsUShort> primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP);
173 geometry->addPrimitiveSet(primitives.get());
174 primitives->push_back(7);
175 primitives->push_back(5);
176 primitives->push_back(3);
177 primitives->push_back(1);
178 }
179
180 return geometry.release();
181 }
182
createText(const osg::BoundingBox & extents,const AlignmentSettings * as,const TextSettings * ts,const std::string & text)183 osg::Node* Style::createText(const osg::BoundingBox& extents, const AlignmentSettings* as, const TextSettings* ts, const std::string& text)
184 {
185 // OSG_NOTICE<<"createText"<<std::endl;
186
187 osg::Vec4 textColor(0.0f,0.0,0.0f,1.0);
188
189 osg::ref_ptr<osgText::Text> textDrawable = new osgText::Text;
190 textDrawable->setName("Text");
191
192 textDrawable->setText(text);
193 textDrawable->setEnableDepthWrites(false);
194 textDrawable->setColor(textColor);
195
196 if (ts)
197 {
198 textDrawable->setFont(ts->getFont());
199 textDrawable->setCharacterSize(ts->getCharacterSize());
200 }
201
202 AlignmentSettings::Alignment alignment = as ? as->getAlignment() : AlignmentSettings::CENTER_CENTER;
203 textDrawable->setAlignment(static_cast<osgText::TextBase::AlignmentType>(alignment));
204
205 switch(alignment)
206 {
207 case(AlignmentSettings::LEFT_TOP):
208 textDrawable->setPosition( osg::Vec3(extents.xMin(), extents.yMax(), extents.zMin()) );
209 break;
210 case(AlignmentSettings::LEFT_CENTER):
211 textDrawable->setPosition( osg::Vec3(extents.xMin(), (extents.yMin()+extents.yMax())*0.5f, extents.zMin()) );
212 break;
213 case(AlignmentSettings::LEFT_BOTTOM):
214 textDrawable->setPosition( osg::Vec3(extents.xMin(), extents.yMin(), extents.zMin()) );
215 break;
216
217 case(AlignmentSettings::CENTER_TOP):
218 textDrawable->setPosition( osg::Vec3((extents.xMin()+extents.xMax())*0.5f, extents.yMax(), extents.zMin()) );
219 break;
220 case(AlignmentSettings::CENTER_CENTER):
221 textDrawable->setPosition( osg::Vec3((extents.xMin()+extents.xMax())*0.5f, (extents.yMin()+extents.yMax())*0.5f, extents.zMin()) );
222 break;
223 case(AlignmentSettings::CENTER_BOTTOM):
224 textDrawable->setPosition( osg::Vec3((extents.xMin()+extents.xMax())*0.5f, extents.yMin(), extents.zMin()) );
225 break;
226
227 case(AlignmentSettings::RIGHT_TOP):
228 textDrawable->setPosition( osg::Vec3(extents.xMax(), extents.yMax(), extents.zMin()) );
229 break;
230 case(AlignmentSettings::RIGHT_CENTER):
231 textDrawable->setPosition( osg::Vec3(extents.xMax(), (extents.yMin()+extents.yMax())*0.5f, extents.zMin()) );
232 break;
233 case(AlignmentSettings::RIGHT_BOTTOM):
234 textDrawable->setPosition( osg::Vec3(extents.xMax(), extents.yMin(), extents.zMin()) );
235 break;
236
237 case(AlignmentSettings::LEFT_BASE_LINE):
238 OSG_NOTICE<<"Text : LEFT_BASE_LINE"<<std::endl;
239 textDrawable->setPosition( osg::Vec3(extents.xMin(), (extents.yMin()+extents.yMax())*0.5f-textDrawable->getCharacterHeight()*0.5f, extents.zMin()) );
240 break;
241 case(AlignmentSettings::CENTER_BASE_LINE):
242 textDrawable->setPosition( osg::Vec3((extents.xMin()+extents.xMax())*0.5f, (extents.yMin()+extents.yMax())*0.5f-textDrawable->getCharacterHeight()*0.5, extents.zMin()) );
243 break;
244 case(AlignmentSettings::RIGHT_BASE_LINE):
245 textDrawable->setPosition( osg::Vec3(extents.xMax(), (extents.yMin()+extents.yMax())*0.5f-textDrawable->getCharacterHeight()*0.5, extents.zMin()) );
246 break;
247
248 case(AlignmentSettings::LEFT_BOTTOM_BASE_LINE):
249 case(AlignmentSettings::CENTER_BOTTOM_BASE_LINE):
250 case(AlignmentSettings::RIGHT_BOTTOM_BASE_LINE):
251
252 default:
253 textDrawable->setPosition( osg::Vec3(extents.xMin(), extents.yMin(), extents.zMin()) );
254 break;
255 }
256
257 return textDrawable.release();
258 }
259
createIcon(const osg::BoundingBox & extents,const std::string & filename,const osg::Vec4 & color)260 osg::Node* Style::createIcon(const osg::BoundingBox& extents, const std::string& filename, const osg::Vec4& color)
261 {
262 osg::ref_ptr<osg::Object> object = osgDB::readRefObjectFile(filename);
263 if (!object)
264 {
265 //OSG_NOTICE<<"Warning: Style::createIcon(.., "<<filename<<") could not find icon file."<<std::endl;
266 //return 0;
267 }
268
269 osg::ref_ptr<osg::Image> image = dynamic_cast<osg::Image*>(object.get());
270 if (image.valid())
271 {
272 osg::Vec3 center(extents.center());
273 float width = extents.xMax()-extents.xMin();
274 float height = extents.yMax()-extents.yMin();
275 float extentsAspectRatio = height/width;
276
277 float imageAspectRatio = static_cast<float>(image->t())/static_cast<float>(image->s());
278 if (imageAspectRatio>extentsAspectRatio) width *= (extentsAspectRatio/imageAspectRatio);
279 else height *= (imageAspectRatio/extentsAspectRatio);
280
281 osg::ref_ptr<osg::Geometry> geometry = osg::createTexturedQuadGeometry(osg::Vec3(center.x()-width*0.5f,center.y()-height*0.5f,center.z()),
282 osg::Vec3(width, 0.0f, 0.0f),
283 osg::Vec3(0.0f, height, 0.0f));
284
285 osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
286 colors->push_back(color);
287 geometry->setColorArray(colors.get(), osg::Array::BIND_OVERALL);
288
289 osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D(image.get());
290
291 osg::ref_ptr<osg::StateSet> stateset = geometry->getOrCreateStateSet();
292 stateset->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);
293
294 if (image->isImageTranslucent())
295 {
296 stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
297 }
298
299 return geometry.release();
300 }
301
302 osg::ref_ptr<osg::Node> node = dynamic_cast<osg::Node*>(object.get());
303 if (!node)
304 {
305 OSG_NOTICE<<"Warning: Style::createIcon(.., "<<filename<<") could not find icon file."<<std::endl;
306
307 osg::ref_ptr<osg::ShapeDrawable> ds = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0,0.0,0.0),1.0));
308
309 node = ds.get();
310
311 //return 0;
312 }
313
314 osg::ComputeBoundsVisitor cbv;
315 node->accept(cbv);
316 osg::BoundingBox bb = cbv.getBoundingBox();
317 osg::Vec3 bb_size(bb.xMax()-bb.xMin(), bb.zMax()-bb.zMin(), bb.zMax()-bb.zMin());
318
319 osg::Vec3 scale( (bb_size.x()>0) ? (extents.xMax()-extents.xMin())/bb_size.x() : 1.0f,
320 (bb_size.y()>0) ? (extents.yMax()-extents.yMin())/bb_size.y() : 1.0f,
321 (bb_size.z()>0) ? (extents.zMax()-extents.zMin())/bb_size.z() : 1.0f);
322
323 float minNonZeroScale = scale.x();
324 if (scale.y()!=0.0 && scale.y()<minNonZeroScale) minNonZeroScale = scale.y();
325 if (scale.z()!=0.0 && scale.z()<minNonZeroScale) minNonZeroScale = scale.z();
326
327 scale.set(minNonZeroScale, minNonZeroScale, minNonZeroScale);
328
329 // create Transform to rescale subgraph
330 osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform;
331 transform->setMatrix(osg::Matrix::translate(-bb.center()) *
332 osg::Matrix::scale(scale) *
333 osg::Matrix::translate(extents.center()));
334
335
336 transform->setDataVariance(osg::Transform::STATIC);
337 transform->addChild(node.get());
338
339 osg::ref_ptr<osg::Group> group = new osg::Group;
340 group->addChild(transform.get());
341
342 {
343 osgUtil::Optimizer::FlattenStaticTransformsVisitor fstv;
344 group->accept(fstv);
345 fstv.removeTransforms(group.get());
346 }
347
348 if (group->getNumChildren()==1)
349 {
350 node = group->getChild(0);
351
352 // remove references to avoid node from node being unreferenced afer the node ref_ptr<> is released().
353 group = 0;
354 transform = 0;
355
356 return node.release();
357 }
358 else
359 {
360 OSG_NOTICE<<"Warning: Style::createIcon(.., "<<filename<<"), error in creation of icon."<<std::endl;
361 return 0;
362 }
363 }
364
createPanel(const osg::BoundingBox & extents,const osg::Vec4 & colour)365 osg::Node* Style::createPanel(const osg::BoundingBox& extents, const osg::Vec4& colour)
366 {
367 // OSG_NOTICE<<"createPanel"<<std::endl;
368
369 osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
370 geometry->setName("Panel");
371
372 osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
373 geometry->setVertexArray(vertices.get());
374
375 vertices->push_back( osg::Vec3(extents.xMin(), extents.yMin(), extents.zMin()) );
376 vertices->push_back( osg::Vec3(extents.xMin(), extents.yMax(), extents.zMin()) );
377 vertices->push_back( osg::Vec3(extents.xMax(), extents.yMin(), extents.zMin()) );
378 vertices->push_back( osg::Vec3(extents.xMax(), extents.yMax(), extents.zMin()) );
379
380 osg::ref_ptr<osg::Vec4Array> colours = new osg::Vec4Array;
381 geometry->setColorArray(colours.get(), osg::Array::BIND_OVERALL);
382
383 colours->push_back( colour );
384
385 geometry->addPrimitiveSet( new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4) );
386
387 return geometry.release();
388 }
389
390
createDepthSetPanel(const osg::BoundingBox & extents)391 osg::Node* Style::createDepthSetPanel(const osg::BoundingBox& extents)
392 {
393 // OSG_NOTICE<<"createDepthSetPanel"<<std::endl;
394
395 osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
396 geometry->setName("DepthSetPanel");
397
398 osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
399 geometry->setVertexArray(vertices.get());
400
401 vertices->push_back( osg::Vec3(extents.xMin(), extents.yMin(), extents.zMin()) );
402 vertices->push_back( osg::Vec3(extents.xMin(), extents.yMax(), extents.zMin()) );
403 vertices->push_back( osg::Vec3(extents.xMax(), extents.yMin(), extents.zMin()) );
404 vertices->push_back( osg::Vec3(extents.xMax(), extents.yMax(), extents.zMin()) );
405
406 geometry->addPrimitiveSet( new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4) );
407
408 osg::ref_ptr<osg::StateSet> stateset = geometry->getOrCreateStateSet();
409 stateset->setAttributeAndModes( _enabledDepthWrite.get(), osg::StateAttribute::ON | osg::StateAttribute::PROTECTED );
410 stateset->setAttributeAndModes( _disableColorWriteMask.get(), osg::StateAttribute::ON | osg::StateAttribute::PROTECTED );
411 stateset->setRenderBinDetails(20, "TraversalOrderBin", osg::StateSet::OVERRIDE_PROTECTED_RENDERBIN_DETAILS);
412 stateset->setNestRenderBins(false);
413
414 return geometry.release();
415 }
416
417
setupDialogStateSet(osg::StateSet * stateset,int binNum)418 void Style::setupDialogStateSet(osg::StateSet* stateset, int binNum)
419 {
420 stateset->setRenderBinDetails(binNum, "TraversalOrderBin", osg::StateSet::OVERRIDE_PROTECTED_RENDERBIN_DETAILS);
421 stateset->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
422 stateset->setAttributeAndModes( _disabledDepthWrite.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
423 stateset->setNestRenderBins(false);
424 }
425
setupPopupStateSet(osg::StateSet *,int)426 void Style::setupPopupStateSet(osg::StateSet* /*stateset*/, int /*binNum*/)
427 {
428 }
429
setupClipStateSet(const osg::BoundingBox & extents,osg::StateSet * stateset)430 void Style::setupClipStateSet(const osg::BoundingBox& extents, osg::StateSet* stateset)
431 {
432 unsigned int clipTextureUnit = 1;
433
434 stateset->setAttributeAndModes( new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.0f), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
435
436 stateset->setTextureAttributeAndModes( clipTextureUnit, _clipTexture.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
437
438 osg::Matrixd matrix = osg::Matrixd::translate(osg::Vec3(-extents.xMin(), -extents.yMin(), -extents.zMin()))*
439 osg::Matrixd::scale(osg::Vec3(1.0f/(extents.xMax()-extents.xMin()), 1.0f/(extents.yMax()-extents.yMin()), 1.0f));
440
441 OSG_NOTICE<<"setupClipState("
442 <<extents.xMin()<<", "<<extents.yMin()<<", "<<extents.zMin()<<", "
443 <<extents.xMax()<<", "<<extents.yMax()<<", "<<extents.zMax()<<")"<<std::endl;
444
445
446 osg::ref_ptr<osg::TexGen> texgen = new osg::TexGen;
447 texgen->setPlanesFromMatrix(matrix);
448 texgen->setMode(osg::TexGen::OBJECT_LINEAR);
449 stateset->setTextureAttributeAndModes( clipTextureUnit, texgen.get(), osg::StateAttribute::ON);
450 }
451