root/OpenSceneGraph/trunk/src/osgWidget/Frame.cpp @ 13041

Revision 13041, 18.0 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
Line 
1// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
2
3#include <osg/io_utils>
4#include <osgDB/ReadFile>
5#include <osgWidget/WindowManager>
6#include <osgWidget/Frame>
7#include <cassert>
8
9namespace osgWidget {
10
11std::string Frame::cornerTypeToString(CornerType c)
12{
13    if(c == CORNER_LOWER_LEFT) return "CornerLowerLeft";
14
15    else if(c == CORNER_LOWER_RIGHT) return "CornerLowerRight";
16
17    else if(c == CORNER_UPPER_RIGHT) return "CornerUpperRight";
18
19    else return "CornerUpperLeft";
20}
21
22std::string Frame::borderTypeToString(BorderType b)
23{
24    if(b == BORDER_LEFT) return "BorderLeft";
25
26    else if(b == BORDER_RIGHT) return "BorderRight";
27
28    else if(b == BORDER_TOP) return "BorderTop";
29
30    else return "BorderBottom";
31}
32
33Frame::Corner::Corner(CornerType corner, point_type width, point_type height):
34Widget  (cornerTypeToString(corner), width, height),
35_corner (corner)
36{
37}
38
39Frame::Corner::Corner(const Corner& corner, const osg::CopyOp& co):
40Widget  (corner, co),
41_corner (corner._corner)
42{
43}
44
45void Frame::Corner::parented(Window* window) {
46    Frame* parent = dynamic_cast<Frame*>(getParent());
47
48    if(!parent) return;
49
50    if(parent->canResize()) setEventMask(EVENT_MASK_MOUSE_DRAG);
51}
52
53bool Frame::Corner::mouseDrag(double x, double y, const WindowManager* wm)
54{
55    Frame* parent = dynamic_cast<Frame*>(getParent());
56
57    if(!parent || !parent->canResize()) return false;
58
59    if(_corner == CORNER_UPPER_LEFT) {
60        if(parent->resizeAdd(-x, y)) parent->addX(x);
61    }
62
63    else if(_corner == CORNER_UPPER_RIGHT) parent->resizeAdd(x, y);
64
65    else if(_corner == CORNER_LOWER_RIGHT) {
66        if(parent->resizeAdd(x, -y)) parent->addY(y);
67    }
68
69    else {
70        if(parent->resizeAdd(-x, -y)) parent->addOrigin(x, y);
71    }
72
73    parent->update();
74
75    return true;
76}
77
78Frame::Border::Border(BorderType border, point_type width, point_type height):
79Widget  (borderTypeToString(border), width, height),
80_border (border)
81{
82    setCanFill(true);
83}
84
85Frame::Border::Border(const Border& border, const osg::CopyOp& co):
86Widget  (border, co),
87_border (border._border)
88{
89}
90
91void Frame::Border::parented(Window* window) {
92    Frame* parent = dynamic_cast<Frame*>(getParent());
93
94    if(!parent) return;
95
96    if(parent->canResize()) setEventMask(EVENT_MASK_MOUSE_DRAG);
97}
98
99void Frame::Border::positioned()
100{
101    osg::Image* image = _image();
102
103    if(!image) return;
104
105    Frame* parent = dynamic_cast<Frame*>(getParent());
106
107    if(!parent || !parent->canTexture()) return;
108
109    point_type w = image->s() / 8.0f;
110    point_type h = getHeight();
111
112    if(_border == BORDER_LEFT) setTexCoordRegion(w * 3, 0.0f, w, h);
113
114    else if(_border == BORDER_RIGHT) setTexCoordRegion(w * 4, 0.0f, w, h);
115
116    else if(_border == BORDER_TOP) {
117        // TODO: Temporary; fix this.
118        point_type tx1 = (w * 2) / image->s();
119        point_type tx2 = w / image->s();
120        point_type tx3 = getWidth() / w;
121
122        setTexCoord(tx1, tx3,  LL);
123        setTexCoord(tx1, 0.0f, LR);
124        setTexCoord(tx2, 0.0f, UR);
125        setTexCoord(tx2, tx3,  UL);
126    }
127
128    else {
129        point_type tx1 = (w * 7) / image->s();
130        point_type tx2 = (w * 6) / image->s();
131        point_type tx3 = getWidth() / w;
132
133        setTexCoord(tx1, tx3,  LL);
134        setTexCoord(tx1, 0.0f, LR);
135        setTexCoord(tx2, 0.0f, UR);
136        setTexCoord(tx2, tx3,  UL);
137    }
138}
139
140bool Frame::Border::mouseDrag(double x, double y, const WindowManager* wm)
141{
142    Frame* parent = dynamic_cast<Frame*>(getParent());
143
144    if(!parent) return false;
145
146    if(_border == BORDER_TOP && parent->canMove()) parent->addOrigin(x, y);
147
148    else {
149        if(!parent->canResize()) return false;
150
151        if(_border == BORDER_LEFT) {
152            if(parent->resizeAdd(-x, 0.0f)) parent->addX(x);
153        }
154
155        else if(_border == BORDER_RIGHT) parent->resizeAdd(x, 0.0f);
156
157        else {
158            if(parent->resizeAdd(0.0f, -y)) parent->addY(y);
159        }
160    }
161
162    parent->update();
163
164    return true;
165}
166
167Frame::Frame(const std::string& name, unsigned int flags):
168    Table  (name, 3, 3),
169    _flags (flags)
170{
171}
172
173Frame::Frame(const Frame& frame, const osg::CopyOp& co):
174    Table(frame, co),
175    _flags(frame._flags)
176{
177}
178
179Widget* Frame::_getCorner(CornerType c) const
180{
181    return const_cast<Widget*>(getByName(cornerTypeToString(c)));
182}
183
184Widget* Frame::_getBorder(BorderType b) const
185{
186    return const_cast<Widget*>(getByName(borderTypeToString(b)));
187}
188
189bool Frame::setWindow(Window* window)
190{
191    if(!window) return false;
192
193    EmbeddedWindow* ew = getEmbeddedWindow();
194
195    // If it's the first time setting the Window...
196    // if(!ew || !ew->getWindow()) return addWidget(window->embed(), 1, 1);
197    if(!ew) return addWidget(window->embed(), 1, 1);
198
199    else return ew->setWindow(window);
200}
201
202Frame* Frame::createSimpleFrame(
203    const std::string& name,
204    point_type         cw,
205    point_type         ch,
206    point_type         w,
207    point_type         h,
208    unsigned int       flags,
209    Frame*             exFrame
210) {
211    Frame* frame = 0;
212
213    // Use an "existing frame" if we have it (for example, if you've in inherited from
214    // Frame and want to use this stuff.
215    if(!exFrame) frame = new Frame(name, flags);
216
217    else frame = exFrame;
218
219    frame->addWidget(new Corner(CORNER_LOWER_LEFT,  cw, ch), 0, 0);
220    frame->addWidget(new Border(BORDER_BOTTOM,      w,  ch), 0, 1);
221    frame->addWidget(new Corner(CORNER_LOWER_RIGHT, cw, ch), 0, 2);
222    frame->addWidget(new Border(BORDER_LEFT,        cw, h),  1, 0);
223    frame->addWidget(new Border(BORDER_RIGHT,       cw, h),  1, 2);
224    frame->addWidget(new Corner(CORNER_UPPER_LEFT,  cw, ch), 2, 0);
225    frame->addWidget(new Border(BORDER_TOP,         w,  ch), 2, 1);
226    frame->addWidget(new Corner(CORNER_UPPER_RIGHT, cw, ch), 2, 2);
227
228    EmbeddedWindow* ew = new EmbeddedWindow(name, w, h);
229
230    ew->setCanFill(true);
231
232    frame->addWidget(ew, 1, 1);
233
234    return frame;
235}
236
237/*
238Frame* Frame::createSimpleFrameWithSingleTexture(
239    const std::string& name,
240    const std::string& texture,
241    point_type         tw,
242    point_type         th,
243    point_type         cw,
244    point_type         ch,
245    point_type         w,
246    point_type         h,
247    Frame*             exFrame
248) {
249    Frame* frame = 0;
250
251    // The same as above...
252    if(!exFrame) frame = createSimpleFrame(name, cw, ch, w, h);
253
254    else frame = createSimpleFrame(name, cw, ch, w, h, exFrame);
255
256    for(unsigned int i = 0; i < 9; i++) frame->getObjects()[i]->setImage(texture);
257
258    frame->getByRowCol(0, 0)->setTexCoordRegion(0.0f, th - ch, cw, ch);
259    frame->getByRowCol(0, 1)->setTexCoordRegion(cw, th - ch, tw - (cw * 2.0f), ch);
260    frame->getByRowCol(0, 2)->setTexCoordRegion(tw - cw, th - ch, cw, ch);
261    frame->getByRowCol(1, 0)->setTexCoordRegion(0.0f, ch, cw, th - (ch * 2.0f));
262    frame->getByRowCol(1, 2)->setTexCoordRegion(tw - cw, ch, cw, th - (ch * 2.0f));
263    frame->getByRowCol(2, 0)->setTexCoordRegion(0.0f, 0.0f, cw, ch);
264    frame->getByRowCol(2, 1)->setTexCoordRegion(cw, 0.0f, tw - (cw * 2.0f), ch);
265    frame->getByRowCol(2, 2)->setTexCoordRegion(tw - cw, 0.0f, cw, ch);
266
267    frame->getEmbeddedWindow()->setTexCoordRegion(cw, ch, tw - (cw * 2.0f), th - (ch * 2.0f));
268
269    return frame;
270}
271*/
272
273// Inspired by: http://www.wowwiki.com/EdgeFiles
274Frame* Frame::createSimpleFrameWithSingleTexture(
275    const std::string& name,
276    osg::Image*        image,
277    point_type         width,
278    point_type         height,
279    unsigned int       flags,
280    Frame*             exFrame
281) {
282    Frame* frame = 0;
283
284    double w = width;
285    double h = height;
286
287    if (image)
288    {
289        w = image->s() / 8.0f;
290        h = image->t();
291    }
292
293    // The same as above...
294    if(!exFrame) frame = createSimpleFrame(name, w, h, width, height, flags);
295
296    else frame = createSimpleFrame(name, w, h, width, height, 0, exFrame);
297
298    if (image)
299    {
300
301        for(unsigned int i = 0; i < 9; i++) frame->getObjects()[i]->setImage(image);
302
303        XYCoord twh(w, h);
304
305        frame->getCorner(CORNER_UPPER_LEFT )->setTexCoordRegion(0.0f,  0.0f, twh);
306        frame->getBorder(BORDER_TOP        )->setTexCoordRegion(w,     0.0f, twh);
307        frame->getCorner(CORNER_UPPER_RIGHT)->setTexCoordRegion(w * 2, 0.0f, twh);
308        frame->getBorder(BORDER_LEFT       )->setTexCoordRegion(w * 3, 0.0f, twh);
309        frame->getBorder(BORDER_RIGHT      )->setTexCoordRegion(w * 4, 0.0f, twh);
310        frame->getCorner(CORNER_LOWER_LEFT )->setTexCoordRegion(w * 5, 0.0f, twh);
311        frame->getBorder(BORDER_BOTTOM     )->setTexCoordRegion(w * 6, 0.0f, twh);
312        frame->getCorner(CORNER_LOWER_RIGHT)->setTexCoordRegion(w * 7, 0.0f, twh);
313
314        // We set all of these to wrap vertically, but the REAL texture coordinates will
315        // be generated properly in the positioned() method.
316        frame->getByRowCol(0, 1)->setTexCoordWrapVertical();
317        frame->getByRowCol(1, 0)->setTexCoordWrapVertical();
318        frame->getByRowCol(1, 2)->setTexCoordWrapVertical();
319        frame->getByRowCol(2, 1)->setTexCoordWrapVertical();
320
321        // frame->getEmbeddedWindow()->setTexCoordRegion(cw, ch, tw - (cw * 2.0f), th - (ch * 2.0f));
322    }
323    else
324    {
325        OSG_WARN << "createSimpleFrameWithSingleTexture with a null image, the frame " << name << " will be use texture" << std::endl;
326    }
327
328    return frame;
329}
330
331bool Frame::resizeFrame(point_type w, point_type h) {
332    Border* left   = getBorder(BORDER_LEFT);
333    Border* right  = getBorder(BORDER_RIGHT);
334    Border* top    = getBorder(BORDER_TOP);
335    Border* bottom = getBorder(BORDER_BOTTOM);
336
337    if(!left || !right || !top || !bottom) return false;
338
339    return resize(
340        left->getWidth() + right->getWidth() + w,
341        top->getHeight() + bottom->getHeight() + h
342    );
343}
344
345
346osg::Image* createNatifEdgeImageFromTheme(osg::Image* theme);
347
348Frame* Frame::createSimpleFrameFromTheme(
349    const std::string& name,
350    osg::Image*        image,
351    point_type         width,
352    point_type         height,
353    unsigned int       flags,
354    Frame*             exFrame
355) {
356
357    osg::ref_ptr<osg::Image> natifImage = createNatifEdgeImageFromTheme(image);
358    Frame* frame;
359
360    frame = createSimpleFrameWithSingleTexture(name, natifImage.get(), width, height, flags, exFrame);
361
362    if (frame && image && natifImage.valid())
363    {
364        const unsigned int bpps = image->getPixelSizeInBits() / 8;
365        const unsigned int one_third_s = image->s()/3;
366        unsigned char* srcdata = (unsigned char*)image->data();
367        osg::Vec4 color(0,0,0,1);
368        for (unsigned int d = 0; d < bpps; d++)
369        {
370            color[d] = srcdata[one_third_s * image->s() * bpps + (one_third_s) * bpps + d] * 1.0/255.0;
371        }
372        frame->getEmbeddedWindow()->setColor(color);
373    }
374    return frame;
375}
376
377
378
379
380
381
382
383// (c) 2006-2008   Jean-Sébastien Guay
384// adapted by Cedric Pinson
385
386/** Implementation of copyImage. */
387template<typename T>
388void copyDataImpl(const osg::Image* source,
389                  const unsigned int x1, const unsigned int y1,
390                  const unsigned int x2, const unsigned int y2,
391                  osg::Image* destination,
392                  const unsigned int xd = 0, const unsigned int yd = 0)
393{
394    if ((unsigned int)destination->s() >= xd + (x2 - x1) &&
395        (unsigned int)destination->t() >= yd + (y2 - y1))
396    {
397        const unsigned int bpps =      source->getPixelSizeInBits() / (8 * sizeof(T));
398
399        T* srcdata = (T*)source->data();
400        T* dstdata = (T*)destination->data();
401
402        for (unsigned int y = 0; y < y2 - y1; ++y)
403        {
404            for (unsigned int x = 0; x < x2 - x1; ++x)
405            {
406                for (unsigned int d = 0; d < bpps; d++)
407                {
408                    T v = srcdata[(y + y1) * source->s() * bpps + (x + x1) * bpps + d];
409                    dstdata[(yd + y) * destination->s() * bpps + (xd + x) * bpps + d] = v;
410                }
411            }
412        }
413    }
414    else
415        assert(false && "copyDataImpl: Incorrect image dimensions.");
416}
417
418/** Copies a rectangle of corners (x1, y1), (x2, y2) from an image into
419    another image starting at position (xd, yd). No scaling is done, the
420    pixels are just copied, so the destination image must be at least
421    (xd + (x2 - x1)) by (yd + (y2 - y1)) pixels. */
422void copyData(const osg::Image* source,
423              const unsigned int x1, const unsigned int y1,
424              const unsigned int x2, const unsigned int y2,
425              osg::Image* destination,
426              const unsigned int xd, const unsigned int yd)
427{
428    if (source->getDataType() == destination->getDataType())
429    {
430        if (source->getDataType() == GL_UNSIGNED_BYTE)
431        {
432            copyDataImpl<unsigned char>(source, x1, y1, x2, y2,
433                                        destination, xd, yd);
434        }
435        else
436        {
437            assert(false && "copyData not implemented for this data type");
438        }
439    }
440    else
441    {
442        assert(false && "source and destination images must be of the same type.");
443        return;
444    }
445}
446
447
448/** Implementation of rotateImage. */
449template<typename T>
450osg::Image* rotateImageImpl(osg::Image* image)
451{
452    if (image->s() == image->t())
453    {
454        const unsigned int s = image->s();
455        const unsigned int bpp = image->getPixelSizeInBits() / (8 * sizeof(T));
456
457        osg::ref_ptr<osg::Image> destination  = new osg::Image;
458        destination->allocateImage(s, s, 1,
459                                   image->getPixelFormat(), image->getDataType(),
460                                   image->getPacking());
461        destination->setInternalTextureFormat(image->getInternalTextureFormat());
462
463        T* srcdata = (T*)image->data();
464        T* dstdata = (T*)destination->data();
465
466        for (unsigned int y = 0; y < s; ++y)
467        {
468            for (unsigned int x = 0; x < s; ++x)
469            {
470                for (unsigned int p = 0; p < bpp; p++)
471                    dstdata[y * s * bpp + x * bpp + p] = srcdata[x * s * bpp + y * bpp + p];
472            }
473        }
474
475        return destination.release();
476    }
477    else
478    {
479        assert(false && "rotateImageImpl: Image must be square.");
480        return 0;
481    }
482}
483
484/** Rotates an osg::Image by 90 degrees. Returns a new osg::Image, be sure to
485    store it in a ref_ptr so it will be freed correctly. */
486osg::Image* rotateImage(osg::Image* image)
487{
488    if (image->getDataType() == GL_UNSIGNED_BYTE)
489    {
490        return rotateImageImpl<unsigned char>(image);
491    }
492    else
493    {
494        assert(false && "rotateImage not implemented for this data type");
495        return 0;
496    }
497}
498
499
500
501// SOURCE
502//          +---+---+---+
503//          | 1 | 2 | 3 |
504//          +---+---+---+
505//          | 4 |   | 5 |
506//          +---+---+---+
507//          | 6 | 7 | 8 |
508//          +---+---+---+
509
510
511// FINAL
512//         +---+---+---+---+---+---+---+---+
513//         | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
514//         +---+---+---+---+---+---+---+---+
515
516//         1. Upper-Left corner.
517//         2. Top border (rotated 90 degrees CCW).
518//         3. Upper-Right corner.
519//         4. Left border.
520//         5. Right border.
521//         6. Bottom-Left corner.
522//         7. Bottom border (rotated 90 degrees CCW).
523//         8. Bottom-Right corner.
524
525osg::Image* createNatifEdgeImageFromTheme(osg::Image* theme)
526{
527    if (!theme) {
528        OSG_WARN << "can't create a natif edge image from null image theme as argument" << std::endl;
529        return 0;
530    }
531    osg::ref_ptr<osg::Image> final = new osg::Image;
532    const int s = theme->s();
533    const int t = theme->t();
534    const GLenum pixelFormat   = theme->getPixelFormat();
535    const GLenum dataType      = theme->getDataType();
536    const GLint internalFormat = theme->getInternalTextureFormat();
537    unsigned int packing       = theme->getPacking();
538
539    if (s != t)
540    {
541        OSG_WARN << "width and height are different, bad format theme image " << theme->getFileName() << std::endl;
542        return 0;
543    }
544
545    // check size
546    int ceilvalue = static_cast<int>(ceil(s * 1.0 / 3));
547    int intvalue = s/3;
548    if (intvalue != ceilvalue)
549    {
550        OSG_WARN << "the size of theme file " << theme->getFileName() << " can not be divided by 3, check the documentation about theme format" << std::endl;
551        return 0;
552    }
553
554    const unsigned int one_third_s = s/3;
555    const unsigned int one_third_t = t/3;
556
557    final->allocateImage(8 * one_third_s , one_third_t, 1, pixelFormat, dataType, packing);
558    final->setInternalTextureFormat(internalFormat);
559
560    // copy 1 (6 in source)
561    copyData(theme, 0, 2 * one_third_s, one_third_s, 3 * one_third_s, final.get(), 0, 0);
562
563    // rotate and copy 2
564    osg::ref_ptr<osg::Image> rotateandcopy2  = new osg::Image;
565    rotateandcopy2->allocateImage(one_third_s , one_third_t, 1, pixelFormat, dataType, packing);
566    rotateandcopy2->setInternalTextureFormat(internalFormat);
567    copyData(theme, one_third_s, 0, 2 * one_third_s , one_third_s, rotateandcopy2.get(), 0, 0);
568    rotateandcopy2 = rotateImage(rotateandcopy2.get());
569    rotateandcopy2->flipHorizontal();
570    copyData(rotateandcopy2.get(), 0, 0, one_third_s , one_third_s, final.get(), 6*one_third_s, 0);
571
572    // copy 3 (8 in source)
573    copyData(theme, 2*one_third_s , 2 *one_third_s, 3*one_third_s , 3 * one_third_s, final.get(), 2 * one_third_s, 0);
574
575    // copy 4
576    copyData(theme, 0, one_third_s, one_third_s , 2 * one_third_s, final.get(), 3 * one_third_s, 0);
577
578    // copy 5
579    copyData(theme, 2*one_third_s , one_third_s, 3 * one_third_s , 2 * one_third_s, final.get(), 4 * one_third_s, 0);
580
581    // copy 6 (1 in source)
582    copyData(theme, 0 , 0, one_third_s, one_third_s, final.get(), 5 * one_third_s, 0);
583
584    // rotate and copy 7
585    osg::ref_ptr<osg::Image> rotateandcopy7  = new osg::Image;
586    rotateandcopy7->allocateImage(one_third_s , one_third_t, 1, pixelFormat, dataType, packing);
587    rotateandcopy7->setInternalTextureFormat(internalFormat);
588    copyData(theme, one_third_s, 2*one_third_s, 2 * one_third_s , 3 * one_third_s, rotateandcopy7.get(), 0, 0);
589    rotateandcopy7 = rotateImage(rotateandcopy7.get());
590    rotateandcopy7->flipHorizontal();
591    copyData(rotateandcopy7.get(), 0, 0, one_third_s , one_third_s, final.get(), one_third_s, 0);
592
593    // copy 8 (3 in source)
594    copyData(theme, 2 * one_third_s, 0, 3 * one_third_s , one_third_s , final.get(), 7 * one_third_s, 0);
595
596    return final.release();
597}
598
599}
Note: See TracBrowser for help on using the browser.