root/OpenSceneGraph/trunk/src/osgWidget/Widget.cpp @ 13376

Revision 13376, 13.7 kB (checked in by robert, 9 hours ago)

Added NodeVisitor::INTERSECTION_VISITOR VisitorType?

  • Property svn:eol-style set to native
Line 
1// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
2// $Id: Widget.cpp 64 2008-06-30 21:32:00Z cubicool $
3
4#include <osg/io_utils>
5#include <osg/Math>
6#include <osg/TextureRectangle>
7#include <osgDB/ReadFile>
8#include <osgDB/FileUtils>
9#include <osgWidget/WindowManager>
10
11// Don't use these macros! :) They're simply for internal optimization!
12#define MACRO_WIDGET_X(v) (*v)[LL].x()
13#define MACRO_WIDGET_Y(v) (*v)[LL].y()
14#define MACRO_WIDGET_W(v) (*v)[LR].x() - (*v)[LL].x()
15#define MACRO_WIDGET_H(v) (*v)[UL].y() - (*v)[LL].y()
16
17namespace osgWidget {
18
19osg::ref_ptr<PointArray> Widget::_norms;
20
21Widget::Widget(const std::string& name, point_type w, point_type h):
22_parent    (0),
23_index     (0),
24_layer     (LAYER_LOW),
25_padLeft   (0.0f),
26_padRight  (0.0f),
27_padTop    (0.0f),
28_padBottom (0.0f),
29_valign    (VA_CENTER),
30_halign    (HA_CENTER),
31_coordMode (CM_ABSOLUTE),
32_canFill   (false),
33_canClone  (true),
34_isManaged (false),
35_isStyled  (false),
36_minWidth  (0.0f),
37_minHeight (0.0f) {
38    _name = name.size() ? name : generateRandomName("Widget");
39
40    if(!_norms.valid()) {
41        _norms = new PointArray(1);
42
43        (*_norms)[0].set(0.0f, 0.0f, 1.0f);
44        (*_norms)[0].normalize();
45    }
46
47    TexCoordArray* texs = new TexCoordArray(4);
48
49    // Fill our texture coordinates with null stuff for now, since we aren't using them
50    // until an Image is set at some later point.
51    std::fill(texs->begin(), texs->end(), osg::Vec2(0.0f, 0.0f));
52
53    setUseDisplayList(false);
54    setDataVariance(osg::Object::DYNAMIC);
55    setVertexArray(new PointArray(4));
56    setColorArray(new ColorArray(4));
57    setNormalArray(_norms.get());
58    setTexCoordArray(0, texs);
59    setNormalBinding(osg::Geometry::BIND_OVERALL);
60    setColorBinding(osg::Geometry::BIND_PER_VERTEX);
61    addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
62
63    setDimensions(0.0f, 0.0f, w, h);
64    setColor(1.0f, 1.0f, 1.0f, 1.0f);
65}
66
67Widget::Widget(const Widget& widget, const osg::CopyOp& co):
68osg::Geometry  (widget, co),
69EventInterface (widget),
70StyleInterface (widget),
71_parent        (0),
72_index         (0),
73_layer         (widget._layer),
74_padLeft       (widget._padLeft),
75_padRight      (widget._padRight),
76_padTop        (widget._padTop),
77_padBottom     (widget._padBottom),
78_valign        (widget._valign),
79_halign        (widget._halign),
80_coordMode     (widget._coordMode),
81_canFill       (widget._canFill),
82_canClone      (widget._canClone),
83_isManaged     (false),
84_isStyled      (widget._isStyled),
85_minWidth      (widget._minWidth),
86_minHeight     (widget._minHeight) {
87}
88
89// This takes an integer value and translates it into a value that will be added to
90// the parent window's Z value.
91point_type Widget::_calculateZ(unsigned int layer) const {
92    point_type zRange = 0.0f;
93
94    if(_parent) zRange = _parent->getZRange();
95
96    return (static_cast<point_type>(layer) / static_cast<point_type>(LAYER_TOP + 1)) * zRange;
97
98}
99
100WindowManager* Widget::_getWindowManager() const {
101    if(!_parent) return 0;
102
103    return _parent->getWindowManager();
104}
105
106osg::Image* Widget::_getImage() const {
107    const osg::Texture* texture = _texture();
108
109    if(texture) return const_cast<osg::Image*>(texture->getImage(0));
110
111    return 0;
112}
113
114void Widget::setDimensions(point_type x, point_type y, point_type w, point_type h, point_type z) {
115    if(w != -1.0f && w < _minWidth) {
116        warn()
117            << "Widget [" << _name
118            << "] was asked to set it's width to " << w
119            << ", but the minimum width is " << _minWidth
120            << "." << std::endl
121        ;
122
123        w = _minWidth;
124    }
125
126    if(h != -1.0f && h < _minHeight) {
127        warn()
128            << "Widget [" << _name
129            << "] was asked to set it's height to " << h
130            << ", but the minimum height is " << _minHeight
131            << "." << std::endl
132        ;
133
134        h = _minHeight;
135    }
136
137    PointArray* verts = _verts();
138
139    if(_coordMode == CM_ABSOLUTE) {
140        // If any of our values are 0, replace them with the current value.
141        // We could just call getWidth(), etc., but all those dynamic_casts could eventually
142        // get expensive, so we just use the already-created verts() array directly.
143        if(x < 0.0f) x = MACRO_WIDGET_X(verts);
144        if(y < 0.0f) y = MACRO_WIDGET_Y(verts);
145        if(w < 0.0f) w = MACRO_WIDGET_W(verts);
146        if(h < 0.0f) h = MACRO_WIDGET_H(verts);
147    }
148
149    else {
150        if(x < 0.0f) x = _relCoords[0];
151        if(y < 0.0f) y = _relCoords[1];
152        if(w < 0.0f) w = _relCoords[2];
153        if(h < 0.0f) h = _relCoords[3];
154    }
155
156    if(z < 0.0f) z = _calculateZ(_layer);
157
158    // Now, we need to determine if the dimensions are actually percentage of the parent's
159    // size, rather than an absolute values. The Widget must be parented for this to be
160    // valid, however.
161    if(_coordMode == CM_RELATIVE) {
162        XYCoord size;
163
164        if(_parent) size = _parent->getSize();
165
166        if(x >= 0.0f && x <= 1.0f) {
167            _relCoords[0] = x;
168
169            x = size.x() * x;
170        }
171
172        if(y >= 0.0f && y <= 1.0f) {
173            _relCoords[1] = y;
174
175            y = size.y() * y;
176        }
177
178        if(w >= 0.0f && w <= 1.0f) {
179            _relCoords[2] = w;
180
181            w = size.x() * w;
182        }
183
184        if(h >= 0.0f && h <= 1.0f) {
185            _relCoords[3] = h;
186
187            h = size.y() * h;
188        }
189    }
190
191    const WindowManager* wm = _getWindowManager();
192
193    if(wm && wm->isUsingRenderBins()) {
194        getOrCreateStateSet()->setRenderBinDetails(static_cast<int>(z), "RenderBin");
195
196        z = 0.0f;
197    }
198
199    (*verts)[LL].set(x,     y,     z);
200    (*verts)[LR].set(x + w, y,     z);
201    (*verts)[UR].set(x + w, y + h, z);
202    (*verts)[UL].set(x,     y + h, z);
203}
204
205void Widget::setColor(color_type r, color_type g, color_type b, color_type a, Corner p) {
206    ColorArray* cols = _cols();
207
208    if(p == ALL_CORNERS) {
209        (*cols)[LL].set(r, g, b, a);
210        (*cols)[LR].set(r, g, b, a);
211        (*cols)[UR].set(r, g, b, a);
212        (*cols)[UL].set(r, g, b, a);
213    }
214
215    else (*cols)[p].set(r, g, b, a);
216}
217
218void Widget::addColor(color_type r, color_type g, color_type b, color_type a, Corner p) {
219    ColorArray* cols = _cols();
220
221    if(p == ALL_CORNERS) {
222        (*cols)[LL] += Color(r, g, b, a);
223        (*cols)[LR] += Color(r, g, b, a);
224        (*cols)[UR] += Color(r, g, b, a);
225        (*cols)[UL] += Color(r, g, b, a);
226    }
227
228    else (*cols)[p] += Color(r, g, b, a);
229}
230
231void Widget::setTexCoord(texcoord_type tx, texcoord_type ty, Corner p) {
232    TexCoordArray* texs = _texs();
233
234    if(p == ALL_CORNERS) {
235        (*texs)[LL].set(tx, ty);
236        (*texs)[LR].set(tx, ty);
237        (*texs)[UR].set(tx, ty);
238        (*texs)[UL].set(tx, ty);
239    }
240
241    else (*texs)[p].set(tx, ty);
242}
243
244// TODO: We chop off any offset here if you use TOP; we need to do the same
245// for BG, etc.
246void Widget::setLayer(Layer layer, unsigned int offset) {
247    if(layer == LAYER_TOP) offset = 0;
248
249    _layer = layer + offset;
250}
251
252void Widget::setTexCoordRegion(point_type x, point_type y, point_type w, point_type h) {
253    osg::Image* image = _image();
254
255    if(!image) return;
256
257    point_type tw = image->s();
258    point_type th = image->t();
259
260    TexCoordArray* texs = _texs();
261
262    // Set the LOWER_LEFT point.
263    XYCoord t(x / tw, y / tw);
264
265    (*texs)[LL] = t;
266
267    // Set the LOWER_RIGHT point.
268    t += XYCoord(w / tw, 0.0f);
269
270    (*texs)[LR] = t;
271
272    // Set the UPPER_RIGHT point.
273    t += XYCoord(0.0f, h / th);
274
275    (*texs)[UR] = t;
276
277    // Set the UPPER_LEFT point.
278    t += XYCoord(-(w / tw), 0.0f);
279
280    (*texs)[UL] = t;
281}
282
283void Widget::setTexCoordWrapHorizontal() {
284    osg::Image*   image   = _image();
285    osg::Texture* texture = _texture();
286
287    if(!image || !texture || image->s() == 0.0f) return;
288
289    texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
290
291    setTexCoord(getWidth() / image->s(), 0.0f, LOWER_RIGHT);
292    setTexCoord(getWidth() / image->s(), 1.0f, UPPER_RIGHT);
293}
294
295void Widget::setTexCoordWrapVertical() {
296    osg::Image*   image   = _image();
297    osg::Texture* texture = _texture();
298
299    if(!image || !texture || image->t() == 0.0f) return;
300
301    texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
302
303    setTexCoord(0.0f, getHeight() / image->t(), UPPER_LEFT);
304    setTexCoord(1.0f, getHeight() / image->t(), UPPER_RIGHT);
305}
306
307XYCoord Widget::localXY(double _x, double _y) const {
308    if(!_parent) return XYCoord(_x, _y);
309
310    return _parent->localXY(_x, _y) - getOrigin();
311}
312
313bool Widget::setImage(osg::Image* image, bool setTexCoords, bool useTextRect) {
314    if(!image) {
315        warn() << "Widget [" << _name << "] cannot use a NULL image." << std::endl;
316
317        return false;
318    }
319
320    osg::Texture* texture = 0;
321
322    if(useTextRect) texture = new osg::TextureRectangle();
323
324    else texture = new osg::Texture2D();
325
326    if(!texture) return false;
327
328    texture->setImage(0, image);
329
330    return setTexture(texture, setTexCoords, useTextRect);
331}
332
333bool Widget::setImage(const std::string& filePath, bool setTexCoords, bool useTextRect) {
334    if(!osgDB::findDataFile(filePath).size()) {
335        warn()
336            << "Widget [" << _name
337            << "] cannot find file " << filePath
338            << " to set as it's Image." << std::endl
339        ;
340
341        return false;
342    }
343
344    return setImage(osgDB::readImageFile(filePath), setTexCoords, useTextRect);
345}
346
347bool Widget::setTexture(osg::Texture* texture, bool setTexCoords, bool useTextRect) {
348    if(!texture) return false;
349
350    getOrCreateStateSet()->setTextureAttributeAndModes(
351        0,
352        texture,
353        osg::StateAttribute::ON
354    );
355
356    if(setTexCoords) {
357        if(useTextRect) {
358             osg::Image* image = texture->getImage(0);
359
360            setTexCoord(0.0f, 0.0f, LOWER_LEFT);
361            setTexCoord(image->s(), 0.0f, LOWER_RIGHT);
362            setTexCoord(image->s(), image->t(), UPPER_RIGHT);
363            setTexCoord(0.0f, image->t(), UPPER_LEFT);
364        }
365
366        else {
367            setTexCoord(0.0f, 0.0f, LOWER_LEFT);
368            setTexCoord(1.0f, 0.0f, LOWER_RIGHT);
369            setTexCoord(1.0f, 1.0f, UPPER_RIGHT);
370            setTexCoord(0.0f, 1.0f, UPPER_LEFT);
371        }
372    }
373
374    return true;
375}
376
377void Widget::setPadding(point_type pad) {
378    _padLeft = _padRight = _padTop = _padBottom = pad;
379}
380
381void Widget::addX(point_type x) {
382    if(_coordMode == CM_ABSOLUTE) setDimensions(MACRO_WIDGET_X(_verts()) + x);
383
384    else setDimensions(_relCoords[0] + x);
385}
386
387void Widget::addY(point_type y) {
388    if(_coordMode == CM_ABSOLUTE) setDimensions(-1.0f, MACRO_WIDGET_Y(_verts()) + y);
389
390    else setDimensions(-1.0f, _relCoords[1] + y);
391}
392
393void Widget::addWidth(point_type w) {
394    if(_coordMode == CM_ABSOLUTE) setDimensions(-1.0f, -1.0f, MACRO_WIDGET_W(_verts()) + w);
395
396    else setDimensions(-1.0f, -1.0f, _relCoords[2] + w);
397}
398
399void Widget::addHeight(point_type h) {
400    if(_coordMode == CM_ABSOLUTE) setDimensions(
401        -1.0f,
402        -1.0f,
403        -1.0f,
404        MACRO_WIDGET_H(_verts()) + h
405    );
406
407    else setDimensions(-1.0f, -1.0f, -1.0f, _relCoords[3] + h);
408}
409
410void Widget::addOrigin(point_type x, point_type y) {
411    if(_coordMode == CM_ABSOLUTE) {
412        PointArray* verts = _verts();
413
414        setDimensions(
415            MACRO_WIDGET_X(verts) + x,
416            MACRO_WIDGET_Y(verts) + y
417        );
418    }
419
420    else setDimensions(_relCoords[0] + x, _relCoords[1] + y);
421}
422
423void Widget::addSize(point_type w, point_type h) {
424    if(_coordMode == CM_ABSOLUTE) {
425        PointArray* verts = _verts();
426
427        setDimensions(
428            -1.0f,
429            -1.0f,
430            MACRO_WIDGET_W(verts) + w,
431            MACRO_WIDGET_H(verts) + h
432        );
433    }
434
435    else setDimensions(-1.0f, -1.0f, _relCoords[2] + w, _relCoords[3] + h);
436}
437
438point_type Widget::getWidth() const {
439    const PointArray* verts = _verts();
440
441    return MACRO_WIDGET_W(verts);
442}
443
444point_type Widget::getHeight() const {
445    const PointArray* verts = _verts();
446
447    return MACRO_WIDGET_H(verts);
448}
449
450point_type Widget::getX() const {
451    return MACRO_WIDGET_X(_verts());
452}
453
454point_type Widget::getY() const {
455    return MACRO_WIDGET_Y(_verts());
456}
457
458point_type Widget::getZ() const {
459    return (*_verts())[LL].z();
460}
461
462point_type Widget::getPadHorizontal() const {
463    return _padLeft + _padRight;
464}
465
466point_type Widget::getPadVertical() const {
467    return _padTop + _padBottom;
468}
469
470const Point& Widget::getPoint(Corner p) const {
471    Corner point = p;
472
473    if(p == ALL_CORNERS) point = UPPER_LEFT;
474
475    return (*_verts())[point];
476}
477
478const Color& Widget::getColor(Corner p) const {
479    Corner point = p;
480
481    if(p == ALL_CORNERS) point = UPPER_LEFT;
482
483    return (*_cols())[point];
484}
485
486const TexCoord& Widget::getTexCoord(Corner p) const {
487    Corner point = p;
488
489    if(p == ALL_CORNERS) point = UPPER_LEFT;
490
491    return (*_texs())[point];
492}
493
494Color Widget::getImageColorAtXY(point_type x, point_type y) const {
495    const osg::Image* image = _image();
496
497    if(!image) return Color();
498
499    const TexCoordArray* texs = _texs();
500
501    /*
502    How do we do this? First we need to make sure our right side is larger
503    than our left side and that the top side is larger the bottom; otherwise,
504    they're using strange tex coords.
505
506    Then, we find the percent area being used in both dimensions. We multiply
507    the XY values by those ratios and then add those values to the "offsets."
508    */
509
510    point_type width  = fabs((*texs)[LR].x() - (*texs)[LL].x());
511    point_type height = fabs((*texs)[LR].y() - (*texs)[UR].y());
512
513    point_type X = ((x / getWidth()) * width) + (*texs)[LL].x();
514    point_type Y = ((y / getHeight()) * height) + (*texs)[LR].y();
515   
516    if (X<0.0 || X>1.0 || Y<0.0 || Y>1.0)
517    {
518        OSG_INFO<<"Widget::getImageColorAtXY("<<x<<", "<<y<<") Texture coordinate out of range, X="<<X<<", Y="<<Y<<std::endl;
519        return Color();
520    }
521
522    return image->getColor(TexCoord(X, Y));
523}
524
525bool Widget::isPaddingUniform() const {
526    return
527        _padLeft == _padRight &&
528        _padLeft == _padTop &&
529        _padLeft == _padBottom
530    ;
531}
532
533}
Note: See TracBrowser for help on using the browser.